]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD.js
Update to iD v2.2.1
[rails.git] / vendor / assets / iD / iD.js
1 (function () {
2 function actionAddEntity(way) {
3     return function(graph) {
4         return graph.replace(way);
5     };
6 }
7
8 var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
9
10
11
12
13
14 function createCommonjsModule(fn, module) {
15         return module = { exports: {} }, fn(module, module.exports), module.exports;
16 }
17
18 var lodash = createCommonjsModule(function (module, exports) {
19 /**
20  * @license
21  * Lodash <https://lodash.com/>
22  * Copyright JS Foundation and other contributors <https://js.foundation/>
23  * Released under MIT license <https://lodash.com/license>
24  * Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
25  * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
26  */
27 (function() {
28
29   /** Used as a safe reference for `undefined` in pre-ES5 environments. */
30   var undefined;
31
32   /** Used as the semantic version number. */
33   var VERSION = '4.17.4';
34
35   /** Used as the size to enable large array optimizations. */
36   var LARGE_ARRAY_SIZE = 200;
37
38   /** Error message constants. */
39   var CORE_ERROR_TEXT = 'Unsupported core-js use. Try https://npms.io/search?q=ponyfill.',
40       FUNC_ERROR_TEXT = 'Expected a function';
41
42   /** Used to stand-in for `undefined` hash values. */
43   var HASH_UNDEFINED = '__lodash_hash_undefined__';
44
45   /** Used as the maximum memoize cache size. */
46   var MAX_MEMOIZE_SIZE = 500;
47
48   /** Used as the internal argument placeholder. */
49   var PLACEHOLDER = '__lodash_placeholder__';
50
51   /** Used to compose bitmasks for cloning. */
52   var CLONE_DEEP_FLAG = 1,
53       CLONE_FLAT_FLAG = 2,
54       CLONE_SYMBOLS_FLAG = 4;
55
56   /** Used to compose bitmasks for value comparisons. */
57   var COMPARE_PARTIAL_FLAG = 1,
58       COMPARE_UNORDERED_FLAG = 2;
59
60   /** Used to compose bitmasks for function metadata. */
61   var WRAP_BIND_FLAG = 1,
62       WRAP_BIND_KEY_FLAG = 2,
63       WRAP_CURRY_BOUND_FLAG = 4,
64       WRAP_CURRY_FLAG = 8,
65       WRAP_CURRY_RIGHT_FLAG = 16,
66       WRAP_PARTIAL_FLAG = 32,
67       WRAP_PARTIAL_RIGHT_FLAG = 64,
68       WRAP_ARY_FLAG = 128,
69       WRAP_REARG_FLAG = 256,
70       WRAP_FLIP_FLAG = 512;
71
72   /** Used as default options for `_.truncate`. */
73   var DEFAULT_TRUNC_LENGTH = 30,
74       DEFAULT_TRUNC_OMISSION = '...';
75
76   /** Used to detect hot functions by number of calls within a span of milliseconds. */
77   var HOT_COUNT = 800,
78       HOT_SPAN = 16;
79
80   /** Used to indicate the type of lazy iteratees. */
81   var LAZY_FILTER_FLAG = 1,
82       LAZY_MAP_FLAG = 2,
83       LAZY_WHILE_FLAG = 3;
84
85   /** Used as references for various `Number` constants. */
86   var INFINITY = 1 / 0,
87       MAX_SAFE_INTEGER = 9007199254740991,
88       MAX_INTEGER = 1.7976931348623157e+308,
89       NAN = 0 / 0;
90
91   /** Used as references for the maximum length and index of an array. */
92   var MAX_ARRAY_LENGTH = 4294967295,
93       MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
94       HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
95
96   /** Used to associate wrap methods with their bit flags. */
97   var wrapFlags = [
98     ['ary', WRAP_ARY_FLAG],
99     ['bind', WRAP_BIND_FLAG],
100     ['bindKey', WRAP_BIND_KEY_FLAG],
101     ['curry', WRAP_CURRY_FLAG],
102     ['curryRight', WRAP_CURRY_RIGHT_FLAG],
103     ['flip', WRAP_FLIP_FLAG],
104     ['partial', WRAP_PARTIAL_FLAG],
105     ['partialRight', WRAP_PARTIAL_RIGHT_FLAG],
106     ['rearg', WRAP_REARG_FLAG]
107   ];
108
109   /** `Object#toString` result references. */
110   var argsTag = '[object Arguments]',
111       arrayTag = '[object Array]',
112       asyncTag = '[object AsyncFunction]',
113       boolTag = '[object Boolean]',
114       dateTag = '[object Date]',
115       domExcTag = '[object DOMException]',
116       errorTag = '[object Error]',
117       funcTag = '[object Function]',
118       genTag = '[object GeneratorFunction]',
119       mapTag = '[object Map]',
120       numberTag = '[object Number]',
121       nullTag = '[object Null]',
122       objectTag = '[object Object]',
123       promiseTag = '[object Promise]',
124       proxyTag = '[object Proxy]',
125       regexpTag = '[object RegExp]',
126       setTag = '[object Set]',
127       stringTag = '[object String]',
128       symbolTag = '[object Symbol]',
129       undefinedTag = '[object Undefined]',
130       weakMapTag = '[object WeakMap]',
131       weakSetTag = '[object WeakSet]';
132
133   var arrayBufferTag = '[object ArrayBuffer]',
134       dataViewTag = '[object DataView]',
135       float32Tag = '[object Float32Array]',
136       float64Tag = '[object Float64Array]',
137       int8Tag = '[object Int8Array]',
138       int16Tag = '[object Int16Array]',
139       int32Tag = '[object Int32Array]',
140       uint8Tag = '[object Uint8Array]',
141       uint8ClampedTag = '[object Uint8ClampedArray]',
142       uint16Tag = '[object Uint16Array]',
143       uint32Tag = '[object Uint32Array]';
144
145   /** Used to match empty string literals in compiled template source. */
146   var reEmptyStringLeading = /\b__p \+= '';/g,
147       reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
148       reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
149
150   /** Used to match HTML entities and HTML characters. */
151   var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g,
152       reUnescapedHtml = /[&<>"']/g,
153       reHasEscapedHtml = RegExp(reEscapedHtml.source),
154       reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
155
156   /** Used to match template delimiters. */
157   var reEscape = /<%-([\s\S]+?)%>/g,
158       reEvaluate = /<%([\s\S]+?)%>/g,
159       reInterpolate = /<%=([\s\S]+?)%>/g;
160
161   /** Used to match property names within property paths. */
162   var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
163       reIsPlainProp = /^\w*$/,
164       reLeadingDot = /^\./,
165       rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;
166
167   /**
168    * Used to match `RegExp`
169    * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns).
170    */
171   var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
172       reHasRegExpChar = RegExp(reRegExpChar.source);
173
174   /** Used to match leading and trailing whitespace. */
175   var reTrim = /^\s+|\s+$/g,
176       reTrimStart = /^\s+/,
177       reTrimEnd = /\s+$/;
178
179   /** Used to match wrap detail comments. */
180   var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/,
181       reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/,
182       reSplitDetails = /,? & /;
183
184   /** Used to match words composed of alphanumeric characters. */
185   var reAsciiWord = /[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;
186
187   /** Used to match backslashes in property paths. */
188   var reEscapeChar = /\\(\\)?/g;
189
190   /**
191    * Used to match
192    * [ES template delimiters](http://ecma-international.org/ecma-262/7.0/#sec-template-literal-lexical-components).
193    */
194   var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
195
196   /** Used to match `RegExp` flags from their coerced string values. */
197   var reFlags = /\w*$/;
198
199   /** Used to detect bad signed hexadecimal string values. */
200   var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
201
202   /** Used to detect binary string values. */
203   var reIsBinary = /^0b[01]+$/i;
204
205   /** Used to detect host constructors (Safari). */
206   var reIsHostCtor = /^\[object .+?Constructor\]$/;
207
208   /** Used to detect octal string values. */
209   var reIsOctal = /^0o[0-7]+$/i;
210
211   /** Used to detect unsigned integer values. */
212   var reIsUint = /^(?:0|[1-9]\d*)$/;
213
214   /** Used to match Latin Unicode letters (excluding mathematical operators). */
215   var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
216
217   /** Used to ensure capturing order of template delimiters. */
218   var reNoMatch = /($^)/;
219
220   /** Used to match unescaped characters in compiled string literals. */
221   var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
222
223   /** Used to compose unicode character classes. */
224   var rsAstralRange = '\\ud800-\\udfff',
225       rsComboMarksRange = '\\u0300-\\u036f',
226       reComboHalfMarksRange = '\\ufe20-\\ufe2f',
227       rsComboSymbolsRange = '\\u20d0-\\u20ff',
228       rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange,
229       rsDingbatRange = '\\u2700-\\u27bf',
230       rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
231       rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
232       rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
233       rsPunctuationRange = '\\u2000-\\u206f',
234       rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
235       rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
236       rsVarRange = '\\ufe0e\\ufe0f',
237       rsBreakRange = rsMathOpRange + rsNonCharRange + rsPunctuationRange + rsSpaceRange;
238
239   /** Used to compose unicode capture groups. */
240   var rsApos = "['\u2019]",
241       rsAstral = '[' + rsAstralRange + ']',
242       rsBreak = '[' + rsBreakRange + ']',
243       rsCombo = '[' + rsComboRange + ']',
244       rsDigits = '\\d+',
245       rsDingbat = '[' + rsDingbatRange + ']',
246       rsLower = '[' + rsLowerRange + ']',
247       rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
248       rsFitz = '\\ud83c[\\udffb-\\udfff]',
249       rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
250       rsNonAstral = '[^' + rsAstralRange + ']',
251       rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
252       rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
253       rsUpper = '[' + rsUpperRange + ']',
254       rsZWJ = '\\u200d';
255
256   /** Used to compose unicode regexes. */
257   var rsMiscLower = '(?:' + rsLower + '|' + rsMisc + ')',
258       rsMiscUpper = '(?:' + rsUpper + '|' + rsMisc + ')',
259       rsOptContrLower = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
260       rsOptContrUpper = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
261       reOptMod = rsModifier + '?',
262       rsOptVar = '[' + rsVarRange + ']?',
263       rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
264       rsOrdLower = '\\d*(?:(?:1st|2nd|3rd|(?![123])\\dth)\\b)',
265       rsOrdUpper = '\\d*(?:(?:1ST|2ND|3RD|(?![123])\\dTH)\\b)',
266       rsSeq = rsOptVar + reOptMod + rsOptJoin,
267       rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
268       rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
269
270   /** Used to match apostrophes. */
271   var reApos = RegExp(rsApos, 'g');
272
273   /**
274    * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
275    * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
276    */
277   var reComboMark = RegExp(rsCombo, 'g');
278
279   /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
280   var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
281
282   /** Used to match complex or compound words. */
283   var reUnicodeWord = RegExp([
284     rsUpper + '?' + rsLower + '+' + rsOptContrLower + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
285     rsMiscUpper + '+' + rsOptContrUpper + '(?=' + [rsBreak, rsUpper + rsMiscLower, '$'].join('|') + ')',
286     rsUpper + '?' + rsMiscLower + '+' + rsOptContrLower,
287     rsUpper + '+' + rsOptContrUpper,
288     rsOrdUpper,
289     rsOrdLower,
290     rsDigits,
291     rsEmoji
292   ].join('|'), 'g');
293
294   /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
295   var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange  + rsComboRange + rsVarRange + ']');
296
297   /** Used to detect strings that need a more robust regexp to match words. */
298   var reHasUnicodeWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
299
300   /** Used to assign default `context` object properties. */
301   var contextProps = [
302     'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array',
303     'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object',
304     'Promise', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError', 'Uint8Array',
305     'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
306     '_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout'
307   ];
308
309   /** Used to make template sourceURLs easier to identify. */
310   var templateCounter = -1;
311
312   /** Used to identify `toStringTag` values of typed arrays. */
313   var typedArrayTags = {};
314   typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
315   typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
316   typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
317   typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
318   typedArrayTags[uint32Tag] = true;
319   typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
320   typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
321   typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
322   typedArrayTags[errorTag] = typedArrayTags[funcTag] =
323   typedArrayTags[mapTag] = typedArrayTags[numberTag] =
324   typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
325   typedArrayTags[setTag] = typedArrayTags[stringTag] =
326   typedArrayTags[weakMapTag] = false;
327
328   /** Used to identify `toStringTag` values supported by `_.clone`. */
329   var cloneableTags = {};
330   cloneableTags[argsTag] = cloneableTags[arrayTag] =
331   cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
332   cloneableTags[boolTag] = cloneableTags[dateTag] =
333   cloneableTags[float32Tag] = cloneableTags[float64Tag] =
334   cloneableTags[int8Tag] = cloneableTags[int16Tag] =
335   cloneableTags[int32Tag] = cloneableTags[mapTag] =
336   cloneableTags[numberTag] = cloneableTags[objectTag] =
337   cloneableTags[regexpTag] = cloneableTags[setTag] =
338   cloneableTags[stringTag] = cloneableTags[symbolTag] =
339   cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
340   cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
341   cloneableTags[errorTag] = cloneableTags[funcTag] =
342   cloneableTags[weakMapTag] = false;
343
344   /** Used to map Latin Unicode letters to basic Latin letters. */
345   var deburredLetters = {
346     // Latin-1 Supplement block.
347     '\xc0': 'A',  '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
348     '\xe0': 'a',  '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
349     '\xc7': 'C',  '\xe7': 'c',
350     '\xd0': 'D',  '\xf0': 'd',
351     '\xc8': 'E',  '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
352     '\xe8': 'e',  '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
353     '\xcc': 'I',  '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
354     '\xec': 'i',  '\xed': 'i', '\xee': 'i', '\xef': 'i',
355     '\xd1': 'N',  '\xf1': 'n',
356     '\xd2': 'O',  '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
357     '\xf2': 'o',  '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
358     '\xd9': 'U',  '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
359     '\xf9': 'u',  '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
360     '\xdd': 'Y',  '\xfd': 'y', '\xff': 'y',
361     '\xc6': 'Ae', '\xe6': 'ae',
362     '\xde': 'Th', '\xfe': 'th',
363     '\xdf': 'ss',
364     // Latin Extended-A block.
365     '\u0100': 'A',  '\u0102': 'A', '\u0104': 'A',
366     '\u0101': 'a',  '\u0103': 'a', '\u0105': 'a',
367     '\u0106': 'C',  '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
368     '\u0107': 'c',  '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
369     '\u010e': 'D',  '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
370     '\u0112': 'E',  '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
371     '\u0113': 'e',  '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
372     '\u011c': 'G',  '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
373     '\u011d': 'g',  '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
374     '\u0124': 'H',  '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
375     '\u0128': 'I',  '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
376     '\u0129': 'i',  '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
377     '\u0134': 'J',  '\u0135': 'j',
378     '\u0136': 'K',  '\u0137': 'k', '\u0138': 'k',
379     '\u0139': 'L',  '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
380     '\u013a': 'l',  '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
381     '\u0143': 'N',  '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
382     '\u0144': 'n',  '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
383     '\u014c': 'O',  '\u014e': 'O', '\u0150': 'O',
384     '\u014d': 'o',  '\u014f': 'o', '\u0151': 'o',
385     '\u0154': 'R',  '\u0156': 'R', '\u0158': 'R',
386     '\u0155': 'r',  '\u0157': 'r', '\u0159': 'r',
387     '\u015a': 'S',  '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
388     '\u015b': 's',  '\u015d': 's', '\u015f': 's', '\u0161': 's',
389     '\u0162': 'T',  '\u0164': 'T', '\u0166': 'T',
390     '\u0163': 't',  '\u0165': 't', '\u0167': 't',
391     '\u0168': 'U',  '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
392     '\u0169': 'u',  '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
393     '\u0174': 'W',  '\u0175': 'w',
394     '\u0176': 'Y',  '\u0177': 'y', '\u0178': 'Y',
395     '\u0179': 'Z',  '\u017b': 'Z', '\u017d': 'Z',
396     '\u017a': 'z',  '\u017c': 'z', '\u017e': 'z',
397     '\u0132': 'IJ', '\u0133': 'ij',
398     '\u0152': 'Oe', '\u0153': 'oe',
399     '\u0149': "'n", '\u017f': 's'
400   };
401
402   /** Used to map characters to HTML entities. */
403   var htmlEscapes = {
404     '&': '&amp;',
405     '<': '&lt;',
406     '>': '&gt;',
407     '"': '&quot;',
408     "'": '&#39;'
409   };
410
411   /** Used to map HTML entities to characters. */
412   var htmlUnescapes = {
413     '&amp;': '&',
414     '&lt;': '<',
415     '&gt;': '>',
416     '&quot;': '"',
417     '&#39;': "'"
418   };
419
420   /** Used to escape characters for inclusion in compiled string literals. */
421   var stringEscapes = {
422     '\\': '\\',
423     "'": "'",
424     '\n': 'n',
425     '\r': 'r',
426     '\u2028': 'u2028',
427     '\u2029': 'u2029'
428   };
429
430   /** Built-in method references without a dependency on `root`. */
431   var freeParseFloat = parseFloat,
432       freeParseInt = parseInt;
433
434   /** Detect free variable `global` from Node.js. */
435   var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal && commonjsGlobal.Object === Object && commonjsGlobal;
436
437   /** Detect free variable `self`. */
438   var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
439
440   /** Used as a reference to the global object. */
441   var root = freeGlobal || freeSelf || Function('return this')();
442
443   /** Detect free variable `exports`. */
444   var freeExports = 'object' == 'object' && exports && !exports.nodeType && exports;
445
446   /** Detect free variable `module`. */
447   var freeModule = freeExports && 'object' == 'object' && module && !module.nodeType && module;
448
449   /** Detect the popular CommonJS extension `module.exports`. */
450   var moduleExports = freeModule && freeModule.exports === freeExports;
451
452   /** Detect free variable `process` from Node.js. */
453   var freeProcess = moduleExports && freeGlobal.process;
454
455   /** Used to access faster Node.js helpers. */
456   var nodeUtil = (function() {
457     try {
458       return freeProcess && freeProcess.binding && freeProcess.binding('util');
459     } catch (e) {}
460   }());
461
462   /* Node.js helper references. */
463   var nodeIsArrayBuffer = nodeUtil && nodeUtil.isArrayBuffer,
464       nodeIsDate = nodeUtil && nodeUtil.isDate,
465       nodeIsMap = nodeUtil && nodeUtil.isMap,
466       nodeIsRegExp = nodeUtil && nodeUtil.isRegExp,
467       nodeIsSet = nodeUtil && nodeUtil.isSet,
468       nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray;
469
470   /*--------------------------------------------------------------------------*/
471
472   /**
473    * Adds the key-value `pair` to `map`.
474    *
475    * @private
476    * @param {Object} map The map to modify.
477    * @param {Array} pair The key-value pair to add.
478    * @returns {Object} Returns `map`.
479    */
480   function addMapEntry(map, pair) {
481     // Don't return `map.set` because it's not chainable in IE 11.
482     map.set(pair[0], pair[1]);
483     return map;
484   }
485
486   /**
487    * Adds `value` to `set`.
488    *
489    * @private
490    * @param {Object} set The set to modify.
491    * @param {*} value The value to add.
492    * @returns {Object} Returns `set`.
493    */
494   function addSetEntry(set, value) {
495     // Don't return `set.add` because it's not chainable in IE 11.
496     set.add(value);
497     return set;
498   }
499
500   /**
501    * A faster alternative to `Function#apply`, this function invokes `func`
502    * with the `this` binding of `thisArg` and the arguments of `args`.
503    *
504    * @private
505    * @param {Function} func The function to invoke.
506    * @param {*} thisArg The `this` binding of `func`.
507    * @param {Array} args The arguments to invoke `func` with.
508    * @returns {*} Returns the result of `func`.
509    */
510   function apply(func, thisArg, args) {
511     switch (args.length) {
512       case 0: return func.call(thisArg);
513       case 1: return func.call(thisArg, args[0]);
514       case 2: return func.call(thisArg, args[0], args[1]);
515       case 3: return func.call(thisArg, args[0], args[1], args[2]);
516     }
517     return func.apply(thisArg, args);
518   }
519
520   /**
521    * A specialized version of `baseAggregator` for arrays.
522    *
523    * @private
524    * @param {Array} [array] The array to iterate over.
525    * @param {Function} setter The function to set `accumulator` values.
526    * @param {Function} iteratee The iteratee to transform keys.
527    * @param {Object} accumulator The initial aggregated object.
528    * @returns {Function} Returns `accumulator`.
529    */
530   function arrayAggregator(array, setter, iteratee, accumulator) {
531     var index = -1,
532         length = array == null ? 0 : array.length;
533
534     while (++index < length) {
535       var value = array[index];
536       setter(accumulator, value, iteratee(value), array);
537     }
538     return accumulator;
539   }
540
541   /**
542    * A specialized version of `_.forEach` for arrays without support for
543    * iteratee shorthands.
544    *
545    * @private
546    * @param {Array} [array] The array to iterate over.
547    * @param {Function} iteratee The function invoked per iteration.
548    * @returns {Array} Returns `array`.
549    */
550   function arrayEach(array, iteratee) {
551     var index = -1,
552         length = array == null ? 0 : array.length;
553
554     while (++index < length) {
555       if (iteratee(array[index], index, array) === false) {
556         break;
557       }
558     }
559     return array;
560   }
561
562   /**
563    * A specialized version of `_.forEachRight` for arrays without support for
564    * iteratee shorthands.
565    *
566    * @private
567    * @param {Array} [array] The array to iterate over.
568    * @param {Function} iteratee The function invoked per iteration.
569    * @returns {Array} Returns `array`.
570    */
571   function arrayEachRight(array, iteratee) {
572     var length = array == null ? 0 : array.length;
573
574     while (length--) {
575       if (iteratee(array[length], length, array) === false) {
576         break;
577       }
578     }
579     return array;
580   }
581
582   /**
583    * A specialized version of `_.every` for arrays without support for
584    * iteratee shorthands.
585    *
586    * @private
587    * @param {Array} [array] The array to iterate over.
588    * @param {Function} predicate The function invoked per iteration.
589    * @returns {boolean} Returns `true` if all elements pass the predicate check,
590    *  else `false`.
591    */
592   function arrayEvery(array, predicate) {
593     var index = -1,
594         length = array == null ? 0 : array.length;
595
596     while (++index < length) {
597       if (!predicate(array[index], index, array)) {
598         return false;
599       }
600     }
601     return true;
602   }
603
604   /**
605    * A specialized version of `_.filter` for arrays without support for
606    * iteratee shorthands.
607    *
608    * @private
609    * @param {Array} [array] The array to iterate over.
610    * @param {Function} predicate The function invoked per iteration.
611    * @returns {Array} Returns the new filtered array.
612    */
613   function arrayFilter(array, predicate) {
614     var index = -1,
615         length = array == null ? 0 : array.length,
616         resIndex = 0,
617         result = [];
618
619     while (++index < length) {
620       var value = array[index];
621       if (predicate(value, index, array)) {
622         result[resIndex++] = value;
623       }
624     }
625     return result;
626   }
627
628   /**
629    * A specialized version of `_.includes` for arrays without support for
630    * specifying an index to search from.
631    *
632    * @private
633    * @param {Array} [array] The array to inspect.
634    * @param {*} target The value to search for.
635    * @returns {boolean} Returns `true` if `target` is found, else `false`.
636    */
637   function arrayIncludes(array, value) {
638     var length = array == null ? 0 : array.length;
639     return !!length && baseIndexOf(array, value, 0) > -1;
640   }
641
642   /**
643    * This function is like `arrayIncludes` except that it accepts a comparator.
644    *
645    * @private
646    * @param {Array} [array] The array to inspect.
647    * @param {*} target The value to search for.
648    * @param {Function} comparator The comparator invoked per element.
649    * @returns {boolean} Returns `true` if `target` is found, else `false`.
650    */
651   function arrayIncludesWith(array, value, comparator) {
652     var index = -1,
653         length = array == null ? 0 : array.length;
654
655     while (++index < length) {
656       if (comparator(value, array[index])) {
657         return true;
658       }
659     }
660     return false;
661   }
662
663   /**
664    * A specialized version of `_.map` for arrays without support for iteratee
665    * shorthands.
666    *
667    * @private
668    * @param {Array} [array] The array to iterate over.
669    * @param {Function} iteratee The function invoked per iteration.
670    * @returns {Array} Returns the new mapped array.
671    */
672   function arrayMap(array, iteratee) {
673     var index = -1,
674         length = array == null ? 0 : array.length,
675         result = Array(length);
676
677     while (++index < length) {
678       result[index] = iteratee(array[index], index, array);
679     }
680     return result;
681   }
682
683   /**
684    * Appends the elements of `values` to `array`.
685    *
686    * @private
687    * @param {Array} array The array to modify.
688    * @param {Array} values The values to append.
689    * @returns {Array} Returns `array`.
690    */
691   function arrayPush(array, values) {
692     var index = -1,
693         length = values.length,
694         offset = array.length;
695
696     while (++index < length) {
697       array[offset + index] = values[index];
698     }
699     return array;
700   }
701
702   /**
703    * A specialized version of `_.reduce` for arrays without support for
704    * iteratee shorthands.
705    *
706    * @private
707    * @param {Array} [array] The array to iterate over.
708    * @param {Function} iteratee The function invoked per iteration.
709    * @param {*} [accumulator] The initial value.
710    * @param {boolean} [initAccum] Specify using the first element of `array` as
711    *  the initial value.
712    * @returns {*} Returns the accumulated value.
713    */
714   function arrayReduce(array, iteratee, accumulator, initAccum) {
715     var index = -1,
716         length = array == null ? 0 : array.length;
717
718     if (initAccum && length) {
719       accumulator = array[++index];
720     }
721     while (++index < length) {
722       accumulator = iteratee(accumulator, array[index], index, array);
723     }
724     return accumulator;
725   }
726
727   /**
728    * A specialized version of `_.reduceRight` for arrays without support for
729    * iteratee shorthands.
730    *
731    * @private
732    * @param {Array} [array] The array to iterate over.
733    * @param {Function} iteratee The function invoked per iteration.
734    * @param {*} [accumulator] The initial value.
735    * @param {boolean} [initAccum] Specify using the last element of `array` as
736    *  the initial value.
737    * @returns {*} Returns the accumulated value.
738    */
739   function arrayReduceRight(array, iteratee, accumulator, initAccum) {
740     var length = array == null ? 0 : array.length;
741     if (initAccum && length) {
742       accumulator = array[--length];
743     }
744     while (length--) {
745       accumulator = iteratee(accumulator, array[length], length, array);
746     }
747     return accumulator;
748   }
749
750   /**
751    * A specialized version of `_.some` for arrays without support for iteratee
752    * shorthands.
753    *
754    * @private
755    * @param {Array} [array] The array to iterate over.
756    * @param {Function} predicate The function invoked per iteration.
757    * @returns {boolean} Returns `true` if any element passes the predicate check,
758    *  else `false`.
759    */
760   function arraySome(array, predicate) {
761     var index = -1,
762         length = array == null ? 0 : array.length;
763
764     while (++index < length) {
765       if (predicate(array[index], index, array)) {
766         return true;
767       }
768     }
769     return false;
770   }
771
772   /**
773    * Gets the size of an ASCII `string`.
774    *
775    * @private
776    * @param {string} string The string inspect.
777    * @returns {number} Returns the string size.
778    */
779   var asciiSize = baseProperty('length');
780
781   /**
782    * Converts an ASCII `string` to an array.
783    *
784    * @private
785    * @param {string} string The string to convert.
786    * @returns {Array} Returns the converted array.
787    */
788   function asciiToArray(string) {
789     return string.split('');
790   }
791
792   /**
793    * Splits an ASCII `string` into an array of its words.
794    *
795    * @private
796    * @param {string} The string to inspect.
797    * @returns {Array} Returns the words of `string`.
798    */
799   function asciiWords(string) {
800     return string.match(reAsciiWord) || [];
801   }
802
803   /**
804    * The base implementation of methods like `_.findKey` and `_.findLastKey`,
805    * without support for iteratee shorthands, which iterates over `collection`
806    * using `eachFunc`.
807    *
808    * @private
809    * @param {Array|Object} collection The collection to inspect.
810    * @param {Function} predicate The function invoked per iteration.
811    * @param {Function} eachFunc The function to iterate over `collection`.
812    * @returns {*} Returns the found element or its key, else `undefined`.
813    */
814   function baseFindKey(collection, predicate, eachFunc) {
815     var result;
816     eachFunc(collection, function(value, key, collection) {
817       if (predicate(value, key, collection)) {
818         result = key;
819         return false;
820       }
821     });
822     return result;
823   }
824
825   /**
826    * The base implementation of `_.findIndex` and `_.findLastIndex` without
827    * support for iteratee shorthands.
828    *
829    * @private
830    * @param {Array} array The array to inspect.
831    * @param {Function} predicate The function invoked per iteration.
832    * @param {number} fromIndex The index to search from.
833    * @param {boolean} [fromRight] Specify iterating from right to left.
834    * @returns {number} Returns the index of the matched value, else `-1`.
835    */
836   function baseFindIndex(array, predicate, fromIndex, fromRight) {
837     var length = array.length,
838         index = fromIndex + (fromRight ? 1 : -1);
839
840     while ((fromRight ? index-- : ++index < length)) {
841       if (predicate(array[index], index, array)) {
842         return index;
843       }
844     }
845     return -1;
846   }
847
848   /**
849    * The base implementation of `_.indexOf` without `fromIndex` bounds checks.
850    *
851    * @private
852    * @param {Array} array The array to inspect.
853    * @param {*} value The value to search for.
854    * @param {number} fromIndex The index to search from.
855    * @returns {number} Returns the index of the matched value, else `-1`.
856    */
857   function baseIndexOf(array, value, fromIndex) {
858     return value === value
859       ? strictIndexOf(array, value, fromIndex)
860       : baseFindIndex(array, baseIsNaN, fromIndex);
861   }
862
863   /**
864    * This function is like `baseIndexOf` except that it accepts a comparator.
865    *
866    * @private
867    * @param {Array} array The array to inspect.
868    * @param {*} value The value to search for.
869    * @param {number} fromIndex The index to search from.
870    * @param {Function} comparator The comparator invoked per element.
871    * @returns {number} Returns the index of the matched value, else `-1`.
872    */
873   function baseIndexOfWith(array, value, fromIndex, comparator) {
874     var index = fromIndex - 1,
875         length = array.length;
876
877     while (++index < length) {
878       if (comparator(array[index], value)) {
879         return index;
880       }
881     }
882     return -1;
883   }
884
885   /**
886    * The base implementation of `_.isNaN` without support for number objects.
887    *
888    * @private
889    * @param {*} value The value to check.
890    * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
891    */
892   function baseIsNaN(value) {
893     return value !== value;
894   }
895
896   /**
897    * The base implementation of `_.mean` and `_.meanBy` without support for
898    * iteratee shorthands.
899    *
900    * @private
901    * @param {Array} array The array to iterate over.
902    * @param {Function} iteratee The function invoked per iteration.
903    * @returns {number} Returns the mean.
904    */
905   function baseMean(array, iteratee) {
906     var length = array == null ? 0 : array.length;
907     return length ? (baseSum(array, iteratee) / length) : NAN;
908   }
909
910   /**
911    * The base implementation of `_.property` without support for deep paths.
912    *
913    * @private
914    * @param {string} key The key of the property to get.
915    * @returns {Function} Returns the new accessor function.
916    */
917   function baseProperty(key) {
918     return function(object) {
919       return object == null ? undefined : object[key];
920     };
921   }
922
923   /**
924    * The base implementation of `_.propertyOf` without support for deep paths.
925    *
926    * @private
927    * @param {Object} object The object to query.
928    * @returns {Function} Returns the new accessor function.
929    */
930   function basePropertyOf(object) {
931     return function(key) {
932       return object == null ? undefined : object[key];
933     };
934   }
935
936   /**
937    * The base implementation of `_.reduce` and `_.reduceRight`, without support
938    * for iteratee shorthands, which iterates over `collection` using `eachFunc`.
939    *
940    * @private
941    * @param {Array|Object} collection The collection to iterate over.
942    * @param {Function} iteratee The function invoked per iteration.
943    * @param {*} accumulator The initial value.
944    * @param {boolean} initAccum Specify using the first or last element of
945    *  `collection` as the initial value.
946    * @param {Function} eachFunc The function to iterate over `collection`.
947    * @returns {*} Returns the accumulated value.
948    */
949   function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
950     eachFunc(collection, function(value, index, collection) {
951       accumulator = initAccum
952         ? (initAccum = false, value)
953         : iteratee(accumulator, value, index, collection);
954     });
955     return accumulator;
956   }
957
958   /**
959    * The base implementation of `_.sortBy` which uses `comparer` to define the
960    * sort order of `array` and replaces criteria objects with their corresponding
961    * values.
962    *
963    * @private
964    * @param {Array} array The array to sort.
965    * @param {Function} comparer The function to define sort order.
966    * @returns {Array} Returns `array`.
967    */
968   function baseSortBy(array, comparer) {
969     var length = array.length;
970
971     array.sort(comparer);
972     while (length--) {
973       array[length] = array[length].value;
974     }
975     return array;
976   }
977
978   /**
979    * The base implementation of `_.sum` and `_.sumBy` without support for
980    * iteratee shorthands.
981    *
982    * @private
983    * @param {Array} array The array to iterate over.
984    * @param {Function} iteratee The function invoked per iteration.
985    * @returns {number} Returns the sum.
986    */
987   function baseSum(array, iteratee) {
988     var result,
989         index = -1,
990         length = array.length;
991
992     while (++index < length) {
993       var current = iteratee(array[index]);
994       if (current !== undefined) {
995         result = result === undefined ? current : (result + current);
996       }
997     }
998     return result;
999   }
1000
1001   /**
1002    * The base implementation of `_.times` without support for iteratee shorthands
1003    * or max array length checks.
1004    *
1005    * @private
1006    * @param {number} n The number of times to invoke `iteratee`.
1007    * @param {Function} iteratee The function invoked per iteration.
1008    * @returns {Array} Returns the array of results.
1009    */
1010   function baseTimes(n, iteratee) {
1011     var index = -1,
1012         result = Array(n);
1013
1014     while (++index < n) {
1015       result[index] = iteratee(index);
1016     }
1017     return result;
1018   }
1019
1020   /**
1021    * The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
1022    * of key-value pairs for `object` corresponding to the property names of `props`.
1023    *
1024    * @private
1025    * @param {Object} object The object to query.
1026    * @param {Array} props The property names to get values for.
1027    * @returns {Object} Returns the key-value pairs.
1028    */
1029   function baseToPairs(object, props) {
1030     return arrayMap(props, function(key) {
1031       return [key, object[key]];
1032     });
1033   }
1034
1035   /**
1036    * The base implementation of `_.unary` without support for storing metadata.
1037    *
1038    * @private
1039    * @param {Function} func The function to cap arguments for.
1040    * @returns {Function} Returns the new capped function.
1041    */
1042   function baseUnary(func) {
1043     return function(value) {
1044       return func(value);
1045     };
1046   }
1047
1048   /**
1049    * The base implementation of `_.values` and `_.valuesIn` which creates an
1050    * array of `object` property values corresponding to the property names
1051    * of `props`.
1052    *
1053    * @private
1054    * @param {Object} object The object to query.
1055    * @param {Array} props The property names to get values for.
1056    * @returns {Object} Returns the array of property values.
1057    */
1058   function baseValues(object, props) {
1059     return arrayMap(props, function(key) {
1060       return object[key];
1061     });
1062   }
1063
1064   /**
1065    * Checks if a `cache` value for `key` exists.
1066    *
1067    * @private
1068    * @param {Object} cache The cache to query.
1069    * @param {string} key The key of the entry to check.
1070    * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
1071    */
1072   function cacheHas(cache, key) {
1073     return cache.has(key);
1074   }
1075
1076   /**
1077    * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
1078    * that is not found in the character symbols.
1079    *
1080    * @private
1081    * @param {Array} strSymbols The string symbols to inspect.
1082    * @param {Array} chrSymbols The character symbols to find.
1083    * @returns {number} Returns the index of the first unmatched string symbol.
1084    */
1085   function charsStartIndex(strSymbols, chrSymbols) {
1086     var index = -1,
1087         length = strSymbols.length;
1088
1089     while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
1090     return index;
1091   }
1092
1093   /**
1094    * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
1095    * that is not found in the character symbols.
1096    *
1097    * @private
1098    * @param {Array} strSymbols The string symbols to inspect.
1099    * @param {Array} chrSymbols The character symbols to find.
1100    * @returns {number} Returns the index of the last unmatched string symbol.
1101    */
1102   function charsEndIndex(strSymbols, chrSymbols) {
1103     var index = strSymbols.length;
1104
1105     while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
1106     return index;
1107   }
1108
1109   /**
1110    * Gets the number of `placeholder` occurrences in `array`.
1111    *
1112    * @private
1113    * @param {Array} array The array to inspect.
1114    * @param {*} placeholder The placeholder to search for.
1115    * @returns {number} Returns the placeholder count.
1116    */
1117   function countHolders(array, placeholder) {
1118     var length = array.length,
1119         result = 0;
1120
1121     while (length--) {
1122       if (array[length] === placeholder) {
1123         ++result;
1124       }
1125     }
1126     return result;
1127   }
1128
1129   /**
1130    * Used by `_.deburr` to convert Latin-1 Supplement and Latin Extended-A
1131    * letters to basic Latin letters.
1132    *
1133    * @private
1134    * @param {string} letter The matched letter to deburr.
1135    * @returns {string} Returns the deburred letter.
1136    */
1137   var deburrLetter = basePropertyOf(deburredLetters);
1138
1139   /**
1140    * Used by `_.escape` to convert characters to HTML entities.
1141    *
1142    * @private
1143    * @param {string} chr The matched character to escape.
1144    * @returns {string} Returns the escaped character.
1145    */
1146   var escapeHtmlChar = basePropertyOf(htmlEscapes);
1147
1148   /**
1149    * Used by `_.template` to escape characters for inclusion in compiled string literals.
1150    *
1151    * @private
1152    * @param {string} chr The matched character to escape.
1153    * @returns {string} Returns the escaped character.
1154    */
1155   function escapeStringChar(chr) {
1156     return '\\' + stringEscapes[chr];
1157   }
1158
1159   /**
1160    * Gets the value at `key` of `object`.
1161    *
1162    * @private
1163    * @param {Object} [object] The object to query.
1164    * @param {string} key The key of the property to get.
1165    * @returns {*} Returns the property value.
1166    */
1167   function getValue(object, key) {
1168     return object == null ? undefined : object[key];
1169   }
1170
1171   /**
1172    * Checks if `string` contains Unicode symbols.
1173    *
1174    * @private
1175    * @param {string} string The string to inspect.
1176    * @returns {boolean} Returns `true` if a symbol is found, else `false`.
1177    */
1178   function hasUnicode(string) {
1179     return reHasUnicode.test(string);
1180   }
1181
1182   /**
1183    * Checks if `string` contains a word composed of Unicode symbols.
1184    *
1185    * @private
1186    * @param {string} string The string to inspect.
1187    * @returns {boolean} Returns `true` if a word is found, else `false`.
1188    */
1189   function hasUnicodeWord(string) {
1190     return reHasUnicodeWord.test(string);
1191   }
1192
1193   /**
1194    * Converts `iterator` to an array.
1195    *
1196    * @private
1197    * @param {Object} iterator The iterator to convert.
1198    * @returns {Array} Returns the converted array.
1199    */
1200   function iteratorToArray(iterator) {
1201     var data,
1202         result = [];
1203
1204     while (!(data = iterator.next()).done) {
1205       result.push(data.value);
1206     }
1207     return result;
1208   }
1209
1210   /**
1211    * Converts `map` to its key-value pairs.
1212    *
1213    * @private
1214    * @param {Object} map The map to convert.
1215    * @returns {Array} Returns the key-value pairs.
1216    */
1217   function mapToArray(map) {
1218     var index = -1,
1219         result = Array(map.size);
1220
1221     map.forEach(function(value, key) {
1222       result[++index] = [key, value];
1223     });
1224     return result;
1225   }
1226
1227   /**
1228    * Creates a unary function that invokes `func` with its argument transformed.
1229    *
1230    * @private
1231    * @param {Function} func The function to wrap.
1232    * @param {Function} transform The argument transform.
1233    * @returns {Function} Returns the new function.
1234    */
1235   function overArg(func, transform) {
1236     return function(arg) {
1237       return func(transform(arg));
1238     };
1239   }
1240
1241   /**
1242    * Replaces all `placeholder` elements in `array` with an internal placeholder
1243    * and returns an array of their indexes.
1244    *
1245    * @private
1246    * @param {Array} array The array to modify.
1247    * @param {*} placeholder The placeholder to replace.
1248    * @returns {Array} Returns the new array of placeholder indexes.
1249    */
1250   function replaceHolders(array, placeholder) {
1251     var index = -1,
1252         length = array.length,
1253         resIndex = 0,
1254         result = [];
1255
1256     while (++index < length) {
1257       var value = array[index];
1258       if (value === placeholder || value === PLACEHOLDER) {
1259         array[index] = PLACEHOLDER;
1260         result[resIndex++] = index;
1261       }
1262     }
1263     return result;
1264   }
1265
1266   /**
1267    * Converts `set` to an array of its values.
1268    *
1269    * @private
1270    * @param {Object} set The set to convert.
1271    * @returns {Array} Returns the values.
1272    */
1273   function setToArray(set) {
1274     var index = -1,
1275         result = Array(set.size);
1276
1277     set.forEach(function(value) {
1278       result[++index] = value;
1279     });
1280     return result;
1281   }
1282
1283   /**
1284    * Converts `set` to its value-value pairs.
1285    *
1286    * @private
1287    * @param {Object} set The set to convert.
1288    * @returns {Array} Returns the value-value pairs.
1289    */
1290   function setToPairs(set) {
1291     var index = -1,
1292         result = Array(set.size);
1293
1294     set.forEach(function(value) {
1295       result[++index] = [value, value];
1296     });
1297     return result;
1298   }
1299
1300   /**
1301    * A specialized version of `_.indexOf` which performs strict equality
1302    * comparisons of values, i.e. `===`.
1303    *
1304    * @private
1305    * @param {Array} array The array to inspect.
1306    * @param {*} value The value to search for.
1307    * @param {number} fromIndex The index to search from.
1308    * @returns {number} Returns the index of the matched value, else `-1`.
1309    */
1310   function strictIndexOf(array, value, fromIndex) {
1311     var index = fromIndex - 1,
1312         length = array.length;
1313
1314     while (++index < length) {
1315       if (array[index] === value) {
1316         return index;
1317       }
1318     }
1319     return -1;
1320   }
1321
1322   /**
1323    * A specialized version of `_.lastIndexOf` which performs strict equality
1324    * comparisons of values, i.e. `===`.
1325    *
1326    * @private
1327    * @param {Array} array The array to inspect.
1328    * @param {*} value The value to search for.
1329    * @param {number} fromIndex The index to search from.
1330    * @returns {number} Returns the index of the matched value, else `-1`.
1331    */
1332   function strictLastIndexOf(array, value, fromIndex) {
1333     var index = fromIndex + 1;
1334     while (index--) {
1335       if (array[index] === value) {
1336         return index;
1337       }
1338     }
1339     return index;
1340   }
1341
1342   /**
1343    * Gets the number of symbols in `string`.
1344    *
1345    * @private
1346    * @param {string} string The string to inspect.
1347    * @returns {number} Returns the string size.
1348    */
1349   function stringSize(string) {
1350     return hasUnicode(string)
1351       ? unicodeSize(string)
1352       : asciiSize(string);
1353   }
1354
1355   /**
1356    * Converts `string` to an array.
1357    *
1358    * @private
1359    * @param {string} string The string to convert.
1360    * @returns {Array} Returns the converted array.
1361    */
1362   function stringToArray(string) {
1363     return hasUnicode(string)
1364       ? unicodeToArray(string)
1365       : asciiToArray(string);
1366   }
1367
1368   /**
1369    * Used by `_.unescape` to convert HTML entities to characters.
1370    *
1371    * @private
1372    * @param {string} chr The matched character to unescape.
1373    * @returns {string} Returns the unescaped character.
1374    */
1375   var unescapeHtmlChar = basePropertyOf(htmlUnescapes);
1376
1377   /**
1378    * Gets the size of a Unicode `string`.
1379    *
1380    * @private
1381    * @param {string} string The string inspect.
1382    * @returns {number} Returns the string size.
1383    */
1384   function unicodeSize(string) {
1385     var result = reUnicode.lastIndex = 0;
1386     while (reUnicode.test(string)) {
1387       ++result;
1388     }
1389     return result;
1390   }
1391
1392   /**
1393    * Converts a Unicode `string` to an array.
1394    *
1395    * @private
1396    * @param {string} string The string to convert.
1397    * @returns {Array} Returns the converted array.
1398    */
1399   function unicodeToArray(string) {
1400     return string.match(reUnicode) || [];
1401   }
1402
1403   /**
1404    * Splits a Unicode `string` into an array of its words.
1405    *
1406    * @private
1407    * @param {string} The string to inspect.
1408    * @returns {Array} Returns the words of `string`.
1409    */
1410   function unicodeWords(string) {
1411     return string.match(reUnicodeWord) || [];
1412   }
1413
1414   /*--------------------------------------------------------------------------*/
1415
1416   /**
1417    * Create a new pristine `lodash` function using the `context` object.
1418    *
1419    * @static
1420    * @memberOf _
1421    * @since 1.1.0
1422    * @category Util
1423    * @param {Object} [context=root] The context object.
1424    * @returns {Function} Returns a new `lodash` function.
1425    * @example
1426    *
1427    * _.mixin({ 'foo': _.constant('foo') });
1428    *
1429    * var lodash = _.runInContext();
1430    * lodash.mixin({ 'bar': lodash.constant('bar') });
1431    *
1432    * _.isFunction(_.foo);
1433    * // => true
1434    * _.isFunction(_.bar);
1435    * // => false
1436    *
1437    * lodash.isFunction(lodash.foo);
1438    * // => false
1439    * lodash.isFunction(lodash.bar);
1440    * // => true
1441    *
1442    * // Create a suped-up `defer` in Node.js.
1443    * var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
1444    */
1445   var runInContext = (function runInContext(context) {
1446     context = context == null ? root : _.defaults(root.Object(), context, _.pick(root, contextProps));
1447
1448     /** Built-in constructor references. */
1449     var Array = context.Array,
1450         Date = context.Date,
1451         Error = context.Error,
1452         Function = context.Function,
1453         Math = context.Math,
1454         Object = context.Object,
1455         RegExp = context.RegExp,
1456         String = context.String,
1457         TypeError = context.TypeError;
1458
1459     /** Used for built-in method references. */
1460     var arrayProto = Array.prototype,
1461         funcProto = Function.prototype,
1462         objectProto = Object.prototype;
1463
1464     /** Used to detect overreaching core-js shims. */
1465     var coreJsData = context['__core-js_shared__'];
1466
1467     /** Used to resolve the decompiled source of functions. */
1468     var funcToString = funcProto.toString;
1469
1470     /** Used to check objects for own properties. */
1471     var hasOwnProperty = objectProto.hasOwnProperty;
1472
1473     /** Used to generate unique IDs. */
1474     var idCounter = 0;
1475
1476     /** Used to detect methods masquerading as native. */
1477     var maskSrcKey = (function() {
1478       var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || '');
1479       return uid ? ('Symbol(src)_1.' + uid) : '';
1480     }());
1481
1482     /**
1483      * Used to resolve the
1484      * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
1485      * of values.
1486      */
1487     var nativeObjectToString = objectProto.toString;
1488
1489     /** Used to infer the `Object` constructor. */
1490     var objectCtorString = funcToString.call(Object);
1491
1492     /** Used to restore the original `_` reference in `_.noConflict`. */
1493     var oldDash = root._;
1494
1495     /** Used to detect if a method is native. */
1496     var reIsNative = RegExp('^' +
1497       funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
1498       .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
1499     );
1500
1501     /** Built-in value references. */
1502     var Buffer = moduleExports ? context.Buffer : undefined,
1503         Symbol = context.Symbol,
1504         Uint8Array = context.Uint8Array,
1505         allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined,
1506         getPrototype = overArg(Object.getPrototypeOf, Object),
1507         objectCreate = Object.create,
1508         propertyIsEnumerable = objectProto.propertyIsEnumerable,
1509         splice = arrayProto.splice,
1510         spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined,
1511         symIterator = Symbol ? Symbol.iterator : undefined,
1512         symToStringTag = Symbol ? Symbol.toStringTag : undefined;
1513
1514     var defineProperty = (function() {
1515       try {
1516         var func = getNative(Object, 'defineProperty');
1517         func({}, '', {});
1518         return func;
1519       } catch (e) {}
1520     }());
1521
1522     /** Mocked built-ins. */
1523     var ctxClearTimeout = context.clearTimeout !== root.clearTimeout && context.clearTimeout,
1524         ctxNow = Date && Date.now !== root.Date.now && Date.now,
1525         ctxSetTimeout = context.setTimeout !== root.setTimeout && context.setTimeout;
1526
1527     /* Built-in method references for those with the same name as other `lodash` methods. */
1528     var nativeCeil = Math.ceil,
1529         nativeFloor = Math.floor,
1530         nativeGetSymbols = Object.getOwnPropertySymbols,
1531         nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined,
1532         nativeIsFinite = context.isFinite,
1533         nativeJoin = arrayProto.join,
1534         nativeKeys = overArg(Object.keys, Object),
1535         nativeMax = Math.max,
1536         nativeMin = Math.min,
1537         nativeNow = Date.now,
1538         nativeParseInt = context.parseInt,
1539         nativeRandom = Math.random,
1540         nativeReverse = arrayProto.reverse;
1541
1542     /* Built-in method references that are verified to be native. */
1543     var DataView = getNative(context, 'DataView'),
1544         Map = getNative(context, 'Map'),
1545         Promise = getNative(context, 'Promise'),
1546         Set = getNative(context, 'Set'),
1547         WeakMap = getNative(context, 'WeakMap'),
1548         nativeCreate = getNative(Object, 'create');
1549
1550     /** Used to store function metadata. */
1551     var metaMap = WeakMap && new WeakMap;
1552
1553     /** Used to lookup unminified function names. */
1554     var realNames = {};
1555
1556     /** Used to detect maps, sets, and weakmaps. */
1557     var dataViewCtorString = toSource(DataView),
1558         mapCtorString = toSource(Map),
1559         promiseCtorString = toSource(Promise),
1560         setCtorString = toSource(Set),
1561         weakMapCtorString = toSource(WeakMap);
1562
1563     /** Used to convert symbols to primitives and strings. */
1564     var symbolProto = Symbol ? Symbol.prototype : undefined,
1565         symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
1566         symbolToString = symbolProto ? symbolProto.toString : undefined;
1567
1568     /*------------------------------------------------------------------------*/
1569
1570     /**
1571      * Creates a `lodash` object which wraps `value` to enable implicit method
1572      * chain sequences. Methods that operate on and return arrays, collections,
1573      * and functions can be chained together. Methods that retrieve a single value
1574      * or may return a primitive value will automatically end the chain sequence
1575      * and return the unwrapped value. Otherwise, the value must be unwrapped
1576      * with `_#value`.
1577      *
1578      * Explicit chain sequences, which must be unwrapped with `_#value`, may be
1579      * enabled using `_.chain`.
1580      *
1581      * The execution of chained methods is lazy, that is, it's deferred until
1582      * `_#value` is implicitly or explicitly called.
1583      *
1584      * Lazy evaluation allows several methods to support shortcut fusion.
1585      * Shortcut fusion is an optimization to merge iteratee calls; this avoids
1586      * the creation of intermediate arrays and can greatly reduce the number of
1587      * iteratee executions. Sections of a chain sequence qualify for shortcut
1588      * fusion if the section is applied to an array and iteratees accept only
1589      * one argument. The heuristic for whether a section qualifies for shortcut
1590      * fusion is subject to change.
1591      *
1592      * Chaining is supported in custom builds as long as the `_#value` method is
1593      * directly or indirectly included in the build.
1594      *
1595      * In addition to lodash methods, wrappers have `Array` and `String` methods.
1596      *
1597      * The wrapper `Array` methods are:
1598      * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
1599      *
1600      * The wrapper `String` methods are:
1601      * `replace` and `split`
1602      *
1603      * The wrapper methods that support shortcut fusion are:
1604      * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
1605      * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
1606      * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
1607      *
1608      * The chainable wrapper methods are:
1609      * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
1610      * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
1611      * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
1612      * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
1613      * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
1614      * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
1615      * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
1616      * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
1617      * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
1618      * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
1619      * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
1620      * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
1621      * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
1622      * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
1623      * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
1624      * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
1625      * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
1626      * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
1627      * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
1628      * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
1629      * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
1630      * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
1631      * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
1632      * `zipObject`, `zipObjectDeep`, and `zipWith`
1633      *
1634      * The wrapper methods that are **not** chainable by default are:
1635      * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
1636      * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`,
1637      * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`,
1638      * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`,
1639      * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`,
1640      * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`,
1641      * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`,
1642      * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`,
1643      * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`,
1644      * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`,
1645      * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`,
1646      * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`,
1647      * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`,
1648      * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`,
1649      * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`,
1650      * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`,
1651      * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`,
1652      * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`,
1653      * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`,
1654      * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`,
1655      * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`,
1656      * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`,
1657      * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`,
1658      * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`,
1659      * `upperFirst`, `value`, and `words`
1660      *
1661      * @name _
1662      * @constructor
1663      * @category Seq
1664      * @param {*} value The value to wrap in a `lodash` instance.
1665      * @returns {Object} Returns the new `lodash` wrapper instance.
1666      * @example
1667      *
1668      * function square(n) {
1669      *   return n * n;
1670      * }
1671      *
1672      * var wrapped = _([1, 2, 3]);
1673      *
1674      * // Returns an unwrapped value.
1675      * wrapped.reduce(_.add);
1676      * // => 6
1677      *
1678      * // Returns a wrapped value.
1679      * var squares = wrapped.map(square);
1680      *
1681      * _.isArray(squares);
1682      * // => false
1683      *
1684      * _.isArray(squares.value());
1685      * // => true
1686      */
1687     function lodash(value) {
1688       if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
1689         if (value instanceof LodashWrapper) {
1690           return value;
1691         }
1692         if (hasOwnProperty.call(value, '__wrapped__')) {
1693           return wrapperClone(value);
1694         }
1695       }
1696       return new LodashWrapper(value);
1697     }
1698
1699     /**
1700      * The base implementation of `_.create` without support for assigning
1701      * properties to the created object.
1702      *
1703      * @private
1704      * @param {Object} proto The object to inherit from.
1705      * @returns {Object} Returns the new object.
1706      */
1707     var baseCreate = (function() {
1708       function object() {}
1709       return function(proto) {
1710         if (!isObject(proto)) {
1711           return {};
1712         }
1713         if (objectCreate) {
1714           return objectCreate(proto);
1715         }
1716         object.prototype = proto;
1717         var result = new object;
1718         object.prototype = undefined;
1719         return result;
1720       };
1721     }());
1722
1723     /**
1724      * The function whose prototype chain sequence wrappers inherit from.
1725      *
1726      * @private
1727      */
1728     function baseLodash() {
1729       // No operation performed.
1730     }
1731
1732     /**
1733      * The base constructor for creating `lodash` wrapper objects.
1734      *
1735      * @private
1736      * @param {*} value The value to wrap.
1737      * @param {boolean} [chainAll] Enable explicit method chain sequences.
1738      */
1739     function LodashWrapper(value, chainAll) {
1740       this.__wrapped__ = value;
1741       this.__actions__ = [];
1742       this.__chain__ = !!chainAll;
1743       this.__index__ = 0;
1744       this.__values__ = undefined;
1745     }
1746
1747     /**
1748      * By default, the template delimiters used by lodash are like those in
1749      * embedded Ruby (ERB) as well as ES2015 template strings. Change the
1750      * following template settings to use alternative delimiters.
1751      *
1752      * @static
1753      * @memberOf _
1754      * @type {Object}
1755      */
1756     lodash.templateSettings = {
1757
1758       /**
1759        * Used to detect `data` property values to be HTML-escaped.
1760        *
1761        * @memberOf _.templateSettings
1762        * @type {RegExp}
1763        */
1764       'escape': reEscape,
1765
1766       /**
1767        * Used to detect code to be evaluated.
1768        *
1769        * @memberOf _.templateSettings
1770        * @type {RegExp}
1771        */
1772       'evaluate': reEvaluate,
1773
1774       /**
1775        * Used to detect `data` property values to inject.
1776        *
1777        * @memberOf _.templateSettings
1778        * @type {RegExp}
1779        */
1780       'interpolate': reInterpolate,
1781
1782       /**
1783        * Used to reference the data object in the template text.
1784        *
1785        * @memberOf _.templateSettings
1786        * @type {string}
1787        */
1788       'variable': '',
1789
1790       /**
1791        * Used to import variables into the compiled template.
1792        *
1793        * @memberOf _.templateSettings
1794        * @type {Object}
1795        */
1796       'imports': {
1797
1798         /**
1799          * A reference to the `lodash` function.
1800          *
1801          * @memberOf _.templateSettings.imports
1802          * @type {Function}
1803          */
1804         '_': lodash
1805       }
1806     };
1807
1808     // Ensure wrappers are instances of `baseLodash`.
1809     lodash.prototype = baseLodash.prototype;
1810     lodash.prototype.constructor = lodash;
1811
1812     LodashWrapper.prototype = baseCreate(baseLodash.prototype);
1813     LodashWrapper.prototype.constructor = LodashWrapper;
1814
1815     /*------------------------------------------------------------------------*/
1816
1817     /**
1818      * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
1819      *
1820      * @private
1821      * @constructor
1822      * @param {*} value The value to wrap.
1823      */
1824     function LazyWrapper(value) {
1825       this.__wrapped__ = value;
1826       this.__actions__ = [];
1827       this.__dir__ = 1;
1828       this.__filtered__ = false;
1829       this.__iteratees__ = [];
1830       this.__takeCount__ = MAX_ARRAY_LENGTH;
1831       this.__views__ = [];
1832     }
1833
1834     /**
1835      * Creates a clone of the lazy wrapper object.
1836      *
1837      * @private
1838      * @name clone
1839      * @memberOf LazyWrapper
1840      * @returns {Object} Returns the cloned `LazyWrapper` object.
1841      */
1842     function lazyClone() {
1843       var result = new LazyWrapper(this.__wrapped__);
1844       result.__actions__ = copyArray(this.__actions__);
1845       result.__dir__ = this.__dir__;
1846       result.__filtered__ = this.__filtered__;
1847       result.__iteratees__ = copyArray(this.__iteratees__);
1848       result.__takeCount__ = this.__takeCount__;
1849       result.__views__ = copyArray(this.__views__);
1850       return result;
1851     }
1852
1853     /**
1854      * Reverses the direction of lazy iteration.
1855      *
1856      * @private
1857      * @name reverse
1858      * @memberOf LazyWrapper
1859      * @returns {Object} Returns the new reversed `LazyWrapper` object.
1860      */
1861     function lazyReverse() {
1862       if (this.__filtered__) {
1863         var result = new LazyWrapper(this);
1864         result.__dir__ = -1;
1865         result.__filtered__ = true;
1866       } else {
1867         result = this.clone();
1868         result.__dir__ *= -1;
1869       }
1870       return result;
1871     }
1872
1873     /**
1874      * Extracts the unwrapped value from its lazy wrapper.
1875      *
1876      * @private
1877      * @name value
1878      * @memberOf LazyWrapper
1879      * @returns {*} Returns the unwrapped value.
1880      */
1881     function lazyValue() {
1882       var array = this.__wrapped__.value(),
1883           dir = this.__dir__,
1884           isArr = isArray(array),
1885           isRight = dir < 0,
1886           arrLength = isArr ? array.length : 0,
1887           view = getView(0, arrLength, this.__views__),
1888           start = view.start,
1889           end = view.end,
1890           length = end - start,
1891           index = isRight ? end : (start - 1),
1892           iteratees = this.__iteratees__,
1893           iterLength = iteratees.length,
1894           resIndex = 0,
1895           takeCount = nativeMin(length, this.__takeCount__);
1896
1897       if (!isArr || (!isRight && arrLength == length && takeCount == length)) {
1898         return baseWrapperValue(array, this.__actions__);
1899       }
1900       var result = [];
1901
1902       outer:
1903       while (length-- && resIndex < takeCount) {
1904         index += dir;
1905
1906         var iterIndex = -1,
1907             value = array[index];
1908
1909         while (++iterIndex < iterLength) {
1910           var data = iteratees[iterIndex],
1911               iteratee = data.iteratee,
1912               type = data.type,
1913               computed = iteratee(value);
1914
1915           if (type == LAZY_MAP_FLAG) {
1916             value = computed;
1917           } else if (!computed) {
1918             if (type == LAZY_FILTER_FLAG) {
1919               continue outer;
1920             } else {
1921               break outer;
1922             }
1923           }
1924         }
1925         result[resIndex++] = value;
1926       }
1927       return result;
1928     }
1929
1930     // Ensure `LazyWrapper` is an instance of `baseLodash`.
1931     LazyWrapper.prototype = baseCreate(baseLodash.prototype);
1932     LazyWrapper.prototype.constructor = LazyWrapper;
1933
1934     /*------------------------------------------------------------------------*/
1935
1936     /**
1937      * Creates a hash object.
1938      *
1939      * @private
1940      * @constructor
1941      * @param {Array} [entries] The key-value pairs to cache.
1942      */
1943     function Hash(entries) {
1944       var index = -1,
1945           length = entries == null ? 0 : entries.length;
1946
1947       this.clear();
1948       while (++index < length) {
1949         var entry = entries[index];
1950         this.set(entry[0], entry[1]);
1951       }
1952     }
1953
1954     /**
1955      * Removes all key-value entries from the hash.
1956      *
1957      * @private
1958      * @name clear
1959      * @memberOf Hash
1960      */
1961     function hashClear() {
1962       this.__data__ = nativeCreate ? nativeCreate(null) : {};
1963       this.size = 0;
1964     }
1965
1966     /**
1967      * Removes `key` and its value from the hash.
1968      *
1969      * @private
1970      * @name delete
1971      * @memberOf Hash
1972      * @param {Object} hash The hash to modify.
1973      * @param {string} key The key of the value to remove.
1974      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
1975      */
1976     function hashDelete(key) {
1977       var result = this.has(key) && delete this.__data__[key];
1978       this.size -= result ? 1 : 0;
1979       return result;
1980     }
1981
1982     /**
1983      * Gets the hash value for `key`.
1984      *
1985      * @private
1986      * @name get
1987      * @memberOf Hash
1988      * @param {string} key The key of the value to get.
1989      * @returns {*} Returns the entry value.
1990      */
1991     function hashGet(key) {
1992       var data = this.__data__;
1993       if (nativeCreate) {
1994         var result = data[key];
1995         return result === HASH_UNDEFINED ? undefined : result;
1996       }
1997       return hasOwnProperty.call(data, key) ? data[key] : undefined;
1998     }
1999
2000     /**
2001      * Checks if a hash value for `key` exists.
2002      *
2003      * @private
2004      * @name has
2005      * @memberOf Hash
2006      * @param {string} key The key of the entry to check.
2007      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2008      */
2009     function hashHas(key) {
2010       var data = this.__data__;
2011       return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key);
2012     }
2013
2014     /**
2015      * Sets the hash `key` to `value`.
2016      *
2017      * @private
2018      * @name set
2019      * @memberOf Hash
2020      * @param {string} key The key of the value to set.
2021      * @param {*} value The value to set.
2022      * @returns {Object} Returns the hash instance.
2023      */
2024     function hashSet(key, value) {
2025       var data = this.__data__;
2026       this.size += this.has(key) ? 0 : 1;
2027       data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
2028       return this;
2029     }
2030
2031     // Add methods to `Hash`.
2032     Hash.prototype.clear = hashClear;
2033     Hash.prototype['delete'] = hashDelete;
2034     Hash.prototype.get = hashGet;
2035     Hash.prototype.has = hashHas;
2036     Hash.prototype.set = hashSet;
2037
2038     /*------------------------------------------------------------------------*/
2039
2040     /**
2041      * Creates an list cache object.
2042      *
2043      * @private
2044      * @constructor
2045      * @param {Array} [entries] The key-value pairs to cache.
2046      */
2047     function ListCache(entries) {
2048       var index = -1,
2049           length = entries == null ? 0 : entries.length;
2050
2051       this.clear();
2052       while (++index < length) {
2053         var entry = entries[index];
2054         this.set(entry[0], entry[1]);
2055       }
2056     }
2057
2058     /**
2059      * Removes all key-value entries from the list cache.
2060      *
2061      * @private
2062      * @name clear
2063      * @memberOf ListCache
2064      */
2065     function listCacheClear() {
2066       this.__data__ = [];
2067       this.size = 0;
2068     }
2069
2070     /**
2071      * Removes `key` and its value from the list cache.
2072      *
2073      * @private
2074      * @name delete
2075      * @memberOf ListCache
2076      * @param {string} key The key of the value to remove.
2077      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
2078      */
2079     function listCacheDelete(key) {
2080       var data = this.__data__,
2081           index = assocIndexOf(data, key);
2082
2083       if (index < 0) {
2084         return false;
2085       }
2086       var lastIndex = data.length - 1;
2087       if (index == lastIndex) {
2088         data.pop();
2089       } else {
2090         splice.call(data, index, 1);
2091       }
2092       --this.size;
2093       return true;
2094     }
2095
2096     /**
2097      * Gets the list cache value for `key`.
2098      *
2099      * @private
2100      * @name get
2101      * @memberOf ListCache
2102      * @param {string} key The key of the value to get.
2103      * @returns {*} Returns the entry value.
2104      */
2105     function listCacheGet(key) {
2106       var data = this.__data__,
2107           index = assocIndexOf(data, key);
2108
2109       return index < 0 ? undefined : data[index][1];
2110     }
2111
2112     /**
2113      * Checks if a list cache value for `key` exists.
2114      *
2115      * @private
2116      * @name has
2117      * @memberOf ListCache
2118      * @param {string} key The key of the entry to check.
2119      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2120      */
2121     function listCacheHas(key) {
2122       return assocIndexOf(this.__data__, key) > -1;
2123     }
2124
2125     /**
2126      * Sets the list cache `key` to `value`.
2127      *
2128      * @private
2129      * @name set
2130      * @memberOf ListCache
2131      * @param {string} key The key of the value to set.
2132      * @param {*} value The value to set.
2133      * @returns {Object} Returns the list cache instance.
2134      */
2135     function listCacheSet(key, value) {
2136       var data = this.__data__,
2137           index = assocIndexOf(data, key);
2138
2139       if (index < 0) {
2140         ++this.size;
2141         data.push([key, value]);
2142       } else {
2143         data[index][1] = value;
2144       }
2145       return this;
2146     }
2147
2148     // Add methods to `ListCache`.
2149     ListCache.prototype.clear = listCacheClear;
2150     ListCache.prototype['delete'] = listCacheDelete;
2151     ListCache.prototype.get = listCacheGet;
2152     ListCache.prototype.has = listCacheHas;
2153     ListCache.prototype.set = listCacheSet;
2154
2155     /*------------------------------------------------------------------------*/
2156
2157     /**
2158      * Creates a map cache object to store key-value pairs.
2159      *
2160      * @private
2161      * @constructor
2162      * @param {Array} [entries] The key-value pairs to cache.
2163      */
2164     function MapCache(entries) {
2165       var index = -1,
2166           length = entries == null ? 0 : entries.length;
2167
2168       this.clear();
2169       while (++index < length) {
2170         var entry = entries[index];
2171         this.set(entry[0], entry[1]);
2172       }
2173     }
2174
2175     /**
2176      * Removes all key-value entries from the map.
2177      *
2178      * @private
2179      * @name clear
2180      * @memberOf MapCache
2181      */
2182     function mapCacheClear() {
2183       this.size = 0;
2184       this.__data__ = {
2185         'hash': new Hash,
2186         'map': new (Map || ListCache),
2187         'string': new Hash
2188       };
2189     }
2190
2191     /**
2192      * Removes `key` and its value from the map.
2193      *
2194      * @private
2195      * @name delete
2196      * @memberOf MapCache
2197      * @param {string} key The key of the value to remove.
2198      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
2199      */
2200     function mapCacheDelete(key) {
2201       var result = getMapData(this, key)['delete'](key);
2202       this.size -= result ? 1 : 0;
2203       return result;
2204     }
2205
2206     /**
2207      * Gets the map value for `key`.
2208      *
2209      * @private
2210      * @name get
2211      * @memberOf MapCache
2212      * @param {string} key The key of the value to get.
2213      * @returns {*} Returns the entry value.
2214      */
2215     function mapCacheGet(key) {
2216       return getMapData(this, key).get(key);
2217     }
2218
2219     /**
2220      * Checks if a map value for `key` exists.
2221      *
2222      * @private
2223      * @name has
2224      * @memberOf MapCache
2225      * @param {string} key The key of the entry to check.
2226      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2227      */
2228     function mapCacheHas(key) {
2229       return getMapData(this, key).has(key);
2230     }
2231
2232     /**
2233      * Sets the map `key` to `value`.
2234      *
2235      * @private
2236      * @name set
2237      * @memberOf MapCache
2238      * @param {string} key The key of the value to set.
2239      * @param {*} value The value to set.
2240      * @returns {Object} Returns the map cache instance.
2241      */
2242     function mapCacheSet(key, value) {
2243       var data = getMapData(this, key),
2244           size = data.size;
2245
2246       data.set(key, value);
2247       this.size += data.size == size ? 0 : 1;
2248       return this;
2249     }
2250
2251     // Add methods to `MapCache`.
2252     MapCache.prototype.clear = mapCacheClear;
2253     MapCache.prototype['delete'] = mapCacheDelete;
2254     MapCache.prototype.get = mapCacheGet;
2255     MapCache.prototype.has = mapCacheHas;
2256     MapCache.prototype.set = mapCacheSet;
2257
2258     /*------------------------------------------------------------------------*/
2259
2260     /**
2261      *
2262      * Creates an array cache object to store unique values.
2263      *
2264      * @private
2265      * @constructor
2266      * @param {Array} [values] The values to cache.
2267      */
2268     function SetCache(values) {
2269       var index = -1,
2270           length = values == null ? 0 : values.length;
2271
2272       this.__data__ = new MapCache;
2273       while (++index < length) {
2274         this.add(values[index]);
2275       }
2276     }
2277
2278     /**
2279      * Adds `value` to the array cache.
2280      *
2281      * @private
2282      * @name add
2283      * @memberOf SetCache
2284      * @alias push
2285      * @param {*} value The value to cache.
2286      * @returns {Object} Returns the cache instance.
2287      */
2288     function setCacheAdd(value) {
2289       this.__data__.set(value, HASH_UNDEFINED);
2290       return this;
2291     }
2292
2293     /**
2294      * Checks if `value` is in the array cache.
2295      *
2296      * @private
2297      * @name has
2298      * @memberOf SetCache
2299      * @param {*} value The value to search for.
2300      * @returns {number} Returns `true` if `value` is found, else `false`.
2301      */
2302     function setCacheHas(value) {
2303       return this.__data__.has(value);
2304     }
2305
2306     // Add methods to `SetCache`.
2307     SetCache.prototype.add = SetCache.prototype.push = setCacheAdd;
2308     SetCache.prototype.has = setCacheHas;
2309
2310     /*------------------------------------------------------------------------*/
2311
2312     /**
2313      * Creates a stack cache object to store key-value pairs.
2314      *
2315      * @private
2316      * @constructor
2317      * @param {Array} [entries] The key-value pairs to cache.
2318      */
2319     function Stack(entries) {
2320       var data = this.__data__ = new ListCache(entries);
2321       this.size = data.size;
2322     }
2323
2324     /**
2325      * Removes all key-value entries from the stack.
2326      *
2327      * @private
2328      * @name clear
2329      * @memberOf Stack
2330      */
2331     function stackClear() {
2332       this.__data__ = new ListCache;
2333       this.size = 0;
2334     }
2335
2336     /**
2337      * Removes `key` and its value from the stack.
2338      *
2339      * @private
2340      * @name delete
2341      * @memberOf Stack
2342      * @param {string} key The key of the value to remove.
2343      * @returns {boolean} Returns `true` if the entry was removed, else `false`.
2344      */
2345     function stackDelete(key) {
2346       var data = this.__data__,
2347           result = data['delete'](key);
2348
2349       this.size = data.size;
2350       return result;
2351     }
2352
2353     /**
2354      * Gets the stack value for `key`.
2355      *
2356      * @private
2357      * @name get
2358      * @memberOf Stack
2359      * @param {string} key The key of the value to get.
2360      * @returns {*} Returns the entry value.
2361      */
2362     function stackGet(key) {
2363       return this.__data__.get(key);
2364     }
2365
2366     /**
2367      * Checks if a stack value for `key` exists.
2368      *
2369      * @private
2370      * @name has
2371      * @memberOf Stack
2372      * @param {string} key The key of the entry to check.
2373      * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
2374      */
2375     function stackHas(key) {
2376       return this.__data__.has(key);
2377     }
2378
2379     /**
2380      * Sets the stack `key` to `value`.
2381      *
2382      * @private
2383      * @name set
2384      * @memberOf Stack
2385      * @param {string} key The key of the value to set.
2386      * @param {*} value The value to set.
2387      * @returns {Object} Returns the stack cache instance.
2388      */
2389     function stackSet(key, value) {
2390       var data = this.__data__;
2391       if (data instanceof ListCache) {
2392         var pairs = data.__data__;
2393         if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) {
2394           pairs.push([key, value]);
2395           this.size = ++data.size;
2396           return this;
2397         }
2398         data = this.__data__ = new MapCache(pairs);
2399       }
2400       data.set(key, value);
2401       this.size = data.size;
2402       return this;
2403     }
2404
2405     // Add methods to `Stack`.
2406     Stack.prototype.clear = stackClear;
2407     Stack.prototype['delete'] = stackDelete;
2408     Stack.prototype.get = stackGet;
2409     Stack.prototype.has = stackHas;
2410     Stack.prototype.set = stackSet;
2411
2412     /*------------------------------------------------------------------------*/
2413
2414     /**
2415      * Creates an array of the enumerable property names of the array-like `value`.
2416      *
2417      * @private
2418      * @param {*} value The value to query.
2419      * @param {boolean} inherited Specify returning inherited property names.
2420      * @returns {Array} Returns the array of property names.
2421      */
2422     function arrayLikeKeys(value, inherited) {
2423       var isArr = isArray(value),
2424           isArg = !isArr && isArguments(value),
2425           isBuff = !isArr && !isArg && isBuffer(value),
2426           isType = !isArr && !isArg && !isBuff && isTypedArray(value),
2427           skipIndexes = isArr || isArg || isBuff || isType,
2428           result = skipIndexes ? baseTimes(value.length, String) : [],
2429           length = result.length;
2430
2431       for (var key in value) {
2432         if ((inherited || hasOwnProperty.call(value, key)) &&
2433             !(skipIndexes && (
2434                // Safari 9 has enumerable `arguments.length` in strict mode.
2435                key == 'length' ||
2436                // Node.js 0.10 has enumerable non-index properties on buffers.
2437                (isBuff && (key == 'offset' || key == 'parent')) ||
2438                // PhantomJS 2 has enumerable non-index properties on typed arrays.
2439                (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) ||
2440                // Skip index properties.
2441                isIndex(key, length)
2442             ))) {
2443           result.push(key);
2444         }
2445       }
2446       return result;
2447     }
2448
2449     /**
2450      * A specialized version of `_.sample` for arrays.
2451      *
2452      * @private
2453      * @param {Array} array The array to sample.
2454      * @returns {*} Returns the random element.
2455      */
2456     function arraySample(array) {
2457       var length = array.length;
2458       return length ? array[baseRandom(0, length - 1)] : undefined;
2459     }
2460
2461     /**
2462      * A specialized version of `_.sampleSize` for arrays.
2463      *
2464      * @private
2465      * @param {Array} array The array to sample.
2466      * @param {number} n The number of elements to sample.
2467      * @returns {Array} Returns the random elements.
2468      */
2469     function arraySampleSize(array, n) {
2470       return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length));
2471     }
2472
2473     /**
2474      * A specialized version of `_.shuffle` for arrays.
2475      *
2476      * @private
2477      * @param {Array} array The array to shuffle.
2478      * @returns {Array} Returns the new shuffled array.
2479      */
2480     function arrayShuffle(array) {
2481       return shuffleSelf(copyArray(array));
2482     }
2483
2484     /**
2485      * This function is like `assignValue` except that it doesn't assign
2486      * `undefined` values.
2487      *
2488      * @private
2489      * @param {Object} object The object to modify.
2490      * @param {string} key The key of the property to assign.
2491      * @param {*} value The value to assign.
2492      */
2493     function assignMergeValue(object, key, value) {
2494       if ((value !== undefined && !eq(object[key], value)) ||
2495           (value === undefined && !(key in object))) {
2496         baseAssignValue(object, key, value);
2497       }
2498     }
2499
2500     /**
2501      * Assigns `value` to `key` of `object` if the existing value is not equivalent
2502      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
2503      * for equality comparisons.
2504      *
2505      * @private
2506      * @param {Object} object The object to modify.
2507      * @param {string} key The key of the property to assign.
2508      * @param {*} value The value to assign.
2509      */
2510     function assignValue(object, key, value) {
2511       var objValue = object[key];
2512       if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
2513           (value === undefined && !(key in object))) {
2514         baseAssignValue(object, key, value);
2515       }
2516     }
2517
2518     /**
2519      * Gets the index at which the `key` is found in `array` of key-value pairs.
2520      *
2521      * @private
2522      * @param {Array} array The array to inspect.
2523      * @param {*} key The key to search for.
2524      * @returns {number} Returns the index of the matched value, else `-1`.
2525      */
2526     function assocIndexOf(array, key) {
2527       var length = array.length;
2528       while (length--) {
2529         if (eq(array[length][0], key)) {
2530           return length;
2531         }
2532       }
2533       return -1;
2534     }
2535
2536     /**
2537      * Aggregates elements of `collection` on `accumulator` with keys transformed
2538      * by `iteratee` and values set by `setter`.
2539      *
2540      * @private
2541      * @param {Array|Object} collection The collection to iterate over.
2542      * @param {Function} setter The function to set `accumulator` values.
2543      * @param {Function} iteratee The iteratee to transform keys.
2544      * @param {Object} accumulator The initial aggregated object.
2545      * @returns {Function} Returns `accumulator`.
2546      */
2547     function baseAggregator(collection, setter, iteratee, accumulator) {
2548       baseEach(collection, function(value, key, collection) {
2549         setter(accumulator, value, iteratee(value), collection);
2550       });
2551       return accumulator;
2552     }
2553
2554     /**
2555      * The base implementation of `_.assign` without support for multiple sources
2556      * or `customizer` functions.
2557      *
2558      * @private
2559      * @param {Object} object The destination object.
2560      * @param {Object} source The source object.
2561      * @returns {Object} Returns `object`.
2562      */
2563     function baseAssign(object, source) {
2564       return object && copyObject(source, keys(source), object);
2565     }
2566
2567     /**
2568      * The base implementation of `_.assignIn` without support for multiple sources
2569      * or `customizer` functions.
2570      *
2571      * @private
2572      * @param {Object} object The destination object.
2573      * @param {Object} source The source object.
2574      * @returns {Object} Returns `object`.
2575      */
2576     function baseAssignIn(object, source) {
2577       return object && copyObject(source, keysIn(source), object);
2578     }
2579
2580     /**
2581      * The base implementation of `assignValue` and `assignMergeValue` without
2582      * value checks.
2583      *
2584      * @private
2585      * @param {Object} object The object to modify.
2586      * @param {string} key The key of the property to assign.
2587      * @param {*} value The value to assign.
2588      */
2589     function baseAssignValue(object, key, value) {
2590       if (key == '__proto__' && defineProperty) {
2591         defineProperty(object, key, {
2592           'configurable': true,
2593           'enumerable': true,
2594           'value': value,
2595           'writable': true
2596         });
2597       } else {
2598         object[key] = value;
2599       }
2600     }
2601
2602     /**
2603      * The base implementation of `_.at` without support for individual paths.
2604      *
2605      * @private
2606      * @param {Object} object The object to iterate over.
2607      * @param {string[]} paths The property paths to pick.
2608      * @returns {Array} Returns the picked elements.
2609      */
2610     function baseAt(object, paths) {
2611       var index = -1,
2612           length = paths.length,
2613           result = Array(length),
2614           skip = object == null;
2615
2616       while (++index < length) {
2617         result[index] = skip ? undefined : get(object, paths[index]);
2618       }
2619       return result;
2620     }
2621
2622     /**
2623      * The base implementation of `_.clamp` which doesn't coerce arguments.
2624      *
2625      * @private
2626      * @param {number} number The number to clamp.
2627      * @param {number} [lower] The lower bound.
2628      * @param {number} upper The upper bound.
2629      * @returns {number} Returns the clamped number.
2630      */
2631     function baseClamp(number, lower, upper) {
2632       if (number === number) {
2633         if (upper !== undefined) {
2634           number = number <= upper ? number : upper;
2635         }
2636         if (lower !== undefined) {
2637           number = number >= lower ? number : lower;
2638         }
2639       }
2640       return number;
2641     }
2642
2643     /**
2644      * The base implementation of `_.clone` and `_.cloneDeep` which tracks
2645      * traversed objects.
2646      *
2647      * @private
2648      * @param {*} value The value to clone.
2649      * @param {boolean} bitmask The bitmask flags.
2650      *  1 - Deep clone
2651      *  2 - Flatten inherited properties
2652      *  4 - Clone symbols
2653      * @param {Function} [customizer] The function to customize cloning.
2654      * @param {string} [key] The key of `value`.
2655      * @param {Object} [object] The parent object of `value`.
2656      * @param {Object} [stack] Tracks traversed objects and their clone counterparts.
2657      * @returns {*} Returns the cloned value.
2658      */
2659     function baseClone(value, bitmask, customizer, key, object, stack) {
2660       var result,
2661           isDeep = bitmask & CLONE_DEEP_FLAG,
2662           isFlat = bitmask & CLONE_FLAT_FLAG,
2663           isFull = bitmask & CLONE_SYMBOLS_FLAG;
2664
2665       if (customizer) {
2666         result = object ? customizer(value, key, object, stack) : customizer(value);
2667       }
2668       if (result !== undefined) {
2669         return result;
2670       }
2671       if (!isObject(value)) {
2672         return value;
2673       }
2674       var isArr = isArray(value);
2675       if (isArr) {
2676         result = initCloneArray(value);
2677         if (!isDeep) {
2678           return copyArray(value, result);
2679         }
2680       } else {
2681         var tag = getTag(value),
2682             isFunc = tag == funcTag || tag == genTag;
2683
2684         if (isBuffer(value)) {
2685           return cloneBuffer(value, isDeep);
2686         }
2687         if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
2688           result = (isFlat || isFunc) ? {} : initCloneObject(value);
2689           if (!isDeep) {
2690             return isFlat
2691               ? copySymbolsIn(value, baseAssignIn(result, value))
2692               : copySymbols(value, baseAssign(result, value));
2693           }
2694         } else {
2695           if (!cloneableTags[tag]) {
2696             return object ? value : {};
2697           }
2698           result = initCloneByTag(value, tag, baseClone, isDeep);
2699         }
2700       }
2701       // Check for circular references and return its corresponding clone.
2702       stack || (stack = new Stack);
2703       var stacked = stack.get(value);
2704       if (stacked) {
2705         return stacked;
2706       }
2707       stack.set(value, result);
2708
2709       var keysFunc = isFull
2710         ? (isFlat ? getAllKeysIn : getAllKeys)
2711         : (isFlat ? keysIn : keys);
2712
2713       var props = isArr ? undefined : keysFunc(value);
2714       arrayEach(props || value, function(subValue, key) {
2715         if (props) {
2716           key = subValue;
2717           subValue = value[key];
2718         }
2719         // Recursively populate clone (susceptible to call stack limits).
2720         assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack));
2721       });
2722       return result;
2723     }
2724
2725     /**
2726      * The base implementation of `_.conforms` which doesn't clone `source`.
2727      *
2728      * @private
2729      * @param {Object} source The object of property predicates to conform to.
2730      * @returns {Function} Returns the new spec function.
2731      */
2732     function baseConforms(source) {
2733       var props = keys(source);
2734       return function(object) {
2735         return baseConformsTo(object, source, props);
2736       };
2737     }
2738
2739     /**
2740      * The base implementation of `_.conformsTo` which accepts `props` to check.
2741      *
2742      * @private
2743      * @param {Object} object The object to inspect.
2744      * @param {Object} source The object of property predicates to conform to.
2745      * @returns {boolean} Returns `true` if `object` conforms, else `false`.
2746      */
2747     function baseConformsTo(object, source, props) {
2748       var length = props.length;
2749       if (object == null) {
2750         return !length;
2751       }
2752       object = Object(object);
2753       while (length--) {
2754         var key = props[length],
2755             predicate = source[key],
2756             value = object[key];
2757
2758         if ((value === undefined && !(key in object)) || !predicate(value)) {
2759           return false;
2760         }
2761       }
2762       return true;
2763     }
2764
2765     /**
2766      * The base implementation of `_.delay` and `_.defer` which accepts `args`
2767      * to provide to `func`.
2768      *
2769      * @private
2770      * @param {Function} func The function to delay.
2771      * @param {number} wait The number of milliseconds to delay invocation.
2772      * @param {Array} args The arguments to provide to `func`.
2773      * @returns {number|Object} Returns the timer id or timeout object.
2774      */
2775     function baseDelay(func, wait, args) {
2776       if (typeof func != 'function') {
2777         throw new TypeError(FUNC_ERROR_TEXT);
2778       }
2779       return setTimeout(function() { func.apply(undefined, args); }, wait);
2780     }
2781
2782     /**
2783      * The base implementation of methods like `_.difference` without support
2784      * for excluding multiple arrays or iteratee shorthands.
2785      *
2786      * @private
2787      * @param {Array} array The array to inspect.
2788      * @param {Array} values The values to exclude.
2789      * @param {Function} [iteratee] The iteratee invoked per element.
2790      * @param {Function} [comparator] The comparator invoked per element.
2791      * @returns {Array} Returns the new array of filtered values.
2792      */
2793     function baseDifference(array, values, iteratee, comparator) {
2794       var index = -1,
2795           includes = arrayIncludes,
2796           isCommon = true,
2797           length = array.length,
2798           result = [],
2799           valuesLength = values.length;
2800
2801       if (!length) {
2802         return result;
2803       }
2804       if (iteratee) {
2805         values = arrayMap(values, baseUnary(iteratee));
2806       }
2807       if (comparator) {
2808         includes = arrayIncludesWith;
2809         isCommon = false;
2810       }
2811       else if (values.length >= LARGE_ARRAY_SIZE) {
2812         includes = cacheHas;
2813         isCommon = false;
2814         values = new SetCache(values);
2815       }
2816       outer:
2817       while (++index < length) {
2818         var value = array[index],
2819             computed = iteratee == null ? value : iteratee(value);
2820
2821         value = (comparator || value !== 0) ? value : 0;
2822         if (isCommon && computed === computed) {
2823           var valuesIndex = valuesLength;
2824           while (valuesIndex--) {
2825             if (values[valuesIndex] === computed) {
2826               continue outer;
2827             }
2828           }
2829           result.push(value);
2830         }
2831         else if (!includes(values, computed, comparator)) {
2832           result.push(value);
2833         }
2834       }
2835       return result;
2836     }
2837
2838     /**
2839      * The base implementation of `_.forEach` without support for iteratee shorthands.
2840      *
2841      * @private
2842      * @param {Array|Object} collection The collection to iterate over.
2843      * @param {Function} iteratee The function invoked per iteration.
2844      * @returns {Array|Object} Returns `collection`.
2845      */
2846     var baseEach = createBaseEach(baseForOwn);
2847
2848     /**
2849      * The base implementation of `_.forEachRight` without support for iteratee shorthands.
2850      *
2851      * @private
2852      * @param {Array|Object} collection The collection to iterate over.
2853      * @param {Function} iteratee The function invoked per iteration.
2854      * @returns {Array|Object} Returns `collection`.
2855      */
2856     var baseEachRight = createBaseEach(baseForOwnRight, true);
2857
2858     /**
2859      * The base implementation of `_.every` without support for iteratee shorthands.
2860      *
2861      * @private
2862      * @param {Array|Object} collection The collection to iterate over.
2863      * @param {Function} predicate The function invoked per iteration.
2864      * @returns {boolean} Returns `true` if all elements pass the predicate check,
2865      *  else `false`
2866      */
2867     function baseEvery(collection, predicate) {
2868       var result = true;
2869       baseEach(collection, function(value, index, collection) {
2870         result = !!predicate(value, index, collection);
2871         return result;
2872       });
2873       return result;
2874     }
2875
2876     /**
2877      * The base implementation of methods like `_.max` and `_.min` which accepts a
2878      * `comparator` to determine the extremum value.
2879      *
2880      * @private
2881      * @param {Array} array The array to iterate over.
2882      * @param {Function} iteratee The iteratee invoked per iteration.
2883      * @param {Function} comparator The comparator used to compare values.
2884      * @returns {*} Returns the extremum value.
2885      */
2886     function baseExtremum(array, iteratee, comparator) {
2887       var index = -1,
2888           length = array.length;
2889
2890       while (++index < length) {
2891         var value = array[index],
2892             current = iteratee(value);
2893
2894         if (current != null && (computed === undefined
2895               ? (current === current && !isSymbol(current))
2896               : comparator(current, computed)
2897             )) {
2898           var computed = current,
2899               result = value;
2900         }
2901       }
2902       return result;
2903     }
2904
2905     /**
2906      * The base implementation of `_.fill` without an iteratee call guard.
2907      *
2908      * @private
2909      * @param {Array} array The array to fill.
2910      * @param {*} value The value to fill `array` with.
2911      * @param {number} [start=0] The start position.
2912      * @param {number} [end=array.length] The end position.
2913      * @returns {Array} Returns `array`.
2914      */
2915     function baseFill(array, value, start, end) {
2916       var length = array.length;
2917
2918       start = toInteger(start);
2919       if (start < 0) {
2920         start = -start > length ? 0 : (length + start);
2921       }
2922       end = (end === undefined || end > length) ? length : toInteger(end);
2923       if (end < 0) {
2924         end += length;
2925       }
2926       end = start > end ? 0 : toLength(end);
2927       while (start < end) {
2928         array[start++] = value;
2929       }
2930       return array;
2931     }
2932
2933     /**
2934      * The base implementation of `_.filter` without support for iteratee shorthands.
2935      *
2936      * @private
2937      * @param {Array|Object} collection The collection to iterate over.
2938      * @param {Function} predicate The function invoked per iteration.
2939      * @returns {Array} Returns the new filtered array.
2940      */
2941     function baseFilter(collection, predicate) {
2942       var result = [];
2943       baseEach(collection, function(value, index, collection) {
2944         if (predicate(value, index, collection)) {
2945           result.push(value);
2946         }
2947       });
2948       return result;
2949     }
2950
2951     /**
2952      * The base implementation of `_.flatten` with support for restricting flattening.
2953      *
2954      * @private
2955      * @param {Array} array The array to flatten.
2956      * @param {number} depth The maximum recursion depth.
2957      * @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
2958      * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
2959      * @param {Array} [result=[]] The initial result value.
2960      * @returns {Array} Returns the new flattened array.
2961      */
2962     function baseFlatten(array, depth, predicate, isStrict, result) {
2963       var index = -1,
2964           length = array.length;
2965
2966       predicate || (predicate = isFlattenable);
2967       result || (result = []);
2968
2969       while (++index < length) {
2970         var value = array[index];
2971         if (depth > 0 && predicate(value)) {
2972           if (depth > 1) {
2973             // Recursively flatten arrays (susceptible to call stack limits).
2974             baseFlatten(value, depth - 1, predicate, isStrict, result);
2975           } else {
2976             arrayPush(result, value);
2977           }
2978         } else if (!isStrict) {
2979           result[result.length] = value;
2980         }
2981       }
2982       return result;
2983     }
2984
2985     /**
2986      * The base implementation of `baseForOwn` which iterates over `object`
2987      * properties returned by `keysFunc` and invokes `iteratee` for each property.
2988      * Iteratee functions may exit iteration early by explicitly returning `false`.
2989      *
2990      * @private
2991      * @param {Object} object The object to iterate over.
2992      * @param {Function} iteratee The function invoked per iteration.
2993      * @param {Function} keysFunc The function to get the keys of `object`.
2994      * @returns {Object} Returns `object`.
2995      */
2996     var baseFor = createBaseFor();
2997
2998     /**
2999      * This function is like `baseFor` except that it iterates over properties
3000      * in the opposite order.
3001      *
3002      * @private
3003      * @param {Object} object The object to iterate over.
3004      * @param {Function} iteratee The function invoked per iteration.
3005      * @param {Function} keysFunc The function to get the keys of `object`.
3006      * @returns {Object} Returns `object`.
3007      */
3008     var baseForRight = createBaseFor(true);
3009
3010     /**
3011      * The base implementation of `_.forOwn` without support for iteratee shorthands.
3012      *
3013      * @private
3014      * @param {Object} object The object to iterate over.
3015      * @param {Function} iteratee The function invoked per iteration.
3016      * @returns {Object} Returns `object`.
3017      */
3018     function baseForOwn(object, iteratee) {
3019       return object && baseFor(object, iteratee, keys);
3020     }
3021
3022     /**
3023      * The base implementation of `_.forOwnRight` without support for iteratee shorthands.
3024      *
3025      * @private
3026      * @param {Object} object The object to iterate over.
3027      * @param {Function} iteratee The function invoked per iteration.
3028      * @returns {Object} Returns `object`.
3029      */
3030     function baseForOwnRight(object, iteratee) {
3031       return object && baseForRight(object, iteratee, keys);
3032     }
3033
3034     /**
3035      * The base implementation of `_.functions` which creates an array of
3036      * `object` function property names filtered from `props`.
3037      *
3038      * @private
3039      * @param {Object} object The object to inspect.
3040      * @param {Array} props The property names to filter.
3041      * @returns {Array} Returns the function names.
3042      */
3043     function baseFunctions(object, props) {
3044       return arrayFilter(props, function(key) {
3045         return isFunction(object[key]);
3046       });
3047     }
3048
3049     /**
3050      * The base implementation of `_.get` without support for default values.
3051      *
3052      * @private
3053      * @param {Object} object The object to query.
3054      * @param {Array|string} path The path of the property to get.
3055      * @returns {*} Returns the resolved value.
3056      */
3057     function baseGet(object, path) {
3058       path = castPath(path, object);
3059
3060       var index = 0,
3061           length = path.length;
3062
3063       while (object != null && index < length) {
3064         object = object[toKey(path[index++])];
3065       }
3066       return (index && index == length) ? object : undefined;
3067     }
3068
3069     /**
3070      * The base implementation of `getAllKeys` and `getAllKeysIn` which uses
3071      * `keysFunc` and `symbolsFunc` to get the enumerable property names and
3072      * symbols of `object`.
3073      *
3074      * @private
3075      * @param {Object} object The object to query.
3076      * @param {Function} keysFunc The function to get the keys of `object`.
3077      * @param {Function} symbolsFunc The function to get the symbols of `object`.
3078      * @returns {Array} Returns the array of property names and symbols.
3079      */
3080     function baseGetAllKeys(object, keysFunc, symbolsFunc) {
3081       var result = keysFunc(object);
3082       return isArray(object) ? result : arrayPush(result, symbolsFunc(object));
3083     }
3084
3085     /**
3086      * The base implementation of `getTag` without fallbacks for buggy environments.
3087      *
3088      * @private
3089      * @param {*} value The value to query.
3090      * @returns {string} Returns the `toStringTag`.
3091      */
3092     function baseGetTag(value) {
3093       if (value == null) {
3094         return value === undefined ? undefinedTag : nullTag;
3095       }
3096       return (symToStringTag && symToStringTag in Object(value))
3097         ? getRawTag(value)
3098         : objectToString(value);
3099     }
3100
3101     /**
3102      * The base implementation of `_.gt` which doesn't coerce arguments.
3103      *
3104      * @private
3105      * @param {*} value The value to compare.
3106      * @param {*} other The other value to compare.
3107      * @returns {boolean} Returns `true` if `value` is greater than `other`,
3108      *  else `false`.
3109      */
3110     function baseGt(value, other) {
3111       return value > other;
3112     }
3113
3114     /**
3115      * The base implementation of `_.has` without support for deep paths.
3116      *
3117      * @private
3118      * @param {Object} [object] The object to query.
3119      * @param {Array|string} key The key to check.
3120      * @returns {boolean} Returns `true` if `key` exists, else `false`.
3121      */
3122     function baseHas(object, key) {
3123       return object != null && hasOwnProperty.call(object, key);
3124     }
3125
3126     /**
3127      * The base implementation of `_.hasIn` without support for deep paths.
3128      *
3129      * @private
3130      * @param {Object} [object] The object to query.
3131      * @param {Array|string} key The key to check.
3132      * @returns {boolean} Returns `true` if `key` exists, else `false`.
3133      */
3134     function baseHasIn(object, key) {
3135       return object != null && key in Object(object);
3136     }
3137
3138     /**
3139      * The base implementation of `_.inRange` which doesn't coerce arguments.
3140      *
3141      * @private
3142      * @param {number} number The number to check.
3143      * @param {number} start The start of the range.
3144      * @param {number} end The end of the range.
3145      * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
3146      */
3147     function baseInRange(number, start, end) {
3148       return number >= nativeMin(start, end) && number < nativeMax(start, end);
3149     }
3150
3151     /**
3152      * The base implementation of methods like `_.intersection`, without support
3153      * for iteratee shorthands, that accepts an array of arrays to inspect.
3154      *
3155      * @private
3156      * @param {Array} arrays The arrays to inspect.
3157      * @param {Function} [iteratee] The iteratee invoked per element.
3158      * @param {Function} [comparator] The comparator invoked per element.
3159      * @returns {Array} Returns the new array of shared values.
3160      */
3161     function baseIntersection(arrays, iteratee, comparator) {
3162       var includes = comparator ? arrayIncludesWith : arrayIncludes,
3163           length = arrays[0].length,
3164           othLength = arrays.length,
3165           othIndex = othLength,
3166           caches = Array(othLength),
3167           maxLength = Infinity,
3168           result = [];
3169
3170       while (othIndex--) {
3171         var array = arrays[othIndex];
3172         if (othIndex && iteratee) {
3173           array = arrayMap(array, baseUnary(iteratee));
3174         }
3175         maxLength = nativeMin(array.length, maxLength);
3176         caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
3177           ? new SetCache(othIndex && array)
3178           : undefined;
3179       }
3180       array = arrays[0];
3181
3182       var index = -1,
3183           seen = caches[0];
3184
3185       outer:
3186       while (++index < length && result.length < maxLength) {
3187         var value = array[index],
3188             computed = iteratee ? iteratee(value) : value;
3189
3190         value = (comparator || value !== 0) ? value : 0;
3191         if (!(seen
3192               ? cacheHas(seen, computed)
3193               : includes(result, computed, comparator)
3194             )) {
3195           othIndex = othLength;
3196           while (--othIndex) {
3197             var cache = caches[othIndex];
3198             if (!(cache
3199                   ? cacheHas(cache, computed)
3200                   : includes(arrays[othIndex], computed, comparator))
3201                 ) {
3202               continue outer;
3203             }
3204           }
3205           if (seen) {
3206             seen.push(computed);
3207           }
3208           result.push(value);
3209         }
3210       }
3211       return result;
3212     }
3213
3214     /**
3215      * The base implementation of `_.invert` and `_.invertBy` which inverts
3216      * `object` with values transformed by `iteratee` and set by `setter`.
3217      *
3218      * @private
3219      * @param {Object} object The object to iterate over.
3220      * @param {Function} setter The function to set `accumulator` values.
3221      * @param {Function} iteratee The iteratee to transform values.
3222      * @param {Object} accumulator The initial inverted object.
3223      * @returns {Function} Returns `accumulator`.
3224      */
3225     function baseInverter(object, setter, iteratee, accumulator) {
3226       baseForOwn(object, function(value, key, object) {
3227         setter(accumulator, iteratee(value), key, object);
3228       });
3229       return accumulator;
3230     }
3231
3232     /**
3233      * The base implementation of `_.invoke` without support for individual
3234      * method arguments.
3235      *
3236      * @private
3237      * @param {Object} object The object to query.
3238      * @param {Array|string} path The path of the method to invoke.
3239      * @param {Array} args The arguments to invoke the method with.
3240      * @returns {*} Returns the result of the invoked method.
3241      */
3242     function baseInvoke(object, path, args) {
3243       path = castPath(path, object);
3244       object = parent(object, path);
3245       var func = object == null ? object : object[toKey(last(path))];
3246       return func == null ? undefined : apply(func, object, args);
3247     }
3248
3249     /**
3250      * The base implementation of `_.isArguments`.
3251      *
3252      * @private
3253      * @param {*} value The value to check.
3254      * @returns {boolean} Returns `true` if `value` is an `arguments` object,
3255      */
3256     function baseIsArguments(value) {
3257       return isObjectLike(value) && baseGetTag(value) == argsTag;
3258     }
3259
3260     /**
3261      * The base implementation of `_.isArrayBuffer` without Node.js optimizations.
3262      *
3263      * @private
3264      * @param {*} value The value to check.
3265      * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
3266      */
3267     function baseIsArrayBuffer(value) {
3268       return isObjectLike(value) && baseGetTag(value) == arrayBufferTag;
3269     }
3270
3271     /**
3272      * The base implementation of `_.isDate` without Node.js optimizations.
3273      *
3274      * @private
3275      * @param {*} value The value to check.
3276      * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
3277      */
3278     function baseIsDate(value) {
3279       return isObjectLike(value) && baseGetTag(value) == dateTag;
3280     }
3281
3282     /**
3283      * The base implementation of `_.isEqual` which supports partial comparisons
3284      * and tracks traversed objects.
3285      *
3286      * @private
3287      * @param {*} value The value to compare.
3288      * @param {*} other The other value to compare.
3289      * @param {boolean} bitmask The bitmask flags.
3290      *  1 - Unordered comparison
3291      *  2 - Partial comparison
3292      * @param {Function} [customizer] The function to customize comparisons.
3293      * @param {Object} [stack] Tracks traversed `value` and `other` objects.
3294      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
3295      */
3296     function baseIsEqual(value, other, bitmask, customizer, stack) {
3297       if (value === other) {
3298         return true;
3299       }
3300       if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) {
3301         return value !== value && other !== other;
3302       }
3303       return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack);
3304     }
3305
3306     /**
3307      * A specialized version of `baseIsEqual` for arrays and objects which performs
3308      * deep comparisons and tracks traversed objects enabling objects with circular
3309      * references to be compared.
3310      *
3311      * @private
3312      * @param {Object} object The object to compare.
3313      * @param {Object} other The other object to compare.
3314      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
3315      * @param {Function} customizer The function to customize comparisons.
3316      * @param {Function} equalFunc The function to determine equivalents of values.
3317      * @param {Object} [stack] Tracks traversed `object` and `other` objects.
3318      * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
3319      */
3320     function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) {
3321       var objIsArr = isArray(object),
3322           othIsArr = isArray(other),
3323           objTag = objIsArr ? arrayTag : getTag(object),
3324           othTag = othIsArr ? arrayTag : getTag(other);
3325
3326       objTag = objTag == argsTag ? objectTag : objTag;
3327       othTag = othTag == argsTag ? objectTag : othTag;
3328
3329       var objIsObj = objTag == objectTag,
3330           othIsObj = othTag == objectTag,
3331           isSameTag = objTag == othTag;
3332
3333       if (isSameTag && isBuffer(object)) {
3334         if (!isBuffer(other)) {
3335           return false;
3336         }
3337         objIsArr = true;
3338         objIsObj = false;
3339       }
3340       if (isSameTag && !objIsObj) {
3341         stack || (stack = new Stack);
3342         return (objIsArr || isTypedArray(object))
3343           ? equalArrays(object, other, bitmask, customizer, equalFunc, stack)
3344           : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack);
3345       }
3346       if (!(bitmask & COMPARE_PARTIAL_FLAG)) {
3347         var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
3348             othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
3349
3350         if (objIsWrapped || othIsWrapped) {
3351           var objUnwrapped = objIsWrapped ? object.value() : object,
3352               othUnwrapped = othIsWrapped ? other.value() : other;
3353
3354           stack || (stack = new Stack);
3355           return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack);
3356         }
3357       }
3358       if (!isSameTag) {
3359         return false;
3360       }
3361       stack || (stack = new Stack);
3362       return equalObjects(object, other, bitmask, customizer, equalFunc, stack);
3363     }
3364
3365     /**
3366      * The base implementation of `_.isMap` without Node.js optimizations.
3367      *
3368      * @private
3369      * @param {*} value The value to check.
3370      * @returns {boolean} Returns `true` if `value` is a map, else `false`.
3371      */
3372     function baseIsMap(value) {
3373       return isObjectLike(value) && getTag(value) == mapTag;
3374     }
3375
3376     /**
3377      * The base implementation of `_.isMatch` without support for iteratee shorthands.
3378      *
3379      * @private
3380      * @param {Object} object The object to inspect.
3381      * @param {Object} source The object of property values to match.
3382      * @param {Array} matchData The property names, values, and compare flags to match.
3383      * @param {Function} [customizer] The function to customize comparisons.
3384      * @returns {boolean} Returns `true` if `object` is a match, else `false`.
3385      */
3386     function baseIsMatch(object, source, matchData, customizer) {
3387       var index = matchData.length,
3388           length = index,
3389           noCustomizer = !customizer;
3390
3391       if (object == null) {
3392         return !length;
3393       }
3394       object = Object(object);
3395       while (index--) {
3396         var data = matchData[index];
3397         if ((noCustomizer && data[2])
3398               ? data[1] !== object[data[0]]
3399               : !(data[0] in object)
3400             ) {
3401           return false;
3402         }
3403       }
3404       while (++index < length) {
3405         data = matchData[index];
3406         var key = data[0],
3407             objValue = object[key],
3408             srcValue = data[1];
3409
3410         if (noCustomizer && data[2]) {
3411           if (objValue === undefined && !(key in object)) {
3412             return false;
3413           }
3414         } else {
3415           var stack = new Stack;
3416           if (customizer) {
3417             var result = customizer(objValue, srcValue, key, object, source, stack);
3418           }
3419           if (!(result === undefined
3420                 ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack)
3421                 : result
3422               )) {
3423             return false;
3424           }
3425         }
3426       }
3427       return true;
3428     }
3429
3430     /**
3431      * The base implementation of `_.isNative` without bad shim checks.
3432      *
3433      * @private
3434      * @param {*} value The value to check.
3435      * @returns {boolean} Returns `true` if `value` is a native function,
3436      *  else `false`.
3437      */
3438     function baseIsNative(value) {
3439       if (!isObject(value) || isMasked(value)) {
3440         return false;
3441       }
3442       var pattern = isFunction(value) ? reIsNative : reIsHostCtor;
3443       return pattern.test(toSource(value));
3444     }
3445
3446     /**
3447      * The base implementation of `_.isRegExp` without Node.js optimizations.
3448      *
3449      * @private
3450      * @param {*} value The value to check.
3451      * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
3452      */
3453     function baseIsRegExp(value) {
3454       return isObjectLike(value) && baseGetTag(value) == regexpTag;
3455     }
3456
3457     /**
3458      * The base implementation of `_.isSet` without Node.js optimizations.
3459      *
3460      * @private
3461      * @param {*} value The value to check.
3462      * @returns {boolean} Returns `true` if `value` is a set, else `false`.
3463      */
3464     function baseIsSet(value) {
3465       return isObjectLike(value) && getTag(value) == setTag;
3466     }
3467
3468     /**
3469      * The base implementation of `_.isTypedArray` without Node.js optimizations.
3470      *
3471      * @private
3472      * @param {*} value The value to check.
3473      * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
3474      */
3475     function baseIsTypedArray(value) {
3476       return isObjectLike(value) &&
3477         isLength(value.length) && !!typedArrayTags[baseGetTag(value)];
3478     }
3479
3480     /**
3481      * The base implementation of `_.iteratee`.
3482      *
3483      * @private
3484      * @param {*} [value=_.identity] The value to convert to an iteratee.
3485      * @returns {Function} Returns the iteratee.
3486      */
3487     function baseIteratee(value) {
3488       // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
3489       // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
3490       if (typeof value == 'function') {
3491         return value;
3492       }
3493       if (value == null) {
3494         return identity;
3495       }
3496       if (typeof value == 'object') {
3497         return isArray(value)
3498           ? baseMatchesProperty(value[0], value[1])
3499           : baseMatches(value);
3500       }
3501       return property(value);
3502     }
3503
3504     /**
3505      * The base implementation of `_.keys` which doesn't treat sparse arrays as dense.
3506      *
3507      * @private
3508      * @param {Object} object The object to query.
3509      * @returns {Array} Returns the array of property names.
3510      */
3511     function baseKeys(object) {
3512       if (!isPrototype(object)) {
3513         return nativeKeys(object);
3514       }
3515       var result = [];
3516       for (var key in Object(object)) {
3517         if (hasOwnProperty.call(object, key) && key != 'constructor') {
3518           result.push(key);
3519         }
3520       }
3521       return result;
3522     }
3523
3524     /**
3525      * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense.
3526      *
3527      * @private
3528      * @param {Object} object The object to query.
3529      * @returns {Array} Returns the array of property names.
3530      */
3531     function baseKeysIn(object) {
3532       if (!isObject(object)) {
3533         return nativeKeysIn(object);
3534       }
3535       var isProto = isPrototype(object),
3536           result = [];
3537
3538       for (var key in object) {
3539         if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
3540           result.push(key);
3541         }
3542       }
3543       return result;
3544     }
3545
3546     /**
3547      * The base implementation of `_.lt` which doesn't coerce arguments.
3548      *
3549      * @private
3550      * @param {*} value The value to compare.
3551      * @param {*} other The other value to compare.
3552      * @returns {boolean} Returns `true` if `value` is less than `other`,
3553      *  else `false`.
3554      */
3555     function baseLt(value, other) {
3556       return value < other;
3557     }
3558
3559     /**
3560      * The base implementation of `_.map` without support for iteratee shorthands.
3561      *
3562      * @private
3563      * @param {Array|Object} collection The collection to iterate over.
3564      * @param {Function} iteratee The function invoked per iteration.
3565      * @returns {Array} Returns the new mapped array.
3566      */
3567     function baseMap(collection, iteratee) {
3568       var index = -1,
3569           result = isArrayLike(collection) ? Array(collection.length) : [];
3570
3571       baseEach(collection, function(value, key, collection) {
3572         result[++index] = iteratee(value, key, collection);
3573       });
3574       return result;
3575     }
3576
3577     /**
3578      * The base implementation of `_.matches` which doesn't clone `source`.
3579      *
3580      * @private
3581      * @param {Object} source The object of property values to match.
3582      * @returns {Function} Returns the new spec function.
3583      */
3584     function baseMatches(source) {
3585       var matchData = getMatchData(source);
3586       if (matchData.length == 1 && matchData[0][2]) {
3587         return matchesStrictComparable(matchData[0][0], matchData[0][1]);
3588       }
3589       return function(object) {
3590         return object === source || baseIsMatch(object, source, matchData);
3591       };
3592     }
3593
3594     /**
3595      * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
3596      *
3597      * @private
3598      * @param {string} path The path of the property to get.
3599      * @param {*} srcValue The value to match.
3600      * @returns {Function} Returns the new spec function.
3601      */
3602     function baseMatchesProperty(path, srcValue) {
3603       if (isKey(path) && isStrictComparable(srcValue)) {
3604         return matchesStrictComparable(toKey(path), srcValue);
3605       }
3606       return function(object) {
3607         var objValue = get(object, path);
3608         return (objValue === undefined && objValue === srcValue)
3609           ? hasIn(object, path)
3610           : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG);
3611       };
3612     }
3613
3614     /**
3615      * The base implementation of `_.merge` without support for multiple sources.
3616      *
3617      * @private
3618      * @param {Object} object The destination object.
3619      * @param {Object} source The source object.
3620      * @param {number} srcIndex The index of `source`.
3621      * @param {Function} [customizer] The function to customize merged values.
3622      * @param {Object} [stack] Tracks traversed source values and their merged
3623      *  counterparts.
3624      */
3625     function baseMerge(object, source, srcIndex, customizer, stack) {
3626       if (object === source) {
3627         return;
3628       }
3629       baseFor(source, function(srcValue, key) {
3630         if (isObject(srcValue)) {
3631           stack || (stack = new Stack);
3632           baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
3633         }
3634         else {
3635           var newValue = customizer
3636             ? customizer(object[key], srcValue, (key + ''), object, source, stack)
3637             : undefined;
3638
3639           if (newValue === undefined) {
3640             newValue = srcValue;
3641           }
3642           assignMergeValue(object, key, newValue);
3643         }
3644       }, keysIn);
3645     }
3646
3647     /**
3648      * A specialized version of `baseMerge` for arrays and objects which performs
3649      * deep merges and tracks traversed objects enabling objects with circular
3650      * references to be merged.
3651      *
3652      * @private
3653      * @param {Object} object The destination object.
3654      * @param {Object} source The source object.
3655      * @param {string} key The key of the value to merge.
3656      * @param {number} srcIndex The index of `source`.
3657      * @param {Function} mergeFunc The function to merge values.
3658      * @param {Function} [customizer] The function to customize assigned values.
3659      * @param {Object} [stack] Tracks traversed source values and their merged
3660      *  counterparts.
3661      */
3662     function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
3663       var objValue = object[key],
3664           srcValue = source[key],
3665           stacked = stack.get(srcValue);
3666
3667       if (stacked) {
3668         assignMergeValue(object, key, stacked);
3669         return;
3670       }
3671       var newValue = customizer
3672         ? customizer(objValue, srcValue, (key + ''), object, source, stack)
3673         : undefined;
3674
3675       var isCommon = newValue === undefined;
3676
3677       if (isCommon) {
3678         var isArr = isArray(srcValue),
3679             isBuff = !isArr && isBuffer(srcValue),
3680             isTyped = !isArr && !isBuff && isTypedArray(srcValue);
3681
3682         newValue = srcValue;
3683         if (isArr || isBuff || isTyped) {
3684           if (isArray(objValue)) {
3685             newValue = objValue;
3686           }
3687           else if (isArrayLikeObject(objValue)) {
3688             newValue = copyArray(objValue);
3689           }
3690           else if (isBuff) {
3691             isCommon = false;
3692             newValue = cloneBuffer(srcValue, true);
3693           }
3694           else if (isTyped) {
3695             isCommon = false;
3696             newValue = cloneTypedArray(srcValue, true);
3697           }
3698           else {
3699             newValue = [];
3700           }
3701         }
3702         else if (isPlainObject(srcValue) || isArguments(srcValue)) {
3703           newValue = objValue;
3704           if (isArguments(objValue)) {
3705             newValue = toPlainObject(objValue);
3706           }
3707           else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) {
3708             newValue = initCloneObject(srcValue);
3709           }
3710         }
3711         else {
3712           isCommon = false;
3713         }
3714       }
3715       if (isCommon) {
3716         // Recursively merge objects and arrays (susceptible to call stack limits).
3717         stack.set(srcValue, newValue);
3718         mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
3719         stack['delete'](srcValue);
3720       }
3721       assignMergeValue(object, key, newValue);
3722     }
3723
3724     /**
3725      * The base implementation of `_.nth` which doesn't coerce arguments.
3726      *
3727      * @private
3728      * @param {Array} array The array to query.
3729      * @param {number} n The index of the element to return.
3730      * @returns {*} Returns the nth element of `array`.
3731      */
3732     function baseNth(array, n) {
3733       var length = array.length;
3734       if (!length) {
3735         return;
3736       }
3737       n += n < 0 ? length : 0;
3738       return isIndex(n, length) ? array[n] : undefined;
3739     }
3740
3741     /**
3742      * The base implementation of `_.orderBy` without param guards.
3743      *
3744      * @private
3745      * @param {Array|Object} collection The collection to iterate over.
3746      * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
3747      * @param {string[]} orders The sort orders of `iteratees`.
3748      * @returns {Array} Returns the new sorted array.
3749      */
3750     function baseOrderBy(collection, iteratees, orders) {
3751       var index = -1;
3752       iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee()));
3753
3754       var result = baseMap(collection, function(value, key, collection) {
3755         var criteria = arrayMap(iteratees, function(iteratee) {
3756           return iteratee(value);
3757         });
3758         return { 'criteria': criteria, 'index': ++index, 'value': value };
3759       });
3760
3761       return baseSortBy(result, function(object, other) {
3762         return compareMultiple(object, other, orders);
3763       });
3764     }
3765
3766     /**
3767      * The base implementation of `_.pick` without support for individual
3768      * property identifiers.
3769      *
3770      * @private
3771      * @param {Object} object The source object.
3772      * @param {string[]} paths The property paths to pick.
3773      * @returns {Object} Returns the new object.
3774      */
3775     function basePick(object, paths) {
3776       return basePickBy(object, paths, function(value, path) {
3777         return hasIn(object, path);
3778       });
3779     }
3780
3781     /**
3782      * The base implementation of  `_.pickBy` without support for iteratee shorthands.
3783      *
3784      * @private
3785      * @param {Object} object The source object.
3786      * @param {string[]} paths The property paths to pick.
3787      * @param {Function} predicate The function invoked per property.
3788      * @returns {Object} Returns the new object.
3789      */
3790     function basePickBy(object, paths, predicate) {
3791       var index = -1,
3792           length = paths.length,
3793           result = {};
3794
3795       while (++index < length) {
3796         var path = paths[index],
3797             value = baseGet(object, path);
3798
3799         if (predicate(value, path)) {
3800           baseSet(result, castPath(path, object), value);
3801         }
3802       }
3803       return result;
3804     }
3805
3806     /**
3807      * A specialized version of `baseProperty` which supports deep paths.
3808      *
3809      * @private
3810      * @param {Array|string} path The path of the property to get.
3811      * @returns {Function} Returns the new accessor function.
3812      */
3813     function basePropertyDeep(path) {
3814       return function(object) {
3815         return baseGet(object, path);
3816       };
3817     }
3818
3819     /**
3820      * The base implementation of `_.pullAllBy` without support for iteratee
3821      * shorthands.
3822      *
3823      * @private
3824      * @param {Array} array The array to modify.
3825      * @param {Array} values The values to remove.
3826      * @param {Function} [iteratee] The iteratee invoked per element.
3827      * @param {Function} [comparator] The comparator invoked per element.
3828      * @returns {Array} Returns `array`.
3829      */
3830     function basePullAll(array, values, iteratee, comparator) {
3831       var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
3832           index = -1,
3833           length = values.length,
3834           seen = array;
3835
3836       if (array === values) {
3837         values = copyArray(values);
3838       }
3839       if (iteratee) {
3840         seen = arrayMap(array, baseUnary(iteratee));
3841       }
3842       while (++index < length) {
3843         var fromIndex = 0,
3844             value = values[index],
3845             computed = iteratee ? iteratee(value) : value;
3846
3847         while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
3848           if (seen !== array) {
3849             splice.call(seen, fromIndex, 1);
3850           }
3851           splice.call(array, fromIndex, 1);
3852         }
3853       }
3854       return array;
3855     }
3856
3857     /**
3858      * The base implementation of `_.pullAt` without support for individual
3859      * indexes or capturing the removed elements.
3860      *
3861      * @private
3862      * @param {Array} array The array to modify.
3863      * @param {number[]} indexes The indexes of elements to remove.
3864      * @returns {Array} Returns `array`.
3865      */
3866     function basePullAt(array, indexes) {
3867       var length = array ? indexes.length : 0,
3868           lastIndex = length - 1;
3869
3870       while (length--) {
3871         var index = indexes[length];
3872         if (length == lastIndex || index !== previous) {
3873           var previous = index;
3874           if (isIndex(index)) {
3875             splice.call(array, index, 1);
3876           } else {
3877             baseUnset(array, index);
3878           }
3879         }
3880       }
3881       return array;
3882     }
3883
3884     /**
3885      * The base implementation of `_.random` without support for returning
3886      * floating-point numbers.
3887      *
3888      * @private
3889      * @param {number} lower The lower bound.
3890      * @param {number} upper The upper bound.
3891      * @returns {number} Returns the random number.
3892      */
3893     function baseRandom(lower, upper) {
3894       return lower + nativeFloor(nativeRandom() * (upper - lower + 1));
3895     }
3896
3897     /**
3898      * The base implementation of `_.range` and `_.rangeRight` which doesn't
3899      * coerce arguments.
3900      *
3901      * @private
3902      * @param {number} start The start of the range.
3903      * @param {number} end The end of the range.
3904      * @param {number} step The value to increment or decrement by.
3905      * @param {boolean} [fromRight] Specify iterating from right to left.
3906      * @returns {Array} Returns the range of numbers.
3907      */
3908     function baseRange(start, end, step, fromRight) {
3909       var index = -1,
3910           length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
3911           result = Array(length);
3912
3913       while (length--) {
3914         result[fromRight ? length : ++index] = start;
3915         start += step;
3916       }
3917       return result;
3918     }
3919
3920     /**
3921      * The base implementation of `_.repeat` which doesn't coerce arguments.
3922      *
3923      * @private
3924      * @param {string} string The string to repeat.
3925      * @param {number} n The number of times to repeat the string.
3926      * @returns {string} Returns the repeated string.
3927      */
3928     function baseRepeat(string, n) {
3929       var result = '';
3930       if (!string || n < 1 || n > MAX_SAFE_INTEGER) {
3931         return result;
3932       }
3933       // Leverage the exponentiation by squaring algorithm for a faster repeat.
3934       // See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
3935       do {
3936         if (n % 2) {
3937           result += string;
3938         }
3939         n = nativeFloor(n / 2);
3940         if (n) {
3941           string += string;
3942         }
3943       } while (n);
3944
3945       return result;
3946     }
3947
3948     /**
3949      * The base implementation of `_.rest` which doesn't validate or coerce arguments.
3950      *
3951      * @private
3952      * @param {Function} func The function to apply a rest parameter to.
3953      * @param {number} [start=func.length-1] The start position of the rest parameter.
3954      * @returns {Function} Returns the new function.
3955      */
3956     function baseRest(func, start) {
3957       return setToString(overRest(func, start, identity), func + '');
3958     }
3959
3960     /**
3961      * The base implementation of `_.sample`.
3962      *
3963      * @private
3964      * @param {Array|Object} collection The collection to sample.
3965      * @returns {*} Returns the random element.
3966      */
3967     function baseSample(collection) {
3968       return arraySample(values(collection));
3969     }
3970
3971     /**
3972      * The base implementation of `_.sampleSize` without param guards.
3973      *
3974      * @private
3975      * @param {Array|Object} collection The collection to sample.
3976      * @param {number} n The number of elements to sample.
3977      * @returns {Array} Returns the random elements.
3978      */
3979     function baseSampleSize(collection, n) {
3980       var array = values(collection);
3981       return shuffleSelf(array, baseClamp(n, 0, array.length));
3982     }
3983
3984     /**
3985      * The base implementation of `_.set`.
3986      *
3987      * @private
3988      * @param {Object} object The object to modify.
3989      * @param {Array|string} path The path of the property to set.
3990      * @param {*} value The value to set.
3991      * @param {Function} [customizer] The function to customize path creation.
3992      * @returns {Object} Returns `object`.
3993      */
3994     function baseSet(object, path, value, customizer) {
3995       if (!isObject(object)) {
3996         return object;
3997       }
3998       path = castPath(path, object);
3999
4000       var index = -1,
4001           length = path.length,
4002           lastIndex = length - 1,
4003           nested = object;
4004
4005       while (nested != null && ++index < length) {
4006         var key = toKey(path[index]),
4007             newValue = value;
4008
4009         if (index != lastIndex) {
4010           var objValue = nested[key];
4011           newValue = customizer ? customizer(objValue, key, nested) : undefined;
4012           if (newValue === undefined) {
4013             newValue = isObject(objValue)
4014               ? objValue
4015               : (isIndex(path[index + 1]) ? [] : {});
4016           }
4017         }
4018         assignValue(nested, key, newValue);
4019         nested = nested[key];
4020       }
4021       return object;
4022     }
4023
4024     /**
4025      * The base implementation of `setData` without support for hot loop shorting.
4026      *
4027      * @private
4028      * @param {Function} func The function to associate metadata with.
4029      * @param {*} data The metadata.
4030      * @returns {Function} Returns `func`.
4031      */
4032     var baseSetData = !metaMap ? identity : function(func, data) {
4033       metaMap.set(func, data);
4034       return func;
4035     };
4036
4037     /**
4038      * The base implementation of `setToString` without support for hot loop shorting.
4039      *
4040      * @private
4041      * @param {Function} func The function to modify.
4042      * @param {Function} string The `toString` result.
4043      * @returns {Function} Returns `func`.
4044      */
4045     var baseSetToString = !defineProperty ? identity : function(func, string) {
4046       return defineProperty(func, 'toString', {
4047         'configurable': true,
4048         'enumerable': false,
4049         'value': constant(string),
4050         'writable': true
4051       });
4052     };
4053
4054     /**
4055      * The base implementation of `_.shuffle`.
4056      *
4057      * @private
4058      * @param {Array|Object} collection The collection to shuffle.
4059      * @returns {Array} Returns the new shuffled array.
4060      */
4061     function baseShuffle(collection) {
4062       return shuffleSelf(values(collection));
4063     }
4064
4065     /**
4066      * The base implementation of `_.slice` without an iteratee call guard.
4067      *
4068      * @private
4069      * @param {Array} array The array to slice.
4070      * @param {number} [start=0] The start position.
4071      * @param {number} [end=array.length] The end position.
4072      * @returns {Array} Returns the slice of `array`.
4073      */
4074     function baseSlice(array, start, end) {
4075       var index = -1,
4076           length = array.length;
4077
4078       if (start < 0) {
4079         start = -start > length ? 0 : (length + start);
4080       }
4081       end = end > length ? length : end;
4082       if (end < 0) {
4083         end += length;
4084       }
4085       length = start > end ? 0 : ((end - start) >>> 0);
4086       start >>>= 0;
4087
4088       var result = Array(length);
4089       while (++index < length) {
4090         result[index] = array[index + start];
4091       }
4092       return result;
4093     }
4094
4095     /**
4096      * The base implementation of `_.some` without support for iteratee shorthands.
4097      *
4098      * @private
4099      * @param {Array|Object} collection The collection to iterate over.
4100      * @param {Function} predicate The function invoked per iteration.
4101      * @returns {boolean} Returns `true` if any element passes the predicate check,
4102      *  else `false`.
4103      */
4104     function baseSome(collection, predicate) {
4105       var result;
4106
4107       baseEach(collection, function(value, index, collection) {
4108         result = predicate(value, index, collection);
4109         return !result;
4110       });
4111       return !!result;
4112     }
4113
4114     /**
4115      * The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
4116      * performs a binary search of `array` to determine the index at which `value`
4117      * should be inserted into `array` in order to maintain its sort order.
4118      *
4119      * @private
4120      * @param {Array} array The sorted array to inspect.
4121      * @param {*} value The value to evaluate.
4122      * @param {boolean} [retHighest] Specify returning the highest qualified index.
4123      * @returns {number} Returns the index at which `value` should be inserted
4124      *  into `array`.
4125      */
4126     function baseSortedIndex(array, value, retHighest) {
4127       var low = 0,
4128           high = array == null ? low : array.length;
4129
4130       if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
4131         while (low < high) {
4132           var mid = (low + high) >>> 1,
4133               computed = array[mid];
4134
4135           if (computed !== null && !isSymbol(computed) &&
4136               (retHighest ? (computed <= value) : (computed < value))) {
4137             low = mid + 1;
4138           } else {
4139             high = mid;
4140           }
4141         }
4142         return high;
4143       }
4144       return baseSortedIndexBy(array, value, identity, retHighest);
4145     }
4146
4147     /**
4148      * The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
4149      * which invokes `iteratee` for `value` and each element of `array` to compute
4150      * their sort ranking. The iteratee is invoked with one argument; (value).
4151      *
4152      * @private
4153      * @param {Array} array The sorted array to inspect.
4154      * @param {*} value The value to evaluate.
4155      * @param {Function} iteratee The iteratee invoked per element.
4156      * @param {boolean} [retHighest] Specify returning the highest qualified index.
4157      * @returns {number} Returns the index at which `value` should be inserted
4158      *  into `array`.
4159      */
4160     function baseSortedIndexBy(array, value, iteratee, retHighest) {
4161       value = iteratee(value);
4162
4163       var low = 0,
4164           high = array == null ? 0 : array.length,
4165           valIsNaN = value !== value,
4166           valIsNull = value === null,
4167           valIsSymbol = isSymbol(value),
4168           valIsUndefined = value === undefined;
4169
4170       while (low < high) {
4171         var mid = nativeFloor((low + high) / 2),
4172             computed = iteratee(array[mid]),
4173             othIsDefined = computed !== undefined,
4174             othIsNull = computed === null,
4175             othIsReflexive = computed === computed,
4176             othIsSymbol = isSymbol(computed);
4177
4178         if (valIsNaN) {
4179           var setLow = retHighest || othIsReflexive;
4180         } else if (valIsUndefined) {
4181           setLow = othIsReflexive && (retHighest || othIsDefined);
4182         } else if (valIsNull) {
4183           setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
4184         } else if (valIsSymbol) {
4185           setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
4186         } else if (othIsNull || othIsSymbol) {
4187           setLow = false;
4188         } else {
4189           setLow = retHighest ? (computed <= value) : (computed < value);
4190         }
4191         if (setLow) {
4192           low = mid + 1;
4193         } else {
4194           high = mid;
4195         }
4196       }
4197       return nativeMin(high, MAX_ARRAY_INDEX);
4198     }
4199
4200     /**
4201      * The base implementation of `_.sortedUniq` and `_.sortedUniqBy` without
4202      * support for iteratee shorthands.
4203      *
4204      * @private
4205      * @param {Array} array The array to inspect.
4206      * @param {Function} [iteratee] The iteratee invoked per element.
4207      * @returns {Array} Returns the new duplicate free array.
4208      */
4209     function baseSortedUniq(array, iteratee) {
4210       var index = -1,
4211           length = array.length,
4212           resIndex = 0,
4213           result = [];
4214
4215       while (++index < length) {
4216         var value = array[index],
4217             computed = iteratee ? iteratee(value) : value;
4218
4219         if (!index || !eq(computed, seen)) {
4220           var seen = computed;
4221           result[resIndex++] = value === 0 ? 0 : value;
4222         }
4223       }
4224       return result;
4225     }
4226
4227     /**
4228      * The base implementation of `_.toNumber` which doesn't ensure correct
4229      * conversions of binary, hexadecimal, or octal string values.
4230      *
4231      * @private
4232      * @param {*} value The value to process.
4233      * @returns {number} Returns the number.
4234      */
4235     function baseToNumber(value) {
4236       if (typeof value == 'number') {
4237         return value;
4238       }
4239       if (isSymbol(value)) {
4240         return NAN;
4241       }
4242       return +value;
4243     }
4244
4245     /**
4246      * The base implementation of `_.toString` which doesn't convert nullish
4247      * values to empty strings.
4248      *
4249      * @private
4250      * @param {*} value The value to process.
4251      * @returns {string} Returns the string.
4252      */
4253     function baseToString(value) {
4254       // Exit early for strings to avoid a performance hit in some environments.
4255       if (typeof value == 'string') {
4256         return value;
4257       }
4258       if (isArray(value)) {
4259         // Recursively convert values (susceptible to call stack limits).
4260         return arrayMap(value, baseToString) + '';
4261       }
4262       if (isSymbol(value)) {
4263         return symbolToString ? symbolToString.call(value) : '';
4264       }
4265       var result = (value + '');
4266       return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
4267     }
4268
4269     /**
4270      * The base implementation of `_.uniqBy` without support for iteratee shorthands.
4271      *
4272      * @private
4273      * @param {Array} array The array to inspect.
4274      * @param {Function} [iteratee] The iteratee invoked per element.
4275      * @param {Function} [comparator] The comparator invoked per element.
4276      * @returns {Array} Returns the new duplicate free array.
4277      */
4278     function baseUniq(array, iteratee, comparator) {
4279       var index = -1,
4280           includes = arrayIncludes,
4281           length = array.length,
4282           isCommon = true,
4283           result = [],
4284           seen = result;
4285
4286       if (comparator) {
4287         isCommon = false;
4288         includes = arrayIncludesWith;
4289       }
4290       else if (length >= LARGE_ARRAY_SIZE) {
4291         var set = iteratee ? null : createSet(array);
4292         if (set) {
4293           return setToArray(set);
4294         }
4295         isCommon = false;
4296         includes = cacheHas;
4297         seen = new SetCache;
4298       }
4299       else {
4300         seen = iteratee ? [] : result;
4301       }
4302       outer:
4303       while (++index < length) {
4304         var value = array[index],
4305             computed = iteratee ? iteratee(value) : value;
4306
4307         value = (comparator || value !== 0) ? value : 0;
4308         if (isCommon && computed === computed) {
4309           var seenIndex = seen.length;
4310           while (seenIndex--) {
4311             if (seen[seenIndex] === computed) {
4312               continue outer;
4313             }
4314           }
4315           if (iteratee) {
4316             seen.push(computed);
4317           }
4318           result.push(value);
4319         }
4320         else if (!includes(seen, computed, comparator)) {
4321           if (seen !== result) {
4322             seen.push(computed);
4323           }
4324           result.push(value);
4325         }
4326       }
4327       return result;
4328     }
4329
4330     /**
4331      * The base implementation of `_.unset`.
4332      *
4333      * @private
4334      * @param {Object} object The object to modify.
4335      * @param {Array|string} path The property path to unset.
4336      * @returns {boolean} Returns `true` if the property is deleted, else `false`.
4337      */
4338     function baseUnset(object, path) {
4339       path = castPath(path, object);
4340       object = parent(object, path);
4341       return object == null || delete object[toKey(last(path))];
4342     }
4343
4344     /**
4345      * The base implementation of `_.update`.
4346      *
4347      * @private
4348      * @param {Object} object The object to modify.
4349      * @param {Array|string} path The path of the property to update.
4350      * @param {Function} updater The function to produce the updated value.
4351      * @param {Function} [customizer] The function to customize path creation.
4352      * @returns {Object} Returns `object`.
4353      */
4354     function baseUpdate(object, path, updater, customizer) {
4355       return baseSet(object, path, updater(baseGet(object, path)), customizer);
4356     }
4357
4358     /**
4359      * The base implementation of methods like `_.dropWhile` and `_.takeWhile`
4360      * without support for iteratee shorthands.
4361      *
4362      * @private
4363      * @param {Array} array The array to query.
4364      * @param {Function} predicate The function invoked per iteration.
4365      * @param {boolean} [isDrop] Specify dropping elements instead of taking them.
4366      * @param {boolean} [fromRight] Specify iterating from right to left.
4367      * @returns {Array} Returns the slice of `array`.
4368      */
4369     function baseWhile(array, predicate, isDrop, fromRight) {
4370       var length = array.length,
4371           index = fromRight ? length : -1;
4372
4373       while ((fromRight ? index-- : ++index < length) &&
4374         predicate(array[index], index, array)) {}
4375
4376       return isDrop
4377         ? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
4378         : baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));
4379     }
4380
4381     /**
4382      * The base implementation of `wrapperValue` which returns the result of
4383      * performing a sequence of actions on the unwrapped `value`, where each
4384      * successive action is supplied the return value of the previous.
4385      *
4386      * @private
4387      * @param {*} value The unwrapped value.
4388      * @param {Array} actions Actions to perform to resolve the unwrapped value.
4389      * @returns {*} Returns the resolved value.
4390      */
4391     function baseWrapperValue(value, actions) {
4392       var result = value;
4393       if (result instanceof LazyWrapper) {
4394         result = result.value();
4395       }
4396       return arrayReduce(actions, function(result, action) {
4397         return action.func.apply(action.thisArg, arrayPush([result], action.args));
4398       }, result);
4399     }
4400
4401     /**
4402      * The base implementation of methods like `_.xor`, without support for
4403      * iteratee shorthands, that accepts an array of arrays to inspect.
4404      *
4405      * @private
4406      * @param {Array} arrays The arrays to inspect.
4407      * @param {Function} [iteratee] The iteratee invoked per element.
4408      * @param {Function} [comparator] The comparator invoked per element.
4409      * @returns {Array} Returns the new array of values.
4410      */
4411     function baseXor(arrays, iteratee, comparator) {
4412       var length = arrays.length;
4413       if (length < 2) {
4414         return length ? baseUniq(arrays[0]) : [];
4415       }
4416       var index = -1,
4417           result = Array(length);
4418
4419       while (++index < length) {
4420         var array = arrays[index],
4421             othIndex = -1;
4422
4423         while (++othIndex < length) {
4424           if (othIndex != index) {
4425             result[index] = baseDifference(result[index] || array, arrays[othIndex], iteratee, comparator);
4426           }
4427         }
4428       }
4429       return baseUniq(baseFlatten(result, 1), iteratee, comparator);
4430     }
4431
4432     /**
4433      * This base implementation of `_.zipObject` which assigns values using `assignFunc`.
4434      *
4435      * @private
4436      * @param {Array} props The property identifiers.
4437      * @param {Array} values The property values.
4438      * @param {Function} assignFunc The function to assign values.
4439      * @returns {Object} Returns the new object.
4440      */
4441     function baseZipObject(props, values, assignFunc) {
4442       var index = -1,
4443           length = props.length,
4444           valsLength = values.length,
4445           result = {};
4446
4447       while (++index < length) {
4448         var value = index < valsLength ? values[index] : undefined;
4449         assignFunc(result, props[index], value);
4450       }
4451       return result;
4452     }
4453
4454     /**
4455      * Casts `value` to an empty array if it's not an array like object.
4456      *
4457      * @private
4458      * @param {*} value The value to inspect.
4459      * @returns {Array|Object} Returns the cast array-like object.
4460      */
4461     function castArrayLikeObject(value) {
4462       return isArrayLikeObject(value) ? value : [];
4463     }
4464
4465     /**
4466      * Casts `value` to `identity` if it's not a function.
4467      *
4468      * @private
4469      * @param {*} value The value to inspect.
4470      * @returns {Function} Returns cast function.
4471      */
4472     function castFunction(value) {
4473       return typeof value == 'function' ? value : identity;
4474     }
4475
4476     /**
4477      * Casts `value` to a path array if it's not one.
4478      *
4479      * @private
4480      * @param {*} value The value to inspect.
4481      * @param {Object} [object] The object to query keys on.
4482      * @returns {Array} Returns the cast property path array.
4483      */
4484     function castPath(value, object) {
4485       if (isArray(value)) {
4486         return value;
4487       }
4488       return isKey(value, object) ? [value] : stringToPath(toString(value));
4489     }
4490
4491     /**
4492      * A `baseRest` alias which can be replaced with `identity` by module
4493      * replacement plugins.
4494      *
4495      * @private
4496      * @type {Function}
4497      * @param {Function} func The function to apply a rest parameter to.
4498      * @returns {Function} Returns the new function.
4499      */
4500     var castRest = baseRest;
4501
4502     /**
4503      * Casts `array` to a slice if it's needed.
4504      *
4505      * @private
4506      * @param {Array} array The array to inspect.
4507      * @param {number} start The start position.
4508      * @param {number} [end=array.length] The end position.
4509      * @returns {Array} Returns the cast slice.
4510      */
4511     function castSlice(array, start, end) {
4512       var length = array.length;
4513       end = end === undefined ? length : end;
4514       return (!start && end >= length) ? array : baseSlice(array, start, end);
4515     }
4516
4517     /**
4518      * A simple wrapper around the global [`clearTimeout`](https://mdn.io/clearTimeout).
4519      *
4520      * @private
4521      * @param {number|Object} id The timer id or timeout object of the timer to clear.
4522      */
4523     var clearTimeout = ctxClearTimeout || function(id) {
4524       return root.clearTimeout(id);
4525     };
4526
4527     /**
4528      * Creates a clone of  `buffer`.
4529      *
4530      * @private
4531      * @param {Buffer} buffer The buffer to clone.
4532      * @param {boolean} [isDeep] Specify a deep clone.
4533      * @returns {Buffer} Returns the cloned buffer.
4534      */
4535     function cloneBuffer(buffer, isDeep) {
4536       if (isDeep) {
4537         return buffer.slice();
4538       }
4539       var length = buffer.length,
4540           result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length);
4541
4542       buffer.copy(result);
4543       return result;
4544     }
4545
4546     /**
4547      * Creates a clone of `arrayBuffer`.
4548      *
4549      * @private
4550      * @param {ArrayBuffer} arrayBuffer The array buffer to clone.
4551      * @returns {ArrayBuffer} Returns the cloned array buffer.
4552      */
4553     function cloneArrayBuffer(arrayBuffer) {
4554       var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
4555       new Uint8Array(result).set(new Uint8Array(arrayBuffer));
4556       return result;
4557     }
4558
4559     /**
4560      * Creates a clone of `dataView`.
4561      *
4562      * @private
4563      * @param {Object} dataView The data view to clone.
4564      * @param {boolean} [isDeep] Specify a deep clone.
4565      * @returns {Object} Returns the cloned data view.
4566      */
4567     function cloneDataView(dataView, isDeep) {
4568       var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
4569       return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
4570     }
4571
4572     /**
4573      * Creates a clone of `map`.
4574      *
4575      * @private
4576      * @param {Object} map The map to clone.
4577      * @param {Function} cloneFunc The function to clone values.
4578      * @param {boolean} [isDeep] Specify a deep clone.
4579      * @returns {Object} Returns the cloned map.
4580      */
4581     function cloneMap(map, isDeep, cloneFunc) {
4582       var array = isDeep ? cloneFunc(mapToArray(map), CLONE_DEEP_FLAG) : mapToArray(map);
4583       return arrayReduce(array, addMapEntry, new map.constructor);
4584     }
4585
4586     /**
4587      * Creates a clone of `regexp`.
4588      *
4589      * @private
4590      * @param {Object} regexp The regexp to clone.
4591      * @returns {Object} Returns the cloned regexp.
4592      */
4593     function cloneRegExp(regexp) {
4594       var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
4595       result.lastIndex = regexp.lastIndex;
4596       return result;
4597     }
4598
4599     /**
4600      * Creates a clone of `set`.
4601      *
4602      * @private
4603      * @param {Object} set The set to clone.
4604      * @param {Function} cloneFunc The function to clone values.
4605      * @param {boolean} [isDeep] Specify a deep clone.
4606      * @returns {Object} Returns the cloned set.
4607      */
4608     function cloneSet(set, isDeep, cloneFunc) {
4609       var array = isDeep ? cloneFunc(setToArray(set), CLONE_DEEP_FLAG) : setToArray(set);
4610       return arrayReduce(array, addSetEntry, new set.constructor);
4611     }
4612
4613     /**
4614      * Creates a clone of the `symbol` object.
4615      *
4616      * @private
4617      * @param {Object} symbol The symbol object to clone.
4618      * @returns {Object} Returns the cloned symbol object.
4619      */
4620     function cloneSymbol(symbol) {
4621       return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
4622     }
4623
4624     /**
4625      * Creates a clone of `typedArray`.
4626      *
4627      * @private
4628      * @param {Object} typedArray The typed array to clone.
4629      * @param {boolean} [isDeep] Specify a deep clone.
4630      * @returns {Object} Returns the cloned typed array.
4631      */
4632     function cloneTypedArray(typedArray, isDeep) {
4633       var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
4634       return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
4635     }
4636
4637     /**
4638      * Compares values to sort them in ascending order.
4639      *
4640      * @private
4641      * @param {*} value The value to compare.
4642      * @param {*} other The other value to compare.
4643      * @returns {number} Returns the sort order indicator for `value`.
4644      */
4645     function compareAscending(value, other) {
4646       if (value !== other) {
4647         var valIsDefined = value !== undefined,
4648             valIsNull = value === null,
4649             valIsReflexive = value === value,
4650             valIsSymbol = isSymbol(value);
4651
4652         var othIsDefined = other !== undefined,
4653             othIsNull = other === null,
4654             othIsReflexive = other === other,
4655             othIsSymbol = isSymbol(other);
4656
4657         if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
4658             (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
4659             (valIsNull && othIsDefined && othIsReflexive) ||
4660             (!valIsDefined && othIsReflexive) ||
4661             !valIsReflexive) {
4662           return 1;
4663         }
4664         if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
4665             (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
4666             (othIsNull && valIsDefined && valIsReflexive) ||
4667             (!othIsDefined && valIsReflexive) ||
4668             !othIsReflexive) {
4669           return -1;
4670         }
4671       }
4672       return 0;
4673     }
4674
4675     /**
4676      * Used by `_.orderBy` to compare multiple properties of a value to another
4677      * and stable sort them.
4678      *
4679      * If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
4680      * specify an order of "desc" for descending or "asc" for ascending sort order
4681      * of corresponding values.
4682      *
4683      * @private
4684      * @param {Object} object The object to compare.
4685      * @param {Object} other The other object to compare.
4686      * @param {boolean[]|string[]} orders The order to sort by for each property.
4687      * @returns {number} Returns the sort order indicator for `object`.
4688      */
4689     function compareMultiple(object, other, orders) {
4690       var index = -1,
4691           objCriteria = object.criteria,
4692           othCriteria = other.criteria,
4693           length = objCriteria.length,
4694           ordersLength = orders.length;
4695
4696       while (++index < length) {
4697         var result = compareAscending(objCriteria[index], othCriteria[index]);
4698         if (result) {
4699           if (index >= ordersLength) {
4700             return result;
4701           }
4702           var order = orders[index];
4703           return result * (order == 'desc' ? -1 : 1);
4704         }
4705       }
4706       // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
4707       // that causes it, under certain circumstances, to provide the same value for
4708       // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
4709       // for more details.
4710       //
4711       // This also ensures a stable sort in V8 and other engines.
4712       // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
4713       return object.index - other.index;
4714     }
4715
4716     /**
4717      * Creates an array that is the composition of partially applied arguments,
4718      * placeholders, and provided arguments into a single array of arguments.
4719      *
4720      * @private
4721      * @param {Array} args The provided arguments.
4722      * @param {Array} partials The arguments to prepend to those provided.
4723      * @param {Array} holders The `partials` placeholder indexes.
4724      * @params {boolean} [isCurried] Specify composing for a curried function.
4725      * @returns {Array} Returns the new array of composed arguments.
4726      */
4727     function composeArgs(args, partials, holders, isCurried) {
4728       var argsIndex = -1,
4729           argsLength = args.length,
4730           holdersLength = holders.length,
4731           leftIndex = -1,
4732           leftLength = partials.length,
4733           rangeLength = nativeMax(argsLength - holdersLength, 0),
4734           result = Array(leftLength + rangeLength),
4735           isUncurried = !isCurried;
4736
4737       while (++leftIndex < leftLength) {
4738         result[leftIndex] = partials[leftIndex];
4739       }
4740       while (++argsIndex < holdersLength) {
4741         if (isUncurried || argsIndex < argsLength) {
4742           result[holders[argsIndex]] = args[argsIndex];
4743         }
4744       }
4745       while (rangeLength--) {
4746         result[leftIndex++] = args[argsIndex++];
4747       }
4748       return result;
4749     }
4750
4751     /**
4752      * This function is like `composeArgs` except that the arguments composition
4753      * is tailored for `_.partialRight`.
4754      *
4755      * @private
4756      * @param {Array} args The provided arguments.
4757      * @param {Array} partials The arguments to append to those provided.
4758      * @param {Array} holders The `partials` placeholder indexes.
4759      * @params {boolean} [isCurried] Specify composing for a curried function.
4760      * @returns {Array} Returns the new array of composed arguments.
4761      */
4762     function composeArgsRight(args, partials, holders, isCurried) {
4763       var argsIndex = -1,
4764           argsLength = args.length,
4765           holdersIndex = -1,
4766           holdersLength = holders.length,
4767           rightIndex = -1,
4768           rightLength = partials.length,
4769           rangeLength = nativeMax(argsLength - holdersLength, 0),
4770           result = Array(rangeLength + rightLength),
4771           isUncurried = !isCurried;
4772
4773       while (++argsIndex < rangeLength) {
4774         result[argsIndex] = args[argsIndex];
4775       }
4776       var offset = argsIndex;
4777       while (++rightIndex < rightLength) {
4778         result[offset + rightIndex] = partials[rightIndex];
4779       }
4780       while (++holdersIndex < holdersLength) {
4781         if (isUncurried || argsIndex < argsLength) {
4782           result[offset + holders[holdersIndex]] = args[argsIndex++];
4783         }
4784       }
4785       return result;
4786     }
4787
4788     /**
4789      * Copies the values of `source` to `array`.
4790      *
4791      * @private
4792      * @param {Array} source The array to copy values from.
4793      * @param {Array} [array=[]] The array to copy values to.
4794      * @returns {Array} Returns `array`.
4795      */
4796     function copyArray(source, array) {
4797       var index = -1,
4798           length = source.length;
4799
4800       array || (array = Array(length));
4801       while (++index < length) {
4802         array[index] = source[index];
4803       }
4804       return array;
4805     }
4806
4807     /**
4808      * Copies properties of `source` to `object`.
4809      *
4810      * @private
4811      * @param {Object} source The object to copy properties from.
4812      * @param {Array} props The property identifiers to copy.
4813      * @param {Object} [object={}] The object to copy properties to.
4814      * @param {Function} [customizer] The function to customize copied values.
4815      * @returns {Object} Returns `object`.
4816      */
4817     function copyObject(source, props, object, customizer) {
4818       var isNew = !object;
4819       object || (object = {});
4820
4821       var index = -1,
4822           length = props.length;
4823
4824       while (++index < length) {
4825         var key = props[index];
4826
4827         var newValue = customizer
4828           ? customizer(object[key], source[key], key, object, source)
4829           : undefined;
4830
4831         if (newValue === undefined) {
4832           newValue = source[key];
4833         }
4834         if (isNew) {
4835           baseAssignValue(object, key, newValue);
4836         } else {
4837           assignValue(object, key, newValue);
4838         }
4839       }
4840       return object;
4841     }
4842
4843     /**
4844      * Copies own symbols of `source` to `object`.
4845      *
4846      * @private
4847      * @param {Object} source The object to copy symbols from.
4848      * @param {Object} [object={}] The object to copy symbols to.
4849      * @returns {Object} Returns `object`.
4850      */
4851     function copySymbols(source, object) {
4852       return copyObject(source, getSymbols(source), object);
4853     }
4854
4855     /**
4856      * Copies own and inherited symbols of `source` to `object`.
4857      *
4858      * @private
4859      * @param {Object} source The object to copy symbols from.
4860      * @param {Object} [object={}] The object to copy symbols to.
4861      * @returns {Object} Returns `object`.
4862      */
4863     function copySymbolsIn(source, object) {
4864       return copyObject(source, getSymbolsIn(source), object);
4865     }
4866
4867     /**
4868      * Creates a function like `_.groupBy`.
4869      *
4870      * @private
4871      * @param {Function} setter The function to set accumulator values.
4872      * @param {Function} [initializer] The accumulator object initializer.
4873      * @returns {Function} Returns the new aggregator function.
4874      */
4875     function createAggregator(setter, initializer) {
4876       return function(collection, iteratee) {
4877         var func = isArray(collection) ? arrayAggregator : baseAggregator,
4878             accumulator = initializer ? initializer() : {};
4879
4880         return func(collection, setter, getIteratee(iteratee, 2), accumulator);
4881       };
4882     }
4883
4884     /**
4885      * Creates a function like `_.assign`.
4886      *
4887      * @private
4888      * @param {Function} assigner The function to assign values.
4889      * @returns {Function} Returns the new assigner function.
4890      */
4891     function createAssigner(assigner) {
4892       return baseRest(function(object, sources) {
4893         var index = -1,
4894             length = sources.length,
4895             customizer = length > 1 ? sources[length - 1] : undefined,
4896             guard = length > 2 ? sources[2] : undefined;
4897
4898         customizer = (assigner.length > 3 && typeof customizer == 'function')
4899           ? (length--, customizer)
4900           : undefined;
4901
4902         if (guard && isIterateeCall(sources[0], sources[1], guard)) {
4903           customizer = length < 3 ? undefined : customizer;
4904           length = 1;
4905         }
4906         object = Object(object);
4907         while (++index < length) {
4908           var source = sources[index];
4909           if (source) {
4910             assigner(object, source, index, customizer);
4911           }
4912         }
4913         return object;
4914       });
4915     }
4916
4917     /**
4918      * Creates a `baseEach` or `baseEachRight` function.
4919      *
4920      * @private
4921      * @param {Function} eachFunc The function to iterate over a collection.
4922      * @param {boolean} [fromRight] Specify iterating from right to left.
4923      * @returns {Function} Returns the new base function.
4924      */
4925     function createBaseEach(eachFunc, fromRight) {
4926       return function(collection, iteratee) {
4927         if (collection == null) {
4928           return collection;
4929         }
4930         if (!isArrayLike(collection)) {
4931           return eachFunc(collection, iteratee);
4932         }
4933         var length = collection.length,
4934             index = fromRight ? length : -1,
4935             iterable = Object(collection);
4936
4937         while ((fromRight ? index-- : ++index < length)) {
4938           if (iteratee(iterable[index], index, iterable) === false) {
4939             break;
4940           }
4941         }
4942         return collection;
4943       };
4944     }
4945
4946     /**
4947      * Creates a base function for methods like `_.forIn` and `_.forOwn`.
4948      *
4949      * @private
4950      * @param {boolean} [fromRight] Specify iterating from right to left.
4951      * @returns {Function} Returns the new base function.
4952      */
4953     function createBaseFor(fromRight) {
4954       return function(object, iteratee, keysFunc) {
4955         var index = -1,
4956             iterable = Object(object),
4957             props = keysFunc(object),
4958             length = props.length;
4959
4960         while (length--) {
4961           var key = props[fromRight ? length : ++index];
4962           if (iteratee(iterable[key], key, iterable) === false) {
4963             break;
4964           }
4965         }
4966         return object;
4967       };
4968     }
4969
4970     /**
4971      * Creates a function that wraps `func` to invoke it with the optional `this`
4972      * binding of `thisArg`.
4973      *
4974      * @private
4975      * @param {Function} func The function to wrap.
4976      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
4977      * @param {*} [thisArg] The `this` binding of `func`.
4978      * @returns {Function} Returns the new wrapped function.
4979      */
4980     function createBind(func, bitmask, thisArg) {
4981       var isBind = bitmask & WRAP_BIND_FLAG,
4982           Ctor = createCtor(func);
4983
4984       function wrapper() {
4985         var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
4986         return fn.apply(isBind ? thisArg : this, arguments);
4987       }
4988       return wrapper;
4989     }
4990
4991     /**
4992      * Creates a function like `_.lowerFirst`.
4993      *
4994      * @private
4995      * @param {string} methodName The name of the `String` case method to use.
4996      * @returns {Function} Returns the new case function.
4997      */
4998     function createCaseFirst(methodName) {
4999       return function(string) {
5000         string = toString(string);
5001
5002         var strSymbols = hasUnicode(string)
5003           ? stringToArray(string)
5004           : undefined;
5005
5006         var chr = strSymbols
5007           ? strSymbols[0]
5008           : string.charAt(0);
5009
5010         var trailing = strSymbols
5011           ? castSlice(strSymbols, 1).join('')
5012           : string.slice(1);
5013
5014         return chr[methodName]() + trailing;
5015       };
5016     }
5017
5018     /**
5019      * Creates a function like `_.camelCase`.
5020      *
5021      * @private
5022      * @param {Function} callback The function to combine each word.
5023      * @returns {Function} Returns the new compounder function.
5024      */
5025     function createCompounder(callback) {
5026       return function(string) {
5027         return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
5028       };
5029     }
5030
5031     /**
5032      * Creates a function that produces an instance of `Ctor` regardless of
5033      * whether it was invoked as part of a `new` expression or by `call` or `apply`.
5034      *
5035      * @private
5036      * @param {Function} Ctor The constructor to wrap.
5037      * @returns {Function} Returns the new wrapped function.
5038      */
5039     function createCtor(Ctor) {
5040       return function() {
5041         // Use a `switch` statement to work with class constructors. See
5042         // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
5043         // for more details.
5044         var args = arguments;
5045         switch (args.length) {
5046           case 0: return new Ctor;
5047           case 1: return new Ctor(args[0]);
5048           case 2: return new Ctor(args[0], args[1]);
5049           case 3: return new Ctor(args[0], args[1], args[2]);
5050           case 4: return new Ctor(args[0], args[1], args[2], args[3]);
5051           case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
5052           case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
5053           case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
5054         }
5055         var thisBinding = baseCreate(Ctor.prototype),
5056             result = Ctor.apply(thisBinding, args);
5057
5058         // Mimic the constructor's `return` behavior.
5059         // See https://es5.github.io/#x13.2.2 for more details.
5060         return isObject(result) ? result : thisBinding;
5061       };
5062     }
5063
5064     /**
5065      * Creates a function that wraps `func` to enable currying.
5066      *
5067      * @private
5068      * @param {Function} func The function to wrap.
5069      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5070      * @param {number} arity The arity of `func`.
5071      * @returns {Function} Returns the new wrapped function.
5072      */
5073     function createCurry(func, bitmask, arity) {
5074       var Ctor = createCtor(func);
5075
5076       function wrapper() {
5077         var length = arguments.length,
5078             args = Array(length),
5079             index = length,
5080             placeholder = getHolder(wrapper);
5081
5082         while (index--) {
5083           args[index] = arguments[index];
5084         }
5085         var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
5086           ? []
5087           : replaceHolders(args, placeholder);
5088
5089         length -= holders.length;
5090         if (length < arity) {
5091           return createRecurry(
5092             func, bitmask, createHybrid, wrapper.placeholder, undefined,
5093             args, holders, undefined, undefined, arity - length);
5094         }
5095         var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
5096         return apply(fn, this, args);
5097       }
5098       return wrapper;
5099     }
5100
5101     /**
5102      * Creates a `_.find` or `_.findLast` function.
5103      *
5104      * @private
5105      * @param {Function} findIndexFunc The function to find the collection index.
5106      * @returns {Function} Returns the new find function.
5107      */
5108     function createFind(findIndexFunc) {
5109       return function(collection, predicate, fromIndex) {
5110         var iterable = Object(collection);
5111         if (!isArrayLike(collection)) {
5112           var iteratee = getIteratee(predicate, 3);
5113           collection = keys(collection);
5114           predicate = function(key) { return iteratee(iterable[key], key, iterable); };
5115         }
5116         var index = findIndexFunc(collection, predicate, fromIndex);
5117         return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined;
5118       };
5119     }
5120
5121     /**
5122      * Creates a `_.flow` or `_.flowRight` function.
5123      *
5124      * @private
5125      * @param {boolean} [fromRight] Specify iterating from right to left.
5126      * @returns {Function} Returns the new flow function.
5127      */
5128     function createFlow(fromRight) {
5129       return flatRest(function(funcs) {
5130         var length = funcs.length,
5131             index = length,
5132             prereq = LodashWrapper.prototype.thru;
5133
5134         if (fromRight) {
5135           funcs.reverse();
5136         }
5137         while (index--) {
5138           var func = funcs[index];
5139           if (typeof func != 'function') {
5140             throw new TypeError(FUNC_ERROR_TEXT);
5141           }
5142           if (prereq && !wrapper && getFuncName(func) == 'wrapper') {
5143             var wrapper = new LodashWrapper([], true);
5144           }
5145         }
5146         index = wrapper ? index : length;
5147         while (++index < length) {
5148           func = funcs[index];
5149
5150           var funcName = getFuncName(func),
5151               data = funcName == 'wrapper' ? getData(func) : undefined;
5152
5153           if (data && isLaziable(data[0]) &&
5154                 data[1] == (WRAP_ARY_FLAG | WRAP_CURRY_FLAG | WRAP_PARTIAL_FLAG | WRAP_REARG_FLAG) &&
5155                 !data[4].length && data[9] == 1
5156               ) {
5157             wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
5158           } else {
5159             wrapper = (func.length == 1 && isLaziable(func))
5160               ? wrapper[funcName]()
5161               : wrapper.thru(func);
5162           }
5163         }
5164         return function() {
5165           var args = arguments,
5166               value = args[0];
5167
5168           if (wrapper && args.length == 1 && isArray(value)) {
5169             return wrapper.plant(value).value();
5170           }
5171           var index = 0,
5172               result = length ? funcs[index].apply(this, args) : value;
5173
5174           while (++index < length) {
5175             result = funcs[index].call(this, result);
5176           }
5177           return result;
5178         };
5179       });
5180     }
5181
5182     /**
5183      * Creates a function that wraps `func` to invoke it with optional `this`
5184      * binding of `thisArg`, partial application, and currying.
5185      *
5186      * @private
5187      * @param {Function|string} func The function or method name to wrap.
5188      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5189      * @param {*} [thisArg] The `this` binding of `func`.
5190      * @param {Array} [partials] The arguments to prepend to those provided to
5191      *  the new function.
5192      * @param {Array} [holders] The `partials` placeholder indexes.
5193      * @param {Array} [partialsRight] The arguments to append to those provided
5194      *  to the new function.
5195      * @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
5196      * @param {Array} [argPos] The argument positions of the new function.
5197      * @param {number} [ary] The arity cap of `func`.
5198      * @param {number} [arity] The arity of `func`.
5199      * @returns {Function} Returns the new wrapped function.
5200      */
5201     function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
5202       var isAry = bitmask & WRAP_ARY_FLAG,
5203           isBind = bitmask & WRAP_BIND_FLAG,
5204           isBindKey = bitmask & WRAP_BIND_KEY_FLAG,
5205           isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG),
5206           isFlip = bitmask & WRAP_FLIP_FLAG,
5207           Ctor = isBindKey ? undefined : createCtor(func);
5208
5209       function wrapper() {
5210         var length = arguments.length,
5211             args = Array(length),
5212             index = length;
5213
5214         while (index--) {
5215           args[index] = arguments[index];
5216         }
5217         if (isCurried) {
5218           var placeholder = getHolder(wrapper),
5219               holdersCount = countHolders(args, placeholder);
5220         }
5221         if (partials) {
5222           args = composeArgs(args, partials, holders, isCurried);
5223         }
5224         if (partialsRight) {
5225           args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
5226         }
5227         length -= holdersCount;
5228         if (isCurried && length < arity) {
5229           var newHolders = replaceHolders(args, placeholder);
5230           return createRecurry(
5231             func, bitmask, createHybrid, wrapper.placeholder, thisArg,
5232             args, newHolders, argPos, ary, arity - length
5233           );
5234         }
5235         var thisBinding = isBind ? thisArg : this,
5236             fn = isBindKey ? thisBinding[func] : func;
5237
5238         length = args.length;
5239         if (argPos) {
5240           args = reorder(args, argPos);
5241         } else if (isFlip && length > 1) {
5242           args.reverse();
5243         }
5244         if (isAry && ary < length) {
5245           args.length = ary;
5246         }
5247         if (this && this !== root && this instanceof wrapper) {
5248           fn = Ctor || createCtor(fn);
5249         }
5250         return fn.apply(thisBinding, args);
5251       }
5252       return wrapper;
5253     }
5254
5255     /**
5256      * Creates a function like `_.invertBy`.
5257      *
5258      * @private
5259      * @param {Function} setter The function to set accumulator values.
5260      * @param {Function} toIteratee The function to resolve iteratees.
5261      * @returns {Function} Returns the new inverter function.
5262      */
5263     function createInverter(setter, toIteratee) {
5264       return function(object, iteratee) {
5265         return baseInverter(object, setter, toIteratee(iteratee), {});
5266       };
5267     }
5268
5269     /**
5270      * Creates a function that performs a mathematical operation on two values.
5271      *
5272      * @private
5273      * @param {Function} operator The function to perform the operation.
5274      * @param {number} [defaultValue] The value used for `undefined` arguments.
5275      * @returns {Function} Returns the new mathematical operation function.
5276      */
5277     function createMathOperation(operator, defaultValue) {
5278       return function(value, other) {
5279         var result;
5280         if (value === undefined && other === undefined) {
5281           return defaultValue;
5282         }
5283         if (value !== undefined) {
5284           result = value;
5285         }
5286         if (other !== undefined) {
5287           if (result === undefined) {
5288             return other;
5289           }
5290           if (typeof value == 'string' || typeof other == 'string') {
5291             value = baseToString(value);
5292             other = baseToString(other);
5293           } else {
5294             value = baseToNumber(value);
5295             other = baseToNumber(other);
5296           }
5297           result = operator(value, other);
5298         }
5299         return result;
5300       };
5301     }
5302
5303     /**
5304      * Creates a function like `_.over`.
5305      *
5306      * @private
5307      * @param {Function} arrayFunc The function to iterate over iteratees.
5308      * @returns {Function} Returns the new over function.
5309      */
5310     function createOver(arrayFunc) {
5311       return flatRest(function(iteratees) {
5312         iteratees = arrayMap(iteratees, baseUnary(getIteratee()));
5313         return baseRest(function(args) {
5314           var thisArg = this;
5315           return arrayFunc(iteratees, function(iteratee) {
5316             return apply(iteratee, thisArg, args);
5317           });
5318         });
5319       });
5320     }
5321
5322     /**
5323      * Creates the padding for `string` based on `length`. The `chars` string
5324      * is truncated if the number of characters exceeds `length`.
5325      *
5326      * @private
5327      * @param {number} length The padding length.
5328      * @param {string} [chars=' '] The string used as padding.
5329      * @returns {string} Returns the padding for `string`.
5330      */
5331     function createPadding(length, chars) {
5332       chars = chars === undefined ? ' ' : baseToString(chars);
5333
5334       var charsLength = chars.length;
5335       if (charsLength < 2) {
5336         return charsLength ? baseRepeat(chars, length) : chars;
5337       }
5338       var result = baseRepeat(chars, nativeCeil(length / stringSize(chars)));
5339       return hasUnicode(chars)
5340         ? castSlice(stringToArray(result), 0, length).join('')
5341         : result.slice(0, length);
5342     }
5343
5344     /**
5345      * Creates a function that wraps `func` to invoke it with the `this` binding
5346      * of `thisArg` and `partials` prepended to the arguments it receives.
5347      *
5348      * @private
5349      * @param {Function} func The function to wrap.
5350      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5351      * @param {*} thisArg The `this` binding of `func`.
5352      * @param {Array} partials The arguments to prepend to those provided to
5353      *  the new function.
5354      * @returns {Function} Returns the new wrapped function.
5355      */
5356     function createPartial(func, bitmask, thisArg, partials) {
5357       var isBind = bitmask & WRAP_BIND_FLAG,
5358           Ctor = createCtor(func);
5359
5360       function wrapper() {
5361         var argsIndex = -1,
5362             argsLength = arguments.length,
5363             leftIndex = -1,
5364             leftLength = partials.length,
5365             args = Array(leftLength + argsLength),
5366             fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
5367
5368         while (++leftIndex < leftLength) {
5369           args[leftIndex] = partials[leftIndex];
5370         }
5371         while (argsLength--) {
5372           args[leftIndex++] = arguments[++argsIndex];
5373         }
5374         return apply(fn, isBind ? thisArg : this, args);
5375       }
5376       return wrapper;
5377     }
5378
5379     /**
5380      * Creates a `_.range` or `_.rangeRight` function.
5381      *
5382      * @private
5383      * @param {boolean} [fromRight] Specify iterating from right to left.
5384      * @returns {Function} Returns the new range function.
5385      */
5386     function createRange(fromRight) {
5387       return function(start, end, step) {
5388         if (step && typeof step != 'number' && isIterateeCall(start, end, step)) {
5389           end = step = undefined;
5390         }
5391         // Ensure the sign of `-0` is preserved.
5392         start = toFinite(start);
5393         if (end === undefined) {
5394           end = start;
5395           start = 0;
5396         } else {
5397           end = toFinite(end);
5398         }
5399         step = step === undefined ? (start < end ? 1 : -1) : toFinite(step);
5400         return baseRange(start, end, step, fromRight);
5401       };
5402     }
5403
5404     /**
5405      * Creates a function that performs a relational operation on two values.
5406      *
5407      * @private
5408      * @param {Function} operator The function to perform the operation.
5409      * @returns {Function} Returns the new relational operation function.
5410      */
5411     function createRelationalOperation(operator) {
5412       return function(value, other) {
5413         if (!(typeof value == 'string' && typeof other == 'string')) {
5414           value = toNumber(value);
5415           other = toNumber(other);
5416         }
5417         return operator(value, other);
5418       };
5419     }
5420
5421     /**
5422      * Creates a function that wraps `func` to continue currying.
5423      *
5424      * @private
5425      * @param {Function} func The function to wrap.
5426      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
5427      * @param {Function} wrapFunc The function to create the `func` wrapper.
5428      * @param {*} placeholder The placeholder value.
5429      * @param {*} [thisArg] The `this` binding of `func`.
5430      * @param {Array} [partials] The arguments to prepend to those provided to
5431      *  the new function.
5432      * @param {Array} [holders] The `partials` placeholder indexes.
5433      * @param {Array} [argPos] The argument positions of the new function.
5434      * @param {number} [ary] The arity cap of `func`.
5435      * @param {number} [arity] The arity of `func`.
5436      * @returns {Function} Returns the new wrapped function.
5437      */
5438     function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
5439       var isCurry = bitmask & WRAP_CURRY_FLAG,
5440           newHolders = isCurry ? holders : undefined,
5441           newHoldersRight = isCurry ? undefined : holders,
5442           newPartials = isCurry ? partials : undefined,
5443           newPartialsRight = isCurry ? undefined : partials;
5444
5445       bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG);
5446       bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG);
5447
5448       if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) {
5449         bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG);
5450       }
5451       var newData = [
5452         func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
5453         newHoldersRight, argPos, ary, arity
5454       ];
5455
5456       var result = wrapFunc.apply(undefined, newData);
5457       if (isLaziable(func)) {
5458         setData(result, newData);
5459       }
5460       result.placeholder = placeholder;
5461       return setWrapToString(result, func, bitmask);
5462     }
5463
5464     /**
5465      * Creates a function like `_.round`.
5466      *
5467      * @private
5468      * @param {string} methodName The name of the `Math` method to use when rounding.
5469      * @returns {Function} Returns the new round function.
5470      */
5471     function createRound(methodName) {
5472       var func = Math[methodName];
5473       return function(number, precision) {
5474         number = toNumber(number);
5475         precision = precision == null ? 0 : nativeMin(toInteger(precision), 292);
5476         if (precision) {
5477           // Shift with exponential notation to avoid floating-point issues.
5478           // See [MDN](https://mdn.io/round#Examples) for more details.
5479           var pair = (toString(number) + 'e').split('e'),
5480               value = func(pair[0] + 'e' + (+pair[1] + precision));
5481
5482           pair = (toString(value) + 'e').split('e');
5483           return +(pair[0] + 'e' + (+pair[1] - precision));
5484         }
5485         return func(number);
5486       };
5487     }
5488
5489     /**
5490      * Creates a set object of `values`.
5491      *
5492      * @private
5493      * @param {Array} values The values to add to the set.
5494      * @returns {Object} Returns the new set.
5495      */
5496     var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) {
5497       return new Set(values);
5498     };
5499
5500     /**
5501      * Creates a `_.toPairs` or `_.toPairsIn` function.
5502      *
5503      * @private
5504      * @param {Function} keysFunc The function to get the keys of a given object.
5505      * @returns {Function} Returns the new pairs function.
5506      */
5507     function createToPairs(keysFunc) {
5508       return function(object) {
5509         var tag = getTag(object);
5510         if (tag == mapTag) {
5511           return mapToArray(object);
5512         }
5513         if (tag == setTag) {
5514           return setToPairs(object);
5515         }
5516         return baseToPairs(object, keysFunc(object));
5517       };
5518     }
5519
5520     /**
5521      * Creates a function that either curries or invokes `func` with optional
5522      * `this` binding and partially applied arguments.
5523      *
5524      * @private
5525      * @param {Function|string} func The function or method name to wrap.
5526      * @param {number} bitmask The bitmask flags.
5527      *    1 - `_.bind`
5528      *    2 - `_.bindKey`
5529      *    4 - `_.curry` or `_.curryRight` of a bound function
5530      *    8 - `_.curry`
5531      *   16 - `_.curryRight`
5532      *   32 - `_.partial`
5533      *   64 - `_.partialRight`
5534      *  128 - `_.rearg`
5535      *  256 - `_.ary`
5536      *  512 - `_.flip`
5537      * @param {*} [thisArg] The `this` binding of `func`.
5538      * @param {Array} [partials] The arguments to be partially applied.
5539      * @param {Array} [holders] The `partials` placeholder indexes.
5540      * @param {Array} [argPos] The argument positions of the new function.
5541      * @param {number} [ary] The arity cap of `func`.
5542      * @param {number} [arity] The arity of `func`.
5543      * @returns {Function} Returns the new wrapped function.
5544      */
5545     function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
5546       var isBindKey = bitmask & WRAP_BIND_KEY_FLAG;
5547       if (!isBindKey && typeof func != 'function') {
5548         throw new TypeError(FUNC_ERROR_TEXT);
5549       }
5550       var length = partials ? partials.length : 0;
5551       if (!length) {
5552         bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG);
5553         partials = holders = undefined;
5554       }
5555       ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
5556       arity = arity === undefined ? arity : toInteger(arity);
5557       length -= holders ? holders.length : 0;
5558
5559       if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) {
5560         var partialsRight = partials,
5561             holdersRight = holders;
5562
5563         partials = holders = undefined;
5564       }
5565       var data = isBindKey ? undefined : getData(func);
5566
5567       var newData = [
5568         func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
5569         argPos, ary, arity
5570       ];
5571
5572       if (data) {
5573         mergeData(newData, data);
5574       }
5575       func = newData[0];
5576       bitmask = newData[1];
5577       thisArg = newData[2];
5578       partials = newData[3];
5579       holders = newData[4];
5580       arity = newData[9] = newData[9] === undefined
5581         ? (isBindKey ? 0 : func.length)
5582         : nativeMax(newData[9] - length, 0);
5583
5584       if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) {
5585         bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG);
5586       }
5587       if (!bitmask || bitmask == WRAP_BIND_FLAG) {
5588         var result = createBind(func, bitmask, thisArg);
5589       } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) {
5590         result = createCurry(func, bitmask, arity);
5591       } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) {
5592         result = createPartial(func, bitmask, thisArg, partials);
5593       } else {
5594         result = createHybrid.apply(undefined, newData);
5595       }
5596       var setter = data ? baseSetData : setData;
5597       return setWrapToString(setter(result, newData), func, bitmask);
5598     }
5599
5600     /**
5601      * Used by `_.defaults` to customize its `_.assignIn` use to assign properties
5602      * of source objects to the destination object for all destination properties
5603      * that resolve to `undefined`.
5604      *
5605      * @private
5606      * @param {*} objValue The destination value.
5607      * @param {*} srcValue The source value.
5608      * @param {string} key The key of the property to assign.
5609      * @param {Object} object The parent object of `objValue`.
5610      * @returns {*} Returns the value to assign.
5611      */
5612     function customDefaultsAssignIn(objValue, srcValue, key, object) {
5613       if (objValue === undefined ||
5614           (eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) {
5615         return srcValue;
5616       }
5617       return objValue;
5618     }
5619
5620     /**
5621      * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source
5622      * objects into destination objects that are passed thru.
5623      *
5624      * @private
5625      * @param {*} objValue The destination value.
5626      * @param {*} srcValue The source value.
5627      * @param {string} key The key of the property to merge.
5628      * @param {Object} object The parent object of `objValue`.
5629      * @param {Object} source The parent object of `srcValue`.
5630      * @param {Object} [stack] Tracks traversed source values and their merged
5631      *  counterparts.
5632      * @returns {*} Returns the value to assign.
5633      */
5634     function customDefaultsMerge(objValue, srcValue, key, object, source, stack) {
5635       if (isObject(objValue) && isObject(srcValue)) {
5636         // Recursively merge objects and arrays (susceptible to call stack limits).
5637         stack.set(srcValue, objValue);
5638         baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack);
5639         stack['delete'](srcValue);
5640       }
5641       return objValue;
5642     }
5643
5644     /**
5645      * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain
5646      * objects.
5647      *
5648      * @private
5649      * @param {*} value The value to inspect.
5650      * @param {string} key The key of the property to inspect.
5651      * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`.
5652      */
5653     function customOmitClone(value) {
5654       return isPlainObject(value) ? undefined : value;
5655     }
5656
5657     /**
5658      * A specialized version of `baseIsEqualDeep` for arrays with support for
5659      * partial deep comparisons.
5660      *
5661      * @private
5662      * @param {Array} array The array to compare.
5663      * @param {Array} other The other array to compare.
5664      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
5665      * @param {Function} customizer The function to customize comparisons.
5666      * @param {Function} equalFunc The function to determine equivalents of values.
5667      * @param {Object} stack Tracks traversed `array` and `other` objects.
5668      * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
5669      */
5670     function equalArrays(array, other, bitmask, customizer, equalFunc, stack) {
5671       var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
5672           arrLength = array.length,
5673           othLength = other.length;
5674
5675       if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
5676         return false;
5677       }
5678       // Assume cyclic values are equal.
5679       var stacked = stack.get(array);
5680       if (stacked && stack.get(other)) {
5681         return stacked == other;
5682       }
5683       var index = -1,
5684           result = true,
5685           seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined;
5686
5687       stack.set(array, other);
5688       stack.set(other, array);
5689
5690       // Ignore non-index properties.
5691       while (++index < arrLength) {
5692         var arrValue = array[index],
5693             othValue = other[index];
5694
5695         if (customizer) {
5696           var compared = isPartial
5697             ? customizer(othValue, arrValue, index, other, array, stack)
5698             : customizer(arrValue, othValue, index, array, other, stack);
5699         }
5700         if (compared !== undefined) {
5701           if (compared) {
5702             continue;
5703           }
5704           result = false;
5705           break;
5706         }
5707         // Recursively compare arrays (susceptible to call stack limits).
5708         if (seen) {
5709           if (!arraySome(other, function(othValue, othIndex) {
5710                 if (!cacheHas(seen, othIndex) &&
5711                     (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) {
5712                   return seen.push(othIndex);
5713                 }
5714               })) {
5715             result = false;
5716             break;
5717           }
5718         } else if (!(
5719               arrValue === othValue ||
5720                 equalFunc(arrValue, othValue, bitmask, customizer, stack)
5721             )) {
5722           result = false;
5723           break;
5724         }
5725       }
5726       stack['delete'](array);
5727       stack['delete'](other);
5728       return result;
5729     }
5730
5731     /**
5732      * A specialized version of `baseIsEqualDeep` for comparing objects of
5733      * the same `toStringTag`.
5734      *
5735      * **Note:** This function only supports comparing values with tags of
5736      * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
5737      *
5738      * @private
5739      * @param {Object} object The object to compare.
5740      * @param {Object} other The other object to compare.
5741      * @param {string} tag The `toStringTag` of the objects to compare.
5742      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
5743      * @param {Function} customizer The function to customize comparisons.
5744      * @param {Function} equalFunc The function to determine equivalents of values.
5745      * @param {Object} stack Tracks traversed `object` and `other` objects.
5746      * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
5747      */
5748     function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) {
5749       switch (tag) {
5750         case dataViewTag:
5751           if ((object.byteLength != other.byteLength) ||
5752               (object.byteOffset != other.byteOffset)) {
5753             return false;
5754           }
5755           object = object.buffer;
5756           other = other.buffer;
5757
5758         case arrayBufferTag:
5759           if ((object.byteLength != other.byteLength) ||
5760               !equalFunc(new Uint8Array(object), new Uint8Array(other))) {
5761             return false;
5762           }
5763           return true;
5764
5765         case boolTag:
5766         case dateTag:
5767         case numberTag:
5768           // Coerce booleans to `1` or `0` and dates to milliseconds.
5769           // Invalid dates are coerced to `NaN`.
5770           return eq(+object, +other);
5771
5772         case errorTag:
5773           return object.name == other.name && object.message == other.message;
5774
5775         case regexpTag:
5776         case stringTag:
5777           // Coerce regexes to strings and treat strings, primitives and objects,
5778           // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring
5779           // for more details.
5780           return object == (other + '');
5781
5782         case mapTag:
5783           var convert = mapToArray;
5784
5785         case setTag:
5786           var isPartial = bitmask & COMPARE_PARTIAL_FLAG;
5787           convert || (convert = setToArray);
5788
5789           if (object.size != other.size && !isPartial) {
5790             return false;
5791           }
5792           // Assume cyclic values are equal.
5793           var stacked = stack.get(object);
5794           if (stacked) {
5795             return stacked == other;
5796           }
5797           bitmask |= COMPARE_UNORDERED_FLAG;
5798
5799           // Recursively compare objects (susceptible to call stack limits).
5800           stack.set(object, other);
5801           var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack);
5802           stack['delete'](object);
5803           return result;
5804
5805         case symbolTag:
5806           if (symbolValueOf) {
5807             return symbolValueOf.call(object) == symbolValueOf.call(other);
5808           }
5809       }
5810       return false;
5811     }
5812
5813     /**
5814      * A specialized version of `baseIsEqualDeep` for objects with support for
5815      * partial deep comparisons.
5816      *
5817      * @private
5818      * @param {Object} object The object to compare.
5819      * @param {Object} other The other object to compare.
5820      * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details.
5821      * @param {Function} customizer The function to customize comparisons.
5822      * @param {Function} equalFunc The function to determine equivalents of values.
5823      * @param {Object} stack Tracks traversed `object` and `other` objects.
5824      * @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
5825      */
5826     function equalObjects(object, other, bitmask, customizer, equalFunc, stack) {
5827       var isPartial = bitmask & COMPARE_PARTIAL_FLAG,
5828           objProps = getAllKeys(object),
5829           objLength = objProps.length,
5830           othProps = getAllKeys(other),
5831           othLength = othProps.length;
5832
5833       if (objLength != othLength && !isPartial) {
5834         return false;
5835       }
5836       var index = objLength;
5837       while (index--) {
5838         var key = objProps[index];
5839         if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) {
5840           return false;
5841         }
5842       }
5843       // Assume cyclic values are equal.
5844       var stacked = stack.get(object);
5845       if (stacked && stack.get(other)) {
5846         return stacked == other;
5847       }
5848       var result = true;
5849       stack.set(object, other);
5850       stack.set(other, object);
5851
5852       var skipCtor = isPartial;
5853       while (++index < objLength) {
5854         key = objProps[index];
5855         var objValue = object[key],
5856             othValue = other[key];
5857
5858         if (customizer) {
5859           var compared = isPartial
5860             ? customizer(othValue, objValue, key, other, object, stack)
5861             : customizer(objValue, othValue, key, object, other, stack);
5862         }
5863         // Recursively compare objects (susceptible to call stack limits).
5864         if (!(compared === undefined
5865               ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack))
5866               : compared
5867             )) {
5868           result = false;
5869           break;
5870         }
5871         skipCtor || (skipCtor = key == 'constructor');
5872       }
5873       if (result && !skipCtor) {
5874         var objCtor = object.constructor,
5875             othCtor = other.constructor;
5876
5877         // Non `Object` object instances with different constructors are not equal.
5878         if (objCtor != othCtor &&
5879             ('constructor' in object && 'constructor' in other) &&
5880             !(typeof objCtor == 'function' && objCtor instanceof objCtor &&
5881               typeof othCtor == 'function' && othCtor instanceof othCtor)) {
5882           result = false;
5883         }
5884       }
5885       stack['delete'](object);
5886       stack['delete'](other);
5887       return result;
5888     }
5889
5890     /**
5891      * A specialized version of `baseRest` which flattens the rest array.
5892      *
5893      * @private
5894      * @param {Function} func The function to apply a rest parameter to.
5895      * @returns {Function} Returns the new function.
5896      */
5897     function flatRest(func) {
5898       return setToString(overRest(func, undefined, flatten), func + '');
5899     }
5900
5901     /**
5902      * Creates an array of own enumerable property names and symbols of `object`.
5903      *
5904      * @private
5905      * @param {Object} object The object to query.
5906      * @returns {Array} Returns the array of property names and symbols.
5907      */
5908     function getAllKeys(object) {
5909       return baseGetAllKeys(object, keys, getSymbols);
5910     }
5911
5912     /**
5913      * Creates an array of own and inherited enumerable property names and
5914      * symbols of `object`.
5915      *
5916      * @private
5917      * @param {Object} object The object to query.
5918      * @returns {Array} Returns the array of property names and symbols.
5919      */
5920     function getAllKeysIn(object) {
5921       return baseGetAllKeys(object, keysIn, getSymbolsIn);
5922     }
5923
5924     /**
5925      * Gets metadata for `func`.
5926      *
5927      * @private
5928      * @param {Function} func The function to query.
5929      * @returns {*} Returns the metadata for `func`.
5930      */
5931     var getData = !metaMap ? noop : function(func) {
5932       return metaMap.get(func);
5933     };
5934
5935     /**
5936      * Gets the name of `func`.
5937      *
5938      * @private
5939      * @param {Function} func The function to query.
5940      * @returns {string} Returns the function name.
5941      */
5942     function getFuncName(func) {
5943       var result = (func.name + ''),
5944           array = realNames[result],
5945           length = hasOwnProperty.call(realNames, result) ? array.length : 0;
5946
5947       while (length--) {
5948         var data = array[length],
5949             otherFunc = data.func;
5950         if (otherFunc == null || otherFunc == func) {
5951           return data.name;
5952         }
5953       }
5954       return result;
5955     }
5956
5957     /**
5958      * Gets the argument placeholder value for `func`.
5959      *
5960      * @private
5961      * @param {Function} func The function to inspect.
5962      * @returns {*} Returns the placeholder value.
5963      */
5964     function getHolder(func) {
5965       var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
5966       return object.placeholder;
5967     }
5968
5969     /**
5970      * Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
5971      * this function returns the custom method, otherwise it returns `baseIteratee`.
5972      * If arguments are provided, the chosen function is invoked with them and
5973      * its result is returned.
5974      *
5975      * @private
5976      * @param {*} [value] The value to convert to an iteratee.
5977      * @param {number} [arity] The arity of the created iteratee.
5978      * @returns {Function} Returns the chosen function or its result.
5979      */
5980     function getIteratee() {
5981       var result = lodash.iteratee || iteratee;
5982       result = result === iteratee ? baseIteratee : result;
5983       return arguments.length ? result(arguments[0], arguments[1]) : result;
5984     }
5985
5986     /**
5987      * Gets the data for `map`.
5988      *
5989      * @private
5990      * @param {Object} map The map to query.
5991      * @param {string} key The reference key.
5992      * @returns {*} Returns the map data.
5993      */
5994     function getMapData(map, key) {
5995       var data = map.__data__;
5996       return isKeyable(key)
5997         ? data[typeof key == 'string' ? 'string' : 'hash']
5998         : data.map;
5999     }
6000
6001     /**
6002      * Gets the property names, values, and compare flags of `object`.
6003      *
6004      * @private
6005      * @param {Object} object The object to query.
6006      * @returns {Array} Returns the match data of `object`.
6007      */
6008     function getMatchData(object) {
6009       var result = keys(object),
6010           length = result.length;
6011
6012       while (length--) {
6013         var key = result[length],
6014             value = object[key];
6015
6016         result[length] = [key, value, isStrictComparable(value)];
6017       }
6018       return result;
6019     }
6020
6021     /**
6022      * Gets the native function at `key` of `object`.
6023      *
6024      * @private
6025      * @param {Object} object The object to query.
6026      * @param {string} key The key of the method to get.
6027      * @returns {*} Returns the function if it's native, else `undefined`.
6028      */
6029     function getNative(object, key) {
6030       var value = getValue(object, key);
6031       return baseIsNative(value) ? value : undefined;
6032     }
6033
6034     /**
6035      * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
6036      *
6037      * @private
6038      * @param {*} value The value to query.
6039      * @returns {string} Returns the raw `toStringTag`.
6040      */
6041     function getRawTag(value) {
6042       var isOwn = hasOwnProperty.call(value, symToStringTag),
6043           tag = value[symToStringTag];
6044
6045       try {
6046         value[symToStringTag] = undefined;
6047         var unmasked = true;
6048       } catch (e) {}
6049
6050       var result = nativeObjectToString.call(value);
6051       if (unmasked) {
6052         if (isOwn) {
6053           value[symToStringTag] = tag;
6054         } else {
6055           delete value[symToStringTag];
6056         }
6057       }
6058       return result;
6059     }
6060
6061     /**
6062      * Creates an array of the own enumerable symbols of `object`.
6063      *
6064      * @private
6065      * @param {Object} object The object to query.
6066      * @returns {Array} Returns the array of symbols.
6067      */
6068     var getSymbols = !nativeGetSymbols ? stubArray : function(object) {
6069       if (object == null) {
6070         return [];
6071       }
6072       object = Object(object);
6073       return arrayFilter(nativeGetSymbols(object), function(symbol) {
6074         return propertyIsEnumerable.call(object, symbol);
6075       });
6076     };
6077
6078     /**
6079      * Creates an array of the own and inherited enumerable symbols of `object`.
6080      *
6081      * @private
6082      * @param {Object} object The object to query.
6083      * @returns {Array} Returns the array of symbols.
6084      */
6085     var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) {
6086       var result = [];
6087       while (object) {
6088         arrayPush(result, getSymbols(object));
6089         object = getPrototype(object);
6090       }
6091       return result;
6092     };
6093
6094     /**
6095      * Gets the `toStringTag` of `value`.
6096      *
6097      * @private
6098      * @param {*} value The value to query.
6099      * @returns {string} Returns the `toStringTag`.
6100      */
6101     var getTag = baseGetTag;
6102
6103     // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6.
6104     if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
6105         (Map && getTag(new Map) != mapTag) ||
6106         (Promise && getTag(Promise.resolve()) != promiseTag) ||
6107         (Set && getTag(new Set) != setTag) ||
6108         (WeakMap && getTag(new WeakMap) != weakMapTag)) {
6109       getTag = function(value) {
6110         var result = baseGetTag(value),
6111             Ctor = result == objectTag ? value.constructor : undefined,
6112             ctorString = Ctor ? toSource(Ctor) : '';
6113
6114         if (ctorString) {
6115           switch (ctorString) {
6116             case dataViewCtorString: return dataViewTag;
6117             case mapCtorString: return mapTag;
6118             case promiseCtorString: return promiseTag;
6119             case setCtorString: return setTag;
6120             case weakMapCtorString: return weakMapTag;
6121           }
6122         }
6123         return result;
6124       };
6125     }
6126
6127     /**
6128      * Gets the view, applying any `transforms` to the `start` and `end` positions.
6129      *
6130      * @private
6131      * @param {number} start The start of the view.
6132      * @param {number} end The end of the view.
6133      * @param {Array} transforms The transformations to apply to the view.
6134      * @returns {Object} Returns an object containing the `start` and `end`
6135      *  positions of the view.
6136      */
6137     function getView(start, end, transforms) {
6138       var index = -1,
6139           length = transforms.length;
6140
6141       while (++index < length) {
6142         var data = transforms[index],
6143             size = data.size;
6144
6145         switch (data.type) {
6146           case 'drop':      start += size; break;
6147           case 'dropRight': end -= size; break;
6148           case 'take':      end = nativeMin(end, start + size); break;
6149           case 'takeRight': start = nativeMax(start, end - size); break;
6150         }
6151       }
6152       return { 'start': start, 'end': end };
6153     }
6154
6155     /**
6156      * Extracts wrapper details from the `source` body comment.
6157      *
6158      * @private
6159      * @param {string} source The source to inspect.
6160      * @returns {Array} Returns the wrapper details.
6161      */
6162     function getWrapDetails(source) {
6163       var match = source.match(reWrapDetails);
6164       return match ? match[1].split(reSplitDetails) : [];
6165     }
6166
6167     /**
6168      * Checks if `path` exists on `object`.
6169      *
6170      * @private
6171      * @param {Object} object The object to query.
6172      * @param {Array|string} path The path to check.
6173      * @param {Function} hasFunc The function to check properties.
6174      * @returns {boolean} Returns `true` if `path` exists, else `false`.
6175      */
6176     function hasPath(object, path, hasFunc) {
6177       path = castPath(path, object);
6178
6179       var index = -1,
6180           length = path.length,
6181           result = false;
6182
6183       while (++index < length) {
6184         var key = toKey(path[index]);
6185         if (!(result = object != null && hasFunc(object, key))) {
6186           break;
6187         }
6188         object = object[key];
6189       }
6190       if (result || ++index != length) {
6191         return result;
6192       }
6193       length = object == null ? 0 : object.length;
6194       return !!length && isLength(length) && isIndex(key, length) &&
6195         (isArray(object) || isArguments(object));
6196     }
6197
6198     /**
6199      * Initializes an array clone.
6200      *
6201      * @private
6202      * @param {Array} array The array to clone.
6203      * @returns {Array} Returns the initialized clone.
6204      */
6205     function initCloneArray(array) {
6206       var length = array.length,
6207           result = array.constructor(length);
6208
6209       // Add properties assigned by `RegExp#exec`.
6210       if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
6211         result.index = array.index;
6212         result.input = array.input;
6213       }
6214       return result;
6215     }
6216
6217     /**
6218      * Initializes an object clone.
6219      *
6220      * @private
6221      * @param {Object} object The object to clone.
6222      * @returns {Object} Returns the initialized clone.
6223      */
6224     function initCloneObject(object) {
6225       return (typeof object.constructor == 'function' && !isPrototype(object))
6226         ? baseCreate(getPrototype(object))
6227         : {};
6228     }
6229
6230     /**
6231      * Initializes an object clone based on its `toStringTag`.
6232      *
6233      * **Note:** This function only supports cloning values with tags of
6234      * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
6235      *
6236      * @private
6237      * @param {Object} object The object to clone.
6238      * @param {string} tag The `toStringTag` of the object to clone.
6239      * @param {Function} cloneFunc The function to clone values.
6240      * @param {boolean} [isDeep] Specify a deep clone.
6241      * @returns {Object} Returns the initialized clone.
6242      */
6243     function initCloneByTag(object, tag, cloneFunc, isDeep) {
6244       var Ctor = object.constructor;
6245       switch (tag) {
6246         case arrayBufferTag:
6247           return cloneArrayBuffer(object);
6248
6249         case boolTag:
6250         case dateTag:
6251           return new Ctor(+object);
6252
6253         case dataViewTag:
6254           return cloneDataView(object, isDeep);
6255
6256         case float32Tag: case float64Tag:
6257         case int8Tag: case int16Tag: case int32Tag:
6258         case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
6259           return cloneTypedArray(object, isDeep);
6260
6261         case mapTag:
6262           return cloneMap(object, isDeep, cloneFunc);
6263
6264         case numberTag:
6265         case stringTag:
6266           return new Ctor(object);
6267
6268         case regexpTag:
6269           return cloneRegExp(object);
6270
6271         case setTag:
6272           return cloneSet(object, isDeep, cloneFunc);
6273
6274         case symbolTag:
6275           return cloneSymbol(object);
6276       }
6277     }
6278
6279     /**
6280      * Inserts wrapper `details` in a comment at the top of the `source` body.
6281      *
6282      * @private
6283      * @param {string} source The source to modify.
6284      * @returns {Array} details The details to insert.
6285      * @returns {string} Returns the modified source.
6286      */
6287     function insertWrapDetails(source, details) {
6288       var length = details.length;
6289       if (!length) {
6290         return source;
6291       }
6292       var lastIndex = length - 1;
6293       details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex];
6294       details = details.join(length > 2 ? ', ' : ' ');
6295       return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n');
6296     }
6297
6298     /**
6299      * Checks if `value` is a flattenable `arguments` object or array.
6300      *
6301      * @private
6302      * @param {*} value The value to check.
6303      * @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
6304      */
6305     function isFlattenable(value) {
6306       return isArray(value) || isArguments(value) ||
6307         !!(spreadableSymbol && value && value[spreadableSymbol]);
6308     }
6309
6310     /**
6311      * Checks if `value` is a valid array-like index.
6312      *
6313      * @private
6314      * @param {*} value The value to check.
6315      * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
6316      * @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
6317      */
6318     function isIndex(value, length) {
6319       length = length == null ? MAX_SAFE_INTEGER : length;
6320       return !!length &&
6321         (typeof value == 'number' || reIsUint.test(value)) &&
6322         (value > -1 && value % 1 == 0 && value < length);
6323     }
6324
6325     /**
6326      * Checks if the given arguments are from an iteratee call.
6327      *
6328      * @private
6329      * @param {*} value The potential iteratee value argument.
6330      * @param {*} index The potential iteratee index or key argument.
6331      * @param {*} object The potential iteratee object argument.
6332      * @returns {boolean} Returns `true` if the arguments are from an iteratee call,
6333      *  else `false`.
6334      */
6335     function isIterateeCall(value, index, object) {
6336       if (!isObject(object)) {
6337         return false;
6338       }
6339       var type = typeof index;
6340       if (type == 'number'
6341             ? (isArrayLike(object) && isIndex(index, object.length))
6342             : (type == 'string' && index in object)
6343           ) {
6344         return eq(object[index], value);
6345       }
6346       return false;
6347     }
6348
6349     /**
6350      * Checks if `value` is a property name and not a property path.
6351      *
6352      * @private
6353      * @param {*} value The value to check.
6354      * @param {Object} [object] The object to query keys on.
6355      * @returns {boolean} Returns `true` if `value` is a property name, else `false`.
6356      */
6357     function isKey(value, object) {
6358       if (isArray(value)) {
6359         return false;
6360       }
6361       var type = typeof value;
6362       if (type == 'number' || type == 'symbol' || type == 'boolean' ||
6363           value == null || isSymbol(value)) {
6364         return true;
6365       }
6366       return reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
6367         (object != null && value in Object(object));
6368     }
6369
6370     /**
6371      * Checks if `value` is suitable for use as unique object key.
6372      *
6373      * @private
6374      * @param {*} value The value to check.
6375      * @returns {boolean} Returns `true` if `value` is suitable, else `false`.
6376      */
6377     function isKeyable(value) {
6378       var type = typeof value;
6379       return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
6380         ? (value !== '__proto__')
6381         : (value === null);
6382     }
6383
6384     /**
6385      * Checks if `func` has a lazy counterpart.
6386      *
6387      * @private
6388      * @param {Function} func The function to check.
6389      * @returns {boolean} Returns `true` if `func` has a lazy counterpart,
6390      *  else `false`.
6391      */
6392     function isLaziable(func) {
6393       var funcName = getFuncName(func),
6394           other = lodash[funcName];
6395
6396       if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
6397         return false;
6398       }
6399       if (func === other) {
6400         return true;
6401       }
6402       var data = getData(other);
6403       return !!data && func === data[0];
6404     }
6405
6406     /**
6407      * Checks if `func` has its source masked.
6408      *
6409      * @private
6410      * @param {Function} func The function to check.
6411      * @returns {boolean} Returns `true` if `func` is masked, else `false`.
6412      */
6413     function isMasked(func) {
6414       return !!maskSrcKey && (maskSrcKey in func);
6415     }
6416
6417     /**
6418      * Checks if `func` is capable of being masked.
6419      *
6420      * @private
6421      * @param {*} value The value to check.
6422      * @returns {boolean} Returns `true` if `func` is maskable, else `false`.
6423      */
6424     var isMaskable = coreJsData ? isFunction : stubFalse;
6425
6426     /**
6427      * Checks if `value` is likely a prototype object.
6428      *
6429      * @private
6430      * @param {*} value The value to check.
6431      * @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
6432      */
6433     function isPrototype(value) {
6434       var Ctor = value && value.constructor,
6435           proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
6436
6437       return value === proto;
6438     }
6439
6440     /**
6441      * Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
6442      *
6443      * @private
6444      * @param {*} value The value to check.
6445      * @returns {boolean} Returns `true` if `value` if suitable for strict
6446      *  equality comparisons, else `false`.
6447      */
6448     function isStrictComparable(value) {
6449       return value === value && !isObject(value);
6450     }
6451
6452     /**
6453      * A specialized version of `matchesProperty` for source values suitable
6454      * for strict equality comparisons, i.e. `===`.
6455      *
6456      * @private
6457      * @param {string} key The key of the property to get.
6458      * @param {*} srcValue The value to match.
6459      * @returns {Function} Returns the new spec function.
6460      */
6461     function matchesStrictComparable(key, srcValue) {
6462       return function(object) {
6463         if (object == null) {
6464           return false;
6465         }
6466         return object[key] === srcValue &&
6467           (srcValue !== undefined || (key in Object(object)));
6468       };
6469     }
6470
6471     /**
6472      * A specialized version of `_.memoize` which clears the memoized function's
6473      * cache when it exceeds `MAX_MEMOIZE_SIZE`.
6474      *
6475      * @private
6476      * @param {Function} func The function to have its output memoized.
6477      * @returns {Function} Returns the new memoized function.
6478      */
6479     function memoizeCapped(func) {
6480       var result = memoize(func, function(key) {
6481         if (cache.size === MAX_MEMOIZE_SIZE) {
6482           cache.clear();
6483         }
6484         return key;
6485       });
6486
6487       var cache = result.cache;
6488       return result;
6489     }
6490
6491     /**
6492      * Merges the function metadata of `source` into `data`.
6493      *
6494      * Merging metadata reduces the number of wrappers used to invoke a function.
6495      * This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
6496      * may be applied regardless of execution order. Methods like `_.ary` and
6497      * `_.rearg` modify function arguments, making the order in which they are
6498      * executed important, preventing the merging of metadata. However, we make
6499      * an exception for a safe combined case where curried functions have `_.ary`
6500      * and or `_.rearg` applied.
6501      *
6502      * @private
6503      * @param {Array} data The destination metadata.
6504      * @param {Array} source The source metadata.
6505      * @returns {Array} Returns `data`.
6506      */
6507     function mergeData(data, source) {
6508       var bitmask = data[1],
6509           srcBitmask = source[1],
6510           newBitmask = bitmask | srcBitmask,
6511           isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG);
6512
6513       var isCombo =
6514         ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) ||
6515         ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) ||
6516         ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG));
6517
6518       // Exit early if metadata can't be merged.
6519       if (!(isCommon || isCombo)) {
6520         return data;
6521       }
6522       // Use source `thisArg` if available.
6523       if (srcBitmask & WRAP_BIND_FLAG) {
6524         data[2] = source[2];
6525         // Set when currying a bound function.
6526         newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG;
6527       }
6528       // Compose partial arguments.
6529       var value = source[3];
6530       if (value) {
6531         var partials = data[3];
6532         data[3] = partials ? composeArgs(partials, value, source[4]) : value;
6533         data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
6534       }
6535       // Compose partial right arguments.
6536       value = source[5];
6537       if (value) {
6538         partials = data[5];
6539         data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
6540         data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
6541       }
6542       // Use source `argPos` if available.
6543       value = source[7];
6544       if (value) {
6545         data[7] = value;
6546       }
6547       // Use source `ary` if it's smaller.
6548       if (srcBitmask & WRAP_ARY_FLAG) {
6549         data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
6550       }
6551       // Use source `arity` if one is not provided.
6552       if (data[9] == null) {
6553         data[9] = source[9];
6554       }
6555       // Use source `func` and merge bitmasks.
6556       data[0] = source[0];
6557       data[1] = newBitmask;
6558
6559       return data;
6560     }
6561
6562     /**
6563      * This function is like
6564      * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
6565      * except that it includes inherited enumerable properties.
6566      *
6567      * @private
6568      * @param {Object} object The object to query.
6569      * @returns {Array} Returns the array of property names.
6570      */
6571     function nativeKeysIn(object) {
6572       var result = [];
6573       if (object != null) {
6574         for (var key in Object(object)) {
6575           result.push(key);
6576         }
6577       }
6578       return result;
6579     }
6580
6581     /**
6582      * Converts `value` to a string using `Object.prototype.toString`.
6583      *
6584      * @private
6585      * @param {*} value The value to convert.
6586      * @returns {string} Returns the converted string.
6587      */
6588     function objectToString(value) {
6589       return nativeObjectToString.call(value);
6590     }
6591
6592     /**
6593      * A specialized version of `baseRest` which transforms the rest array.
6594      *
6595      * @private
6596      * @param {Function} func The function to apply a rest parameter to.
6597      * @param {number} [start=func.length-1] The start position of the rest parameter.
6598      * @param {Function} transform The rest array transform.
6599      * @returns {Function} Returns the new function.
6600      */
6601     function overRest(func, start, transform) {
6602       start = nativeMax(start === undefined ? (func.length - 1) : start, 0);
6603       return function() {
6604         var args = arguments,
6605             index = -1,
6606             length = nativeMax(args.length - start, 0),
6607             array = Array(length);
6608
6609         while (++index < length) {
6610           array[index] = args[start + index];
6611         }
6612         index = -1;
6613         var otherArgs = Array(start + 1);
6614         while (++index < start) {
6615           otherArgs[index] = args[index];
6616         }
6617         otherArgs[start] = transform(array);
6618         return apply(func, this, otherArgs);
6619       };
6620     }
6621
6622     /**
6623      * Gets the parent value at `path` of `object`.
6624      *
6625      * @private
6626      * @param {Object} object The object to query.
6627      * @param {Array} path The path to get the parent value of.
6628      * @returns {*} Returns the parent value.
6629      */
6630     function parent(object, path) {
6631       return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1));
6632     }
6633
6634     /**
6635      * Reorder `array` according to the specified indexes where the element at
6636      * the first index is assigned as the first element, the element at
6637      * the second index is assigned as the second element, and so on.
6638      *
6639      * @private
6640      * @param {Array} array The array to reorder.
6641      * @param {Array} indexes The arranged array indexes.
6642      * @returns {Array} Returns `array`.
6643      */
6644     function reorder(array, indexes) {
6645       var arrLength = array.length,
6646           length = nativeMin(indexes.length, arrLength),
6647           oldArray = copyArray(array);
6648
6649       while (length--) {
6650         var index = indexes[length];
6651         array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
6652       }
6653       return array;
6654     }
6655
6656     /**
6657      * Sets metadata for `func`.
6658      *
6659      * **Note:** If this function becomes hot, i.e. is invoked a lot in a short
6660      * period of time, it will trip its breaker and transition to an identity
6661      * function to avoid garbage collection pauses in V8. See
6662      * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
6663      * for more details.
6664      *
6665      * @private
6666      * @param {Function} func The function to associate metadata with.
6667      * @param {*} data The metadata.
6668      * @returns {Function} Returns `func`.
6669      */
6670     var setData = shortOut(baseSetData);
6671
6672     /**
6673      * A simple wrapper around the global [`setTimeout`](https://mdn.io/setTimeout).
6674      *
6675      * @private
6676      * @param {Function} func The function to delay.
6677      * @param {number} wait The number of milliseconds to delay invocation.
6678      * @returns {number|Object} Returns the timer id or timeout object.
6679      */
6680     var setTimeout = ctxSetTimeout || function(func, wait) {
6681       return root.setTimeout(func, wait);
6682     };
6683
6684     /**
6685      * Sets the `toString` method of `func` to return `string`.
6686      *
6687      * @private
6688      * @param {Function} func The function to modify.
6689      * @param {Function} string The `toString` result.
6690      * @returns {Function} Returns `func`.
6691      */
6692     var setToString = shortOut(baseSetToString);
6693
6694     /**
6695      * Sets the `toString` method of `wrapper` to mimic the source of `reference`
6696      * with wrapper details in a comment at the top of the source body.
6697      *
6698      * @private
6699      * @param {Function} wrapper The function to modify.
6700      * @param {Function} reference The reference function.
6701      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
6702      * @returns {Function} Returns `wrapper`.
6703      */
6704     function setWrapToString(wrapper, reference, bitmask) {
6705       var source = (reference + '');
6706       return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask)));
6707     }
6708
6709     /**
6710      * Creates a function that'll short out and invoke `identity` instead
6711      * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN`
6712      * milliseconds.
6713      *
6714      * @private
6715      * @param {Function} func The function to restrict.
6716      * @returns {Function} Returns the new shortable function.
6717      */
6718     function shortOut(func) {
6719       var count = 0,
6720           lastCalled = 0;
6721
6722       return function() {
6723         var stamp = nativeNow(),
6724             remaining = HOT_SPAN - (stamp - lastCalled);
6725
6726         lastCalled = stamp;
6727         if (remaining > 0) {
6728           if (++count >= HOT_COUNT) {
6729             return arguments[0];
6730           }
6731         } else {
6732           count = 0;
6733         }
6734         return func.apply(undefined, arguments);
6735       };
6736     }
6737
6738     /**
6739      * A specialized version of `_.shuffle` which mutates and sets the size of `array`.
6740      *
6741      * @private
6742      * @param {Array} array The array to shuffle.
6743      * @param {number} [size=array.length] The size of `array`.
6744      * @returns {Array} Returns `array`.
6745      */
6746     function shuffleSelf(array, size) {
6747       var index = -1,
6748           length = array.length,
6749           lastIndex = length - 1;
6750
6751       size = size === undefined ? length : size;
6752       while (++index < size) {
6753         var rand = baseRandom(index, lastIndex),
6754             value = array[rand];
6755
6756         array[rand] = array[index];
6757         array[index] = value;
6758       }
6759       array.length = size;
6760       return array;
6761     }
6762
6763     /**
6764      * Converts `string` to a property path array.
6765      *
6766      * @private
6767      * @param {string} string The string to convert.
6768      * @returns {Array} Returns the property path array.
6769      */
6770     var stringToPath = memoizeCapped(function(string) {
6771       var result = [];
6772       if (reLeadingDot.test(string)) {
6773         result.push('');
6774       }
6775       string.replace(rePropName, function(match, number, quote, string) {
6776         result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
6777       });
6778       return result;
6779     });
6780
6781     /**
6782      * Converts `value` to a string key if it's not a string or symbol.
6783      *
6784      * @private
6785      * @param {*} value The value to inspect.
6786      * @returns {string|symbol} Returns the key.
6787      */
6788     function toKey(value) {
6789       if (typeof value == 'string' || isSymbol(value)) {
6790         return value;
6791       }
6792       var result = (value + '');
6793       return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
6794     }
6795
6796     /**
6797      * Converts `func` to its source code.
6798      *
6799      * @private
6800      * @param {Function} func The function to convert.
6801      * @returns {string} Returns the source code.
6802      */
6803     function toSource(func) {
6804       if (func != null) {
6805         try {
6806           return funcToString.call(func);
6807         } catch (e) {}
6808         try {
6809           return (func + '');
6810         } catch (e) {}
6811       }
6812       return '';
6813     }
6814
6815     /**
6816      * Updates wrapper `details` based on `bitmask` flags.
6817      *
6818      * @private
6819      * @returns {Array} details The details to modify.
6820      * @param {number} bitmask The bitmask flags. See `createWrap` for more details.
6821      * @returns {Array} Returns `details`.
6822      */
6823     function updateWrapDetails(details, bitmask) {
6824       arrayEach(wrapFlags, function(pair) {
6825         var value = '_.' + pair[0];
6826         if ((bitmask & pair[1]) && !arrayIncludes(details, value)) {
6827           details.push(value);
6828         }
6829       });
6830       return details.sort();
6831     }
6832
6833     /**
6834      * Creates a clone of `wrapper`.
6835      *
6836      * @private
6837      * @param {Object} wrapper The wrapper to clone.
6838      * @returns {Object} Returns the cloned wrapper.
6839      */
6840     function wrapperClone(wrapper) {
6841       if (wrapper instanceof LazyWrapper) {
6842         return wrapper.clone();
6843       }
6844       var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
6845       result.__actions__ = copyArray(wrapper.__actions__);
6846       result.__index__  = wrapper.__index__;
6847       result.__values__ = wrapper.__values__;
6848       return result;
6849     }
6850
6851     /*------------------------------------------------------------------------*/
6852
6853     /**
6854      * Creates an array of elements split into groups the length of `size`.
6855      * If `array` can't be split evenly, the final chunk will be the remaining
6856      * elements.
6857      *
6858      * @static
6859      * @memberOf _
6860      * @since 3.0.0
6861      * @category Array
6862      * @param {Array} array The array to process.
6863      * @param {number} [size=1] The length of each chunk
6864      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
6865      * @returns {Array} Returns the new array of chunks.
6866      * @example
6867      *
6868      * _.chunk(['a', 'b', 'c', 'd'], 2);
6869      * // => [['a', 'b'], ['c', 'd']]
6870      *
6871      * _.chunk(['a', 'b', 'c', 'd'], 3);
6872      * // => [['a', 'b', 'c'], ['d']]
6873      */
6874     function chunk(array, size, guard) {
6875       if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
6876         size = 1;
6877       } else {
6878         size = nativeMax(toInteger(size), 0);
6879       }
6880       var length = array == null ? 0 : array.length;
6881       if (!length || size < 1) {
6882         return [];
6883       }
6884       var index = 0,
6885           resIndex = 0,
6886           result = Array(nativeCeil(length / size));
6887
6888       while (index < length) {
6889         result[resIndex++] = baseSlice(array, index, (index += size));
6890       }
6891       return result;
6892     }
6893
6894     /**
6895      * Creates an array with all falsey values removed. The values `false`, `null`,
6896      * `0`, `""`, `undefined`, and `NaN` are falsey.
6897      *
6898      * @static
6899      * @memberOf _
6900      * @since 0.1.0
6901      * @category Array
6902      * @param {Array} array The array to compact.
6903      * @returns {Array} Returns the new array of filtered values.
6904      * @example
6905      *
6906      * _.compact([0, 1, false, 2, '', 3]);
6907      * // => [1, 2, 3]
6908      */
6909     function compact(array) {
6910       var index = -1,
6911           length = array == null ? 0 : array.length,
6912           resIndex = 0,
6913           result = [];
6914
6915       while (++index < length) {
6916         var value = array[index];
6917         if (value) {
6918           result[resIndex++] = value;
6919         }
6920       }
6921       return result;
6922     }
6923
6924     /**
6925      * Creates a new array concatenating `array` with any additional arrays
6926      * and/or values.
6927      *
6928      * @static
6929      * @memberOf _
6930      * @since 4.0.0
6931      * @category Array
6932      * @param {Array} array The array to concatenate.
6933      * @param {...*} [values] The values to concatenate.
6934      * @returns {Array} Returns the new concatenated array.
6935      * @example
6936      *
6937      * var array = [1];
6938      * var other = _.concat(array, 2, [3], [[4]]);
6939      *
6940      * console.log(other);
6941      * // => [1, 2, 3, [4]]
6942      *
6943      * console.log(array);
6944      * // => [1]
6945      */
6946     function concat() {
6947       var length = arguments.length;
6948       if (!length) {
6949         return [];
6950       }
6951       var args = Array(length - 1),
6952           array = arguments[0],
6953           index = length;
6954
6955       while (index--) {
6956         args[index - 1] = arguments[index];
6957       }
6958       return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1));
6959     }
6960
6961     /**
6962      * Creates an array of `array` values not included in the other given arrays
6963      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
6964      * for equality comparisons. The order and references of result values are
6965      * determined by the first array.
6966      *
6967      * **Note:** Unlike `_.pullAll`, this method returns a new array.
6968      *
6969      * @static
6970      * @memberOf _
6971      * @since 0.1.0
6972      * @category Array
6973      * @param {Array} array The array to inspect.
6974      * @param {...Array} [values] The values to exclude.
6975      * @returns {Array} Returns the new array of filtered values.
6976      * @see _.without, _.xor
6977      * @example
6978      *
6979      * _.difference([2, 1], [2, 3]);
6980      * // => [1]
6981      */
6982     var difference = baseRest(function(array, values) {
6983       return isArrayLikeObject(array)
6984         ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
6985         : [];
6986     });
6987
6988     /**
6989      * This method is like `_.difference` except that it accepts `iteratee` which
6990      * is invoked for each element of `array` and `values` to generate the criterion
6991      * by which they're compared. The order and references of result values are
6992      * determined by the first array. The iteratee is invoked with one argument:
6993      * (value).
6994      *
6995      * **Note:** Unlike `_.pullAllBy`, this method returns a new array.
6996      *
6997      * @static
6998      * @memberOf _
6999      * @since 4.0.0
7000      * @category Array
7001      * @param {Array} array The array to inspect.
7002      * @param {...Array} [values] The values to exclude.
7003      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7004      * @returns {Array} Returns the new array of filtered values.
7005      * @example
7006      *
7007      * _.differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor);
7008      * // => [1.2]
7009      *
7010      * // The `_.property` iteratee shorthand.
7011      * _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
7012      * // => [{ 'x': 2 }]
7013      */
7014     var differenceBy = baseRest(function(array, values) {
7015       var iteratee = last(values);
7016       if (isArrayLikeObject(iteratee)) {
7017         iteratee = undefined;
7018       }
7019       return isArrayLikeObject(array)
7020         ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee, 2))
7021         : [];
7022     });
7023
7024     /**
7025      * This method is like `_.difference` except that it accepts `comparator`
7026      * which is invoked to compare elements of `array` to `values`. The order and
7027      * references of result values are determined by the first array. The comparator
7028      * is invoked with two arguments: (arrVal, othVal).
7029      *
7030      * **Note:** Unlike `_.pullAllWith`, this method returns a new array.
7031      *
7032      * @static
7033      * @memberOf _
7034      * @since 4.0.0
7035      * @category Array
7036      * @param {Array} array The array to inspect.
7037      * @param {...Array} [values] The values to exclude.
7038      * @param {Function} [comparator] The comparator invoked per element.
7039      * @returns {Array} Returns the new array of filtered values.
7040      * @example
7041      *
7042      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
7043      *
7044      * _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
7045      * // => [{ 'x': 2, 'y': 1 }]
7046      */
7047     var differenceWith = baseRest(function(array, values) {
7048       var comparator = last(values);
7049       if (isArrayLikeObject(comparator)) {
7050         comparator = undefined;
7051       }
7052       return isArrayLikeObject(array)
7053         ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)
7054         : [];
7055     });
7056
7057     /**
7058      * Creates a slice of `array` with `n` elements dropped from the beginning.
7059      *
7060      * @static
7061      * @memberOf _
7062      * @since 0.5.0
7063      * @category Array
7064      * @param {Array} array The array to query.
7065      * @param {number} [n=1] The number of elements to drop.
7066      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
7067      * @returns {Array} Returns the slice of `array`.
7068      * @example
7069      *
7070      * _.drop([1, 2, 3]);
7071      * // => [2, 3]
7072      *
7073      * _.drop([1, 2, 3], 2);
7074      * // => [3]
7075      *
7076      * _.drop([1, 2, 3], 5);
7077      * // => []
7078      *
7079      * _.drop([1, 2, 3], 0);
7080      * // => [1, 2, 3]
7081      */
7082     function drop(array, n, guard) {
7083       var length = array == null ? 0 : array.length;
7084       if (!length) {
7085         return [];
7086       }
7087       n = (guard || n === undefined) ? 1 : toInteger(n);
7088       return baseSlice(array, n < 0 ? 0 : n, length);
7089     }
7090
7091     /**
7092      * Creates a slice of `array` with `n` elements dropped from the end.
7093      *
7094      * @static
7095      * @memberOf _
7096      * @since 3.0.0
7097      * @category Array
7098      * @param {Array} array The array to query.
7099      * @param {number} [n=1] The number of elements to drop.
7100      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
7101      * @returns {Array} Returns the slice of `array`.
7102      * @example
7103      *
7104      * _.dropRight([1, 2, 3]);
7105      * // => [1, 2]
7106      *
7107      * _.dropRight([1, 2, 3], 2);
7108      * // => [1]
7109      *
7110      * _.dropRight([1, 2, 3], 5);
7111      * // => []
7112      *
7113      * _.dropRight([1, 2, 3], 0);
7114      * // => [1, 2, 3]
7115      */
7116     function dropRight(array, n, guard) {
7117       var length = array == null ? 0 : array.length;
7118       if (!length) {
7119         return [];
7120       }
7121       n = (guard || n === undefined) ? 1 : toInteger(n);
7122       n = length - n;
7123       return baseSlice(array, 0, n < 0 ? 0 : n);
7124     }
7125
7126     /**
7127      * Creates a slice of `array` excluding elements dropped from the end.
7128      * Elements are dropped until `predicate` returns falsey. The predicate is
7129      * invoked with three arguments: (value, index, array).
7130      *
7131      * @static
7132      * @memberOf _
7133      * @since 3.0.0
7134      * @category Array
7135      * @param {Array} array The array to query.
7136      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7137      * @returns {Array} Returns the slice of `array`.
7138      * @example
7139      *
7140      * var users = [
7141      *   { 'user': 'barney',  'active': true },
7142      *   { 'user': 'fred',    'active': false },
7143      *   { 'user': 'pebbles', 'active': false }
7144      * ];
7145      *
7146      * _.dropRightWhile(users, function(o) { return !o.active; });
7147      * // => objects for ['barney']
7148      *
7149      * // The `_.matches` iteratee shorthand.
7150      * _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
7151      * // => objects for ['barney', 'fred']
7152      *
7153      * // The `_.matchesProperty` iteratee shorthand.
7154      * _.dropRightWhile(users, ['active', false]);
7155      * // => objects for ['barney']
7156      *
7157      * // The `_.property` iteratee shorthand.
7158      * _.dropRightWhile(users, 'active');
7159      * // => objects for ['barney', 'fred', 'pebbles']
7160      */
7161     function dropRightWhile(array, predicate) {
7162       return (array && array.length)
7163         ? baseWhile(array, getIteratee(predicate, 3), true, true)
7164         : [];
7165     }
7166
7167     /**
7168      * Creates a slice of `array` excluding elements dropped from the beginning.
7169      * Elements are dropped until `predicate` returns falsey. The predicate is
7170      * invoked with three arguments: (value, index, array).
7171      *
7172      * @static
7173      * @memberOf _
7174      * @since 3.0.0
7175      * @category Array
7176      * @param {Array} array The array to query.
7177      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7178      * @returns {Array} Returns the slice of `array`.
7179      * @example
7180      *
7181      * var users = [
7182      *   { 'user': 'barney',  'active': false },
7183      *   { 'user': 'fred',    'active': false },
7184      *   { 'user': 'pebbles', 'active': true }
7185      * ];
7186      *
7187      * _.dropWhile(users, function(o) { return !o.active; });
7188      * // => objects for ['pebbles']
7189      *
7190      * // The `_.matches` iteratee shorthand.
7191      * _.dropWhile(users, { 'user': 'barney', 'active': false });
7192      * // => objects for ['fred', 'pebbles']
7193      *
7194      * // The `_.matchesProperty` iteratee shorthand.
7195      * _.dropWhile(users, ['active', false]);
7196      * // => objects for ['pebbles']
7197      *
7198      * // The `_.property` iteratee shorthand.
7199      * _.dropWhile(users, 'active');
7200      * // => objects for ['barney', 'fred', 'pebbles']
7201      */
7202     function dropWhile(array, predicate) {
7203       return (array && array.length)
7204         ? baseWhile(array, getIteratee(predicate, 3), true)
7205         : [];
7206     }
7207
7208     /**
7209      * Fills elements of `array` with `value` from `start` up to, but not
7210      * including, `end`.
7211      *
7212      * **Note:** This method mutates `array`.
7213      *
7214      * @static
7215      * @memberOf _
7216      * @since 3.2.0
7217      * @category Array
7218      * @param {Array} array The array to fill.
7219      * @param {*} value The value to fill `array` with.
7220      * @param {number} [start=0] The start position.
7221      * @param {number} [end=array.length] The end position.
7222      * @returns {Array} Returns `array`.
7223      * @example
7224      *
7225      * var array = [1, 2, 3];
7226      *
7227      * _.fill(array, 'a');
7228      * console.log(array);
7229      * // => ['a', 'a', 'a']
7230      *
7231      * _.fill(Array(3), 2);
7232      * // => [2, 2, 2]
7233      *
7234      * _.fill([4, 6, 8, 10], '*', 1, 3);
7235      * // => [4, '*', '*', 10]
7236      */
7237     function fill(array, value, start, end) {
7238       var length = array == null ? 0 : array.length;
7239       if (!length) {
7240         return [];
7241       }
7242       if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
7243         start = 0;
7244         end = length;
7245       }
7246       return baseFill(array, value, start, end);
7247     }
7248
7249     /**
7250      * This method is like `_.find` except that it returns the index of the first
7251      * element `predicate` returns truthy for instead of the element itself.
7252      *
7253      * @static
7254      * @memberOf _
7255      * @since 1.1.0
7256      * @category Array
7257      * @param {Array} array The array to inspect.
7258      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7259      * @param {number} [fromIndex=0] The index to search from.
7260      * @returns {number} Returns the index of the found element, else `-1`.
7261      * @example
7262      *
7263      * var users = [
7264      *   { 'user': 'barney',  'active': false },
7265      *   { 'user': 'fred',    'active': false },
7266      *   { 'user': 'pebbles', 'active': true }
7267      * ];
7268      *
7269      * _.findIndex(users, function(o) { return o.user == 'barney'; });
7270      * // => 0
7271      *
7272      * // The `_.matches` iteratee shorthand.
7273      * _.findIndex(users, { 'user': 'fred', 'active': false });
7274      * // => 1
7275      *
7276      * // The `_.matchesProperty` iteratee shorthand.
7277      * _.findIndex(users, ['active', false]);
7278      * // => 0
7279      *
7280      * // The `_.property` iteratee shorthand.
7281      * _.findIndex(users, 'active');
7282      * // => 2
7283      */
7284     function findIndex(array, predicate, fromIndex) {
7285       var length = array == null ? 0 : array.length;
7286       if (!length) {
7287         return -1;
7288       }
7289       var index = fromIndex == null ? 0 : toInteger(fromIndex);
7290       if (index < 0) {
7291         index = nativeMax(length + index, 0);
7292       }
7293       return baseFindIndex(array, getIteratee(predicate, 3), index);
7294     }
7295
7296     /**
7297      * This method is like `_.findIndex` except that it iterates over elements
7298      * of `collection` from right to left.
7299      *
7300      * @static
7301      * @memberOf _
7302      * @since 2.0.0
7303      * @category Array
7304      * @param {Array} array The array to inspect.
7305      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7306      * @param {number} [fromIndex=array.length-1] The index to search from.
7307      * @returns {number} Returns the index of the found element, else `-1`.
7308      * @example
7309      *
7310      * var users = [
7311      *   { 'user': 'barney',  'active': true },
7312      *   { 'user': 'fred',    'active': false },
7313      *   { 'user': 'pebbles', 'active': false }
7314      * ];
7315      *
7316      * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
7317      * // => 2
7318      *
7319      * // The `_.matches` iteratee shorthand.
7320      * _.findLastIndex(users, { 'user': 'barney', 'active': true });
7321      * // => 0
7322      *
7323      * // The `_.matchesProperty` iteratee shorthand.
7324      * _.findLastIndex(users, ['active', false]);
7325      * // => 2
7326      *
7327      * // The `_.property` iteratee shorthand.
7328      * _.findLastIndex(users, 'active');
7329      * // => 0
7330      */
7331     function findLastIndex(array, predicate, fromIndex) {
7332       var length = array == null ? 0 : array.length;
7333       if (!length) {
7334         return -1;
7335       }
7336       var index = length - 1;
7337       if (fromIndex !== undefined) {
7338         index = toInteger(fromIndex);
7339         index = fromIndex < 0
7340           ? nativeMax(length + index, 0)
7341           : nativeMin(index, length - 1);
7342       }
7343       return baseFindIndex(array, getIteratee(predicate, 3), index, true);
7344     }
7345
7346     /**
7347      * Flattens `array` a single level deep.
7348      *
7349      * @static
7350      * @memberOf _
7351      * @since 0.1.0
7352      * @category Array
7353      * @param {Array} array The array to flatten.
7354      * @returns {Array} Returns the new flattened array.
7355      * @example
7356      *
7357      * _.flatten([1, [2, [3, [4]], 5]]);
7358      * // => [1, 2, [3, [4]], 5]
7359      */
7360     function flatten(array) {
7361       var length = array == null ? 0 : array.length;
7362       return length ? baseFlatten(array, 1) : [];
7363     }
7364
7365     /**
7366      * Recursively flattens `array`.
7367      *
7368      * @static
7369      * @memberOf _
7370      * @since 3.0.0
7371      * @category Array
7372      * @param {Array} array The array to flatten.
7373      * @returns {Array} Returns the new flattened array.
7374      * @example
7375      *
7376      * _.flattenDeep([1, [2, [3, [4]], 5]]);
7377      * // => [1, 2, 3, 4, 5]
7378      */
7379     function flattenDeep(array) {
7380       var length = array == null ? 0 : array.length;
7381       return length ? baseFlatten(array, INFINITY) : [];
7382     }
7383
7384     /**
7385      * Recursively flatten `array` up to `depth` times.
7386      *
7387      * @static
7388      * @memberOf _
7389      * @since 4.4.0
7390      * @category Array
7391      * @param {Array} array The array to flatten.
7392      * @param {number} [depth=1] The maximum recursion depth.
7393      * @returns {Array} Returns the new flattened array.
7394      * @example
7395      *
7396      * var array = [1, [2, [3, [4]], 5]];
7397      *
7398      * _.flattenDepth(array, 1);
7399      * // => [1, 2, [3, [4]], 5]
7400      *
7401      * _.flattenDepth(array, 2);
7402      * // => [1, 2, 3, [4], 5]
7403      */
7404     function flattenDepth(array, depth) {
7405       var length = array == null ? 0 : array.length;
7406       if (!length) {
7407         return [];
7408       }
7409       depth = depth === undefined ? 1 : toInteger(depth);
7410       return baseFlatten(array, depth);
7411     }
7412
7413     /**
7414      * The inverse of `_.toPairs`; this method returns an object composed
7415      * from key-value `pairs`.
7416      *
7417      * @static
7418      * @memberOf _
7419      * @since 4.0.0
7420      * @category Array
7421      * @param {Array} pairs The key-value pairs.
7422      * @returns {Object} Returns the new object.
7423      * @example
7424      *
7425      * _.fromPairs([['a', 1], ['b', 2]]);
7426      * // => { 'a': 1, 'b': 2 }
7427      */
7428     function fromPairs(pairs) {
7429       var index = -1,
7430           length = pairs == null ? 0 : pairs.length,
7431           result = {};
7432
7433       while (++index < length) {
7434         var pair = pairs[index];
7435         result[pair[0]] = pair[1];
7436       }
7437       return result;
7438     }
7439
7440     /**
7441      * Gets the first element of `array`.
7442      *
7443      * @static
7444      * @memberOf _
7445      * @since 0.1.0
7446      * @alias first
7447      * @category Array
7448      * @param {Array} array The array to query.
7449      * @returns {*} Returns the first element of `array`.
7450      * @example
7451      *
7452      * _.head([1, 2, 3]);
7453      * // => 1
7454      *
7455      * _.head([]);
7456      * // => undefined
7457      */
7458     function head(array) {
7459       return (array && array.length) ? array[0] : undefined;
7460     }
7461
7462     /**
7463      * Gets the index at which the first occurrence of `value` is found in `array`
7464      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
7465      * for equality comparisons. If `fromIndex` is negative, it's used as the
7466      * offset from the end of `array`.
7467      *
7468      * @static
7469      * @memberOf _
7470      * @since 0.1.0
7471      * @category Array
7472      * @param {Array} array The array to inspect.
7473      * @param {*} value The value to search for.
7474      * @param {number} [fromIndex=0] The index to search from.
7475      * @returns {number} Returns the index of the matched value, else `-1`.
7476      * @example
7477      *
7478      * _.indexOf([1, 2, 1, 2], 2);
7479      * // => 1
7480      *
7481      * // Search from the `fromIndex`.
7482      * _.indexOf([1, 2, 1, 2], 2, 2);
7483      * // => 3
7484      */
7485     function indexOf(array, value, fromIndex) {
7486       var length = array == null ? 0 : array.length;
7487       if (!length) {
7488         return -1;
7489       }
7490       var index = fromIndex == null ? 0 : toInteger(fromIndex);
7491       if (index < 0) {
7492         index = nativeMax(length + index, 0);
7493       }
7494       return baseIndexOf(array, value, index);
7495     }
7496
7497     /**
7498      * Gets all but the last element of `array`.
7499      *
7500      * @static
7501      * @memberOf _
7502      * @since 0.1.0
7503      * @category Array
7504      * @param {Array} array The array to query.
7505      * @returns {Array} Returns the slice of `array`.
7506      * @example
7507      *
7508      * _.initial([1, 2, 3]);
7509      * // => [1, 2]
7510      */
7511     function initial(array) {
7512       var length = array == null ? 0 : array.length;
7513       return length ? baseSlice(array, 0, -1) : [];
7514     }
7515
7516     /**
7517      * Creates an array of unique values that are included in all given arrays
7518      * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
7519      * for equality comparisons. The order and references of result values are
7520      * determined by the first array.
7521      *
7522      * @static
7523      * @memberOf _
7524      * @since 0.1.0
7525      * @category Array
7526      * @param {...Array} [arrays] The arrays to inspect.
7527      * @returns {Array} Returns the new array of intersecting values.
7528      * @example
7529      *
7530      * _.intersection([2, 1], [2, 3]);
7531      * // => [2]
7532      */
7533     var intersection = baseRest(function(arrays) {
7534       var mapped = arrayMap(arrays, castArrayLikeObject);
7535       return (mapped.length && mapped[0] === arrays[0])
7536         ? baseIntersection(mapped)
7537         : [];
7538     });
7539
7540     /**
7541      * This method is like `_.intersection` except that it accepts `iteratee`
7542      * which is invoked for each element of each `arrays` to generate the criterion
7543      * by which they're compared. The order and references of result values are
7544      * determined by the first array. The iteratee is invoked with one argument:
7545      * (value).
7546      *
7547      * @static
7548      * @memberOf _
7549      * @since 4.0.0
7550      * @category Array
7551      * @param {...Array} [arrays] The arrays to inspect.
7552      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7553      * @returns {Array} Returns the new array of intersecting values.
7554      * @example
7555      *
7556      * _.intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor);
7557      * // => [2.1]
7558      *
7559      * // The `_.property` iteratee shorthand.
7560      * _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
7561      * // => [{ 'x': 1 }]
7562      */
7563     var intersectionBy = baseRest(function(arrays) {
7564       var iteratee = last(arrays),
7565           mapped = arrayMap(arrays, castArrayLikeObject);
7566
7567       if (iteratee === last(mapped)) {
7568         iteratee = undefined;
7569       } else {
7570         mapped.pop();
7571       }
7572       return (mapped.length && mapped[0] === arrays[0])
7573         ? baseIntersection(mapped, getIteratee(iteratee, 2))
7574         : [];
7575     });
7576
7577     /**
7578      * This method is like `_.intersection` except that it accepts `comparator`
7579      * which is invoked to compare elements of `arrays`. The order and references
7580      * of result values are determined by the first array. The comparator is
7581      * invoked with two arguments: (arrVal, othVal).
7582      *
7583      * @static
7584      * @memberOf _
7585      * @since 4.0.0
7586      * @category Array
7587      * @param {...Array} [arrays] The arrays to inspect.
7588      * @param {Function} [comparator] The comparator invoked per element.
7589      * @returns {Array} Returns the new array of intersecting values.
7590      * @example
7591      *
7592      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
7593      * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
7594      *
7595      * _.intersectionWith(objects, others, _.isEqual);
7596      * // => [{ 'x': 1, 'y': 2 }]
7597      */
7598     var intersectionWith = baseRest(function(arrays) {
7599       var comparator = last(arrays),
7600           mapped = arrayMap(arrays, castArrayLikeObject);
7601
7602       comparator = typeof comparator == 'function' ? comparator : undefined;
7603       if (comparator) {
7604         mapped.pop();
7605       }
7606       return (mapped.length && mapped[0] === arrays[0])
7607         ? baseIntersection(mapped, undefined, comparator)
7608         : [];
7609     });
7610
7611     /**
7612      * Converts all elements in `array` into a string separated by `separator`.
7613      *
7614      * @static
7615      * @memberOf _
7616      * @since 4.0.0
7617      * @category Array
7618      * @param {Array} array The array to convert.
7619      * @param {string} [separator=','] The element separator.
7620      * @returns {string} Returns the joined string.
7621      * @example
7622      *
7623      * _.join(['a', 'b', 'c'], '~');
7624      * // => 'a~b~c'
7625      */
7626     function join(array, separator) {
7627       return array == null ? '' : nativeJoin.call(array, separator);
7628     }
7629
7630     /**
7631      * Gets the last element of `array`.
7632      *
7633      * @static
7634      * @memberOf _
7635      * @since 0.1.0
7636      * @category Array
7637      * @param {Array} array The array to query.
7638      * @returns {*} Returns the last element of `array`.
7639      * @example
7640      *
7641      * _.last([1, 2, 3]);
7642      * // => 3
7643      */
7644     function last(array) {
7645       var length = array == null ? 0 : array.length;
7646       return length ? array[length - 1] : undefined;
7647     }
7648
7649     /**
7650      * This method is like `_.indexOf` except that it iterates over elements of
7651      * `array` from right to left.
7652      *
7653      * @static
7654      * @memberOf _
7655      * @since 0.1.0
7656      * @category Array
7657      * @param {Array} array The array to inspect.
7658      * @param {*} value The value to search for.
7659      * @param {number} [fromIndex=array.length-1] The index to search from.
7660      * @returns {number} Returns the index of the matched value, else `-1`.
7661      * @example
7662      *
7663      * _.lastIndexOf([1, 2, 1, 2], 2);
7664      * // => 3
7665      *
7666      * // Search from the `fromIndex`.
7667      * _.lastIndexOf([1, 2, 1, 2], 2, 2);
7668      * // => 1
7669      */
7670     function lastIndexOf(array, value, fromIndex) {
7671       var length = array == null ? 0 : array.length;
7672       if (!length) {
7673         return -1;
7674       }
7675       var index = length;
7676       if (fromIndex !== undefined) {
7677         index = toInteger(fromIndex);
7678         index = index < 0 ? nativeMax(length + index, 0) : nativeMin(index, length - 1);
7679       }
7680       return value === value
7681         ? strictLastIndexOf(array, value, index)
7682         : baseFindIndex(array, baseIsNaN, index, true);
7683     }
7684
7685     /**
7686      * Gets the element at index `n` of `array`. If `n` is negative, the nth
7687      * element from the end is returned.
7688      *
7689      * @static
7690      * @memberOf _
7691      * @since 4.11.0
7692      * @category Array
7693      * @param {Array} array The array to query.
7694      * @param {number} [n=0] The index of the element to return.
7695      * @returns {*} Returns the nth element of `array`.
7696      * @example
7697      *
7698      * var array = ['a', 'b', 'c', 'd'];
7699      *
7700      * _.nth(array, 1);
7701      * // => 'b'
7702      *
7703      * _.nth(array, -2);
7704      * // => 'c';
7705      */
7706     function nth(array, n) {
7707       return (array && array.length) ? baseNth(array, toInteger(n)) : undefined;
7708     }
7709
7710     /**
7711      * Removes all given values from `array` using
7712      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
7713      * for equality comparisons.
7714      *
7715      * **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
7716      * to remove elements from an array by predicate.
7717      *
7718      * @static
7719      * @memberOf _
7720      * @since 2.0.0
7721      * @category Array
7722      * @param {Array} array The array to modify.
7723      * @param {...*} [values] The values to remove.
7724      * @returns {Array} Returns `array`.
7725      * @example
7726      *
7727      * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
7728      *
7729      * _.pull(array, 'a', 'c');
7730      * console.log(array);
7731      * // => ['b', 'b']
7732      */
7733     var pull = baseRest(pullAll);
7734
7735     /**
7736      * This method is like `_.pull` except that it accepts an array of values to remove.
7737      *
7738      * **Note:** Unlike `_.difference`, this method mutates `array`.
7739      *
7740      * @static
7741      * @memberOf _
7742      * @since 4.0.0
7743      * @category Array
7744      * @param {Array} array The array to modify.
7745      * @param {Array} values The values to remove.
7746      * @returns {Array} Returns `array`.
7747      * @example
7748      *
7749      * var array = ['a', 'b', 'c', 'a', 'b', 'c'];
7750      *
7751      * _.pullAll(array, ['a', 'c']);
7752      * console.log(array);
7753      * // => ['b', 'b']
7754      */
7755     function pullAll(array, values) {
7756       return (array && array.length && values && values.length)
7757         ? basePullAll(array, values)
7758         : array;
7759     }
7760
7761     /**
7762      * This method is like `_.pullAll` except that it accepts `iteratee` which is
7763      * invoked for each element of `array` and `values` to generate the criterion
7764      * by which they're compared. The iteratee is invoked with one argument: (value).
7765      *
7766      * **Note:** Unlike `_.differenceBy`, this method mutates `array`.
7767      *
7768      * @static
7769      * @memberOf _
7770      * @since 4.0.0
7771      * @category Array
7772      * @param {Array} array The array to modify.
7773      * @param {Array} values The values to remove.
7774      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7775      * @returns {Array} Returns `array`.
7776      * @example
7777      *
7778      * var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
7779      *
7780      * _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
7781      * console.log(array);
7782      * // => [{ 'x': 2 }]
7783      */
7784     function pullAllBy(array, values, iteratee) {
7785       return (array && array.length && values && values.length)
7786         ? basePullAll(array, values, getIteratee(iteratee, 2))
7787         : array;
7788     }
7789
7790     /**
7791      * This method is like `_.pullAll` except that it accepts `comparator` which
7792      * is invoked to compare elements of `array` to `values`. The comparator is
7793      * invoked with two arguments: (arrVal, othVal).
7794      *
7795      * **Note:** Unlike `_.differenceWith`, this method mutates `array`.
7796      *
7797      * @static
7798      * @memberOf _
7799      * @since 4.6.0
7800      * @category Array
7801      * @param {Array} array The array to modify.
7802      * @param {Array} values The values to remove.
7803      * @param {Function} [comparator] The comparator invoked per element.
7804      * @returns {Array} Returns `array`.
7805      * @example
7806      *
7807      * var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
7808      *
7809      * _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
7810      * console.log(array);
7811      * // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
7812      */
7813     function pullAllWith(array, values, comparator) {
7814       return (array && array.length && values && values.length)
7815         ? basePullAll(array, values, undefined, comparator)
7816         : array;
7817     }
7818
7819     /**
7820      * Removes elements from `array` corresponding to `indexes` and returns an
7821      * array of removed elements.
7822      *
7823      * **Note:** Unlike `_.at`, this method mutates `array`.
7824      *
7825      * @static
7826      * @memberOf _
7827      * @since 3.0.0
7828      * @category Array
7829      * @param {Array} array The array to modify.
7830      * @param {...(number|number[])} [indexes] The indexes of elements to remove.
7831      * @returns {Array} Returns the new array of removed elements.
7832      * @example
7833      *
7834      * var array = ['a', 'b', 'c', 'd'];
7835      * var pulled = _.pullAt(array, [1, 3]);
7836      *
7837      * console.log(array);
7838      * // => ['a', 'c']
7839      *
7840      * console.log(pulled);
7841      * // => ['b', 'd']
7842      */
7843     var pullAt = flatRest(function(array, indexes) {
7844       var length = array == null ? 0 : array.length,
7845           result = baseAt(array, indexes);
7846
7847       basePullAt(array, arrayMap(indexes, function(index) {
7848         return isIndex(index, length) ? +index : index;
7849       }).sort(compareAscending));
7850
7851       return result;
7852     });
7853
7854     /**
7855      * Removes all elements from `array` that `predicate` returns truthy for
7856      * and returns an array of the removed elements. The predicate is invoked
7857      * with three arguments: (value, index, array).
7858      *
7859      * **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull`
7860      * to pull elements from an array by value.
7861      *
7862      * @static
7863      * @memberOf _
7864      * @since 2.0.0
7865      * @category Array
7866      * @param {Array} array The array to modify.
7867      * @param {Function} [predicate=_.identity] The function invoked per iteration.
7868      * @returns {Array} Returns the new array of removed elements.
7869      * @example
7870      *
7871      * var array = [1, 2, 3, 4];
7872      * var evens = _.remove(array, function(n) {
7873      *   return n % 2 == 0;
7874      * });
7875      *
7876      * console.log(array);
7877      * // => [1, 3]
7878      *
7879      * console.log(evens);
7880      * // => [2, 4]
7881      */
7882     function remove(array, predicate) {
7883       var result = [];
7884       if (!(array && array.length)) {
7885         return result;
7886       }
7887       var index = -1,
7888           indexes = [],
7889           length = array.length;
7890
7891       predicate = getIteratee(predicate, 3);
7892       while (++index < length) {
7893         var value = array[index];
7894         if (predicate(value, index, array)) {
7895           result.push(value);
7896           indexes.push(index);
7897         }
7898       }
7899       basePullAt(array, indexes);
7900       return result;
7901     }
7902
7903     /**
7904      * Reverses `array` so that the first element becomes the last, the second
7905      * element becomes the second to last, and so on.
7906      *
7907      * **Note:** This method mutates `array` and is based on
7908      * [`Array#reverse`](https://mdn.io/Array/reverse).
7909      *
7910      * @static
7911      * @memberOf _
7912      * @since 4.0.0
7913      * @category Array
7914      * @param {Array} array The array to modify.
7915      * @returns {Array} Returns `array`.
7916      * @example
7917      *
7918      * var array = [1, 2, 3];
7919      *
7920      * _.reverse(array);
7921      * // => [3, 2, 1]
7922      *
7923      * console.log(array);
7924      * // => [3, 2, 1]
7925      */
7926     function reverse(array) {
7927       return array == null ? array : nativeReverse.call(array);
7928     }
7929
7930     /**
7931      * Creates a slice of `array` from `start` up to, but not including, `end`.
7932      *
7933      * **Note:** This method is used instead of
7934      * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
7935      * returned.
7936      *
7937      * @static
7938      * @memberOf _
7939      * @since 3.0.0
7940      * @category Array
7941      * @param {Array} array The array to slice.
7942      * @param {number} [start=0] The start position.
7943      * @param {number} [end=array.length] The end position.
7944      * @returns {Array} Returns the slice of `array`.
7945      */
7946     function slice(array, start, end) {
7947       var length = array == null ? 0 : array.length;
7948       if (!length) {
7949         return [];
7950       }
7951       if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
7952         start = 0;
7953         end = length;
7954       }
7955       else {
7956         start = start == null ? 0 : toInteger(start);
7957         end = end === undefined ? length : toInteger(end);
7958       }
7959       return baseSlice(array, start, end);
7960     }
7961
7962     /**
7963      * Uses a binary search to determine the lowest index at which `value`
7964      * should be inserted into `array` in order to maintain its sort order.
7965      *
7966      * @static
7967      * @memberOf _
7968      * @since 0.1.0
7969      * @category Array
7970      * @param {Array} array The sorted array to inspect.
7971      * @param {*} value The value to evaluate.
7972      * @returns {number} Returns the index at which `value` should be inserted
7973      *  into `array`.
7974      * @example
7975      *
7976      * _.sortedIndex([30, 50], 40);
7977      * // => 1
7978      */
7979     function sortedIndex(array, value) {
7980       return baseSortedIndex(array, value);
7981     }
7982
7983     /**
7984      * This method is like `_.sortedIndex` except that it accepts `iteratee`
7985      * which is invoked for `value` and each element of `array` to compute their
7986      * sort ranking. The iteratee is invoked with one argument: (value).
7987      *
7988      * @static
7989      * @memberOf _
7990      * @since 4.0.0
7991      * @category Array
7992      * @param {Array} array The sorted array to inspect.
7993      * @param {*} value The value to evaluate.
7994      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
7995      * @returns {number} Returns the index at which `value` should be inserted
7996      *  into `array`.
7997      * @example
7998      *
7999      * var objects = [{ 'x': 4 }, { 'x': 5 }];
8000      *
8001      * _.sortedIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
8002      * // => 0
8003      *
8004      * // The `_.property` iteratee shorthand.
8005      * _.sortedIndexBy(objects, { 'x': 4 }, 'x');
8006      * // => 0
8007      */
8008     function sortedIndexBy(array, value, iteratee) {
8009       return baseSortedIndexBy(array, value, getIteratee(iteratee, 2));
8010     }
8011
8012     /**
8013      * This method is like `_.indexOf` except that it performs a binary
8014      * search on a sorted `array`.
8015      *
8016      * @static
8017      * @memberOf _
8018      * @since 4.0.0
8019      * @category Array
8020      * @param {Array} array The array to inspect.
8021      * @param {*} value The value to search for.
8022      * @returns {number} Returns the index of the matched value, else `-1`.
8023      * @example
8024      *
8025      * _.sortedIndexOf([4, 5, 5, 5, 6], 5);
8026      * // => 1
8027      */
8028     function sortedIndexOf(array, value) {
8029       var length = array == null ? 0 : array.length;
8030       if (length) {
8031         var index = baseSortedIndex(array, value);
8032         if (index < length && eq(array[index], value)) {
8033           return index;
8034         }
8035       }
8036       return -1;
8037     }
8038
8039     /**
8040      * This method is like `_.sortedIndex` except that it returns the highest
8041      * index at which `value` should be inserted into `array` in order to
8042      * maintain its sort order.
8043      *
8044      * @static
8045      * @memberOf _
8046      * @since 3.0.0
8047      * @category Array
8048      * @param {Array} array The sorted array to inspect.
8049      * @param {*} value The value to evaluate.
8050      * @returns {number} Returns the index at which `value` should be inserted
8051      *  into `array`.
8052      * @example
8053      *
8054      * _.sortedLastIndex([4, 5, 5, 5, 6], 5);
8055      * // => 4
8056      */
8057     function sortedLastIndex(array, value) {
8058       return baseSortedIndex(array, value, true);
8059     }
8060
8061     /**
8062      * This method is like `_.sortedLastIndex` except that it accepts `iteratee`
8063      * which is invoked for `value` and each element of `array` to compute their
8064      * sort ranking. The iteratee is invoked with one argument: (value).
8065      *
8066      * @static
8067      * @memberOf _
8068      * @since 4.0.0
8069      * @category Array
8070      * @param {Array} array The sorted array to inspect.
8071      * @param {*} value The value to evaluate.
8072      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8073      * @returns {number} Returns the index at which `value` should be inserted
8074      *  into `array`.
8075      * @example
8076      *
8077      * var objects = [{ 'x': 4 }, { 'x': 5 }];
8078      *
8079      * _.sortedLastIndexBy(objects, { 'x': 4 }, function(o) { return o.x; });
8080      * // => 1
8081      *
8082      * // The `_.property` iteratee shorthand.
8083      * _.sortedLastIndexBy(objects, { 'x': 4 }, 'x');
8084      * // => 1
8085      */
8086     function sortedLastIndexBy(array, value, iteratee) {
8087       return baseSortedIndexBy(array, value, getIteratee(iteratee, 2), true);
8088     }
8089
8090     /**
8091      * This method is like `_.lastIndexOf` except that it performs a binary
8092      * search on a sorted `array`.
8093      *
8094      * @static
8095      * @memberOf _
8096      * @since 4.0.0
8097      * @category Array
8098      * @param {Array} array The array to inspect.
8099      * @param {*} value The value to search for.
8100      * @returns {number} Returns the index of the matched value, else `-1`.
8101      * @example
8102      *
8103      * _.sortedLastIndexOf([4, 5, 5, 5, 6], 5);
8104      * // => 3
8105      */
8106     function sortedLastIndexOf(array, value) {
8107       var length = array == null ? 0 : array.length;
8108       if (length) {
8109         var index = baseSortedIndex(array, value, true) - 1;
8110         if (eq(array[index], value)) {
8111           return index;
8112         }
8113       }
8114       return -1;
8115     }
8116
8117     /**
8118      * This method is like `_.uniq` except that it's designed and optimized
8119      * for sorted arrays.
8120      *
8121      * @static
8122      * @memberOf _
8123      * @since 4.0.0
8124      * @category Array
8125      * @param {Array} array The array to inspect.
8126      * @returns {Array} Returns the new duplicate free array.
8127      * @example
8128      *
8129      * _.sortedUniq([1, 1, 2]);
8130      * // => [1, 2]
8131      */
8132     function sortedUniq(array) {
8133       return (array && array.length)
8134         ? baseSortedUniq(array)
8135         : [];
8136     }
8137
8138     /**
8139      * This method is like `_.uniqBy` except that it's designed and optimized
8140      * for sorted arrays.
8141      *
8142      * @static
8143      * @memberOf _
8144      * @since 4.0.0
8145      * @category Array
8146      * @param {Array} array The array to inspect.
8147      * @param {Function} [iteratee] The iteratee invoked per element.
8148      * @returns {Array} Returns the new duplicate free array.
8149      * @example
8150      *
8151      * _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
8152      * // => [1.1, 2.3]
8153      */
8154     function sortedUniqBy(array, iteratee) {
8155       return (array && array.length)
8156         ? baseSortedUniq(array, getIteratee(iteratee, 2))
8157         : [];
8158     }
8159
8160     /**
8161      * Gets all but the first element of `array`.
8162      *
8163      * @static
8164      * @memberOf _
8165      * @since 4.0.0
8166      * @category Array
8167      * @param {Array} array The array to query.
8168      * @returns {Array} Returns the slice of `array`.
8169      * @example
8170      *
8171      * _.tail([1, 2, 3]);
8172      * // => [2, 3]
8173      */
8174     function tail(array) {
8175       var length = array == null ? 0 : array.length;
8176       return length ? baseSlice(array, 1, length) : [];
8177     }
8178
8179     /**
8180      * Creates a slice of `array` with `n` elements taken from the beginning.
8181      *
8182      * @static
8183      * @memberOf _
8184      * @since 0.1.0
8185      * @category Array
8186      * @param {Array} array The array to query.
8187      * @param {number} [n=1] The number of elements to take.
8188      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
8189      * @returns {Array} Returns the slice of `array`.
8190      * @example
8191      *
8192      * _.take([1, 2, 3]);
8193      * // => [1]
8194      *
8195      * _.take([1, 2, 3], 2);
8196      * // => [1, 2]
8197      *
8198      * _.take([1, 2, 3], 5);
8199      * // => [1, 2, 3]
8200      *
8201      * _.take([1, 2, 3], 0);
8202      * // => []
8203      */
8204     function take(array, n, guard) {
8205       if (!(array && array.length)) {
8206         return [];
8207       }
8208       n = (guard || n === undefined) ? 1 : toInteger(n);
8209       return baseSlice(array, 0, n < 0 ? 0 : n);
8210     }
8211
8212     /**
8213      * Creates a slice of `array` with `n` elements taken from the end.
8214      *
8215      * @static
8216      * @memberOf _
8217      * @since 3.0.0
8218      * @category Array
8219      * @param {Array} array The array to query.
8220      * @param {number} [n=1] The number of elements to take.
8221      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
8222      * @returns {Array} Returns the slice of `array`.
8223      * @example
8224      *
8225      * _.takeRight([1, 2, 3]);
8226      * // => [3]
8227      *
8228      * _.takeRight([1, 2, 3], 2);
8229      * // => [2, 3]
8230      *
8231      * _.takeRight([1, 2, 3], 5);
8232      * // => [1, 2, 3]
8233      *
8234      * _.takeRight([1, 2, 3], 0);
8235      * // => []
8236      */
8237     function takeRight(array, n, guard) {
8238       var length = array == null ? 0 : array.length;
8239       if (!length) {
8240         return [];
8241       }
8242       n = (guard || n === undefined) ? 1 : toInteger(n);
8243       n = length - n;
8244       return baseSlice(array, n < 0 ? 0 : n, length);
8245     }
8246
8247     /**
8248      * Creates a slice of `array` with elements taken from the end. Elements are
8249      * taken until `predicate` returns falsey. The predicate is invoked with
8250      * three arguments: (value, index, array).
8251      *
8252      * @static
8253      * @memberOf _
8254      * @since 3.0.0
8255      * @category Array
8256      * @param {Array} array The array to query.
8257      * @param {Function} [predicate=_.identity] The function invoked per iteration.
8258      * @returns {Array} Returns the slice of `array`.
8259      * @example
8260      *
8261      * var users = [
8262      *   { 'user': 'barney',  'active': true },
8263      *   { 'user': 'fred',    'active': false },
8264      *   { 'user': 'pebbles', 'active': false }
8265      * ];
8266      *
8267      * _.takeRightWhile(users, function(o) { return !o.active; });
8268      * // => objects for ['fred', 'pebbles']
8269      *
8270      * // The `_.matches` iteratee shorthand.
8271      * _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
8272      * // => objects for ['pebbles']
8273      *
8274      * // The `_.matchesProperty` iteratee shorthand.
8275      * _.takeRightWhile(users, ['active', false]);
8276      * // => objects for ['fred', 'pebbles']
8277      *
8278      * // The `_.property` iteratee shorthand.
8279      * _.takeRightWhile(users, 'active');
8280      * // => []
8281      */
8282     function takeRightWhile(array, predicate) {
8283       return (array && array.length)
8284         ? baseWhile(array, getIteratee(predicate, 3), false, true)
8285         : [];
8286     }
8287
8288     /**
8289      * Creates a slice of `array` with elements taken from the beginning. Elements
8290      * are taken until `predicate` returns falsey. The predicate is invoked with
8291      * three arguments: (value, index, array).
8292      *
8293      * @static
8294      * @memberOf _
8295      * @since 3.0.0
8296      * @category Array
8297      * @param {Array} array The array to query.
8298      * @param {Function} [predicate=_.identity] The function invoked per iteration.
8299      * @returns {Array} Returns the slice of `array`.
8300      * @example
8301      *
8302      * var users = [
8303      *   { 'user': 'barney',  'active': false },
8304      *   { 'user': 'fred',    'active': false },
8305      *   { 'user': 'pebbles', 'active': true }
8306      * ];
8307      *
8308      * _.takeWhile(users, function(o) { return !o.active; });
8309      * // => objects for ['barney', 'fred']
8310      *
8311      * // The `_.matches` iteratee shorthand.
8312      * _.takeWhile(users, { 'user': 'barney', 'active': false });
8313      * // => objects for ['barney']
8314      *
8315      * // The `_.matchesProperty` iteratee shorthand.
8316      * _.takeWhile(users, ['active', false]);
8317      * // => objects for ['barney', 'fred']
8318      *
8319      * // The `_.property` iteratee shorthand.
8320      * _.takeWhile(users, 'active');
8321      * // => []
8322      */
8323     function takeWhile(array, predicate) {
8324       return (array && array.length)
8325         ? baseWhile(array, getIteratee(predicate, 3))
8326         : [];
8327     }
8328
8329     /**
8330      * Creates an array of unique values, in order, from all given arrays using
8331      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8332      * for equality comparisons.
8333      *
8334      * @static
8335      * @memberOf _
8336      * @since 0.1.0
8337      * @category Array
8338      * @param {...Array} [arrays] The arrays to inspect.
8339      * @returns {Array} Returns the new array of combined values.
8340      * @example
8341      *
8342      * _.union([2], [1, 2]);
8343      * // => [2, 1]
8344      */
8345     var union = baseRest(function(arrays) {
8346       return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
8347     });
8348
8349     /**
8350      * This method is like `_.union` except that it accepts `iteratee` which is
8351      * invoked for each element of each `arrays` to generate the criterion by
8352      * which uniqueness is computed. Result values are chosen from the first
8353      * array in which the value occurs. The iteratee is invoked with one argument:
8354      * (value).
8355      *
8356      * @static
8357      * @memberOf _
8358      * @since 4.0.0
8359      * @category Array
8360      * @param {...Array} [arrays] The arrays to inspect.
8361      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8362      * @returns {Array} Returns the new array of combined values.
8363      * @example
8364      *
8365      * _.unionBy([2.1], [1.2, 2.3], Math.floor);
8366      * // => [2.1, 1.2]
8367      *
8368      * // The `_.property` iteratee shorthand.
8369      * _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
8370      * // => [{ 'x': 1 }, { 'x': 2 }]
8371      */
8372     var unionBy = baseRest(function(arrays) {
8373       var iteratee = last(arrays);
8374       if (isArrayLikeObject(iteratee)) {
8375         iteratee = undefined;
8376       }
8377       return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee, 2));
8378     });
8379
8380     /**
8381      * This method is like `_.union` except that it accepts `comparator` which
8382      * is invoked to compare elements of `arrays`. Result values are chosen from
8383      * the first array in which the value occurs. The comparator is invoked
8384      * with two arguments: (arrVal, othVal).
8385      *
8386      * @static
8387      * @memberOf _
8388      * @since 4.0.0
8389      * @category Array
8390      * @param {...Array} [arrays] The arrays to inspect.
8391      * @param {Function} [comparator] The comparator invoked per element.
8392      * @returns {Array} Returns the new array of combined values.
8393      * @example
8394      *
8395      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
8396      * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
8397      *
8398      * _.unionWith(objects, others, _.isEqual);
8399      * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
8400      */
8401     var unionWith = baseRest(function(arrays) {
8402       var comparator = last(arrays);
8403       comparator = typeof comparator == 'function' ? comparator : undefined;
8404       return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator);
8405     });
8406
8407     /**
8408      * Creates a duplicate-free version of an array, using
8409      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8410      * for equality comparisons, in which only the first occurrence of each element
8411      * is kept. The order of result values is determined by the order they occur
8412      * in the array.
8413      *
8414      * @static
8415      * @memberOf _
8416      * @since 0.1.0
8417      * @category Array
8418      * @param {Array} array The array to inspect.
8419      * @returns {Array} Returns the new duplicate free array.
8420      * @example
8421      *
8422      * _.uniq([2, 1, 2]);
8423      * // => [2, 1]
8424      */
8425     function uniq(array) {
8426       return (array && array.length) ? baseUniq(array) : [];
8427     }
8428
8429     /**
8430      * This method is like `_.uniq` except that it accepts `iteratee` which is
8431      * invoked for each element in `array` to generate the criterion by which
8432      * uniqueness is computed. The order of result values is determined by the
8433      * order they occur in the array. The iteratee is invoked with one argument:
8434      * (value).
8435      *
8436      * @static
8437      * @memberOf _
8438      * @since 4.0.0
8439      * @category Array
8440      * @param {Array} array The array to inspect.
8441      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8442      * @returns {Array} Returns the new duplicate free array.
8443      * @example
8444      *
8445      * _.uniqBy([2.1, 1.2, 2.3], Math.floor);
8446      * // => [2.1, 1.2]
8447      *
8448      * // The `_.property` iteratee shorthand.
8449      * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
8450      * // => [{ 'x': 1 }, { 'x': 2 }]
8451      */
8452     function uniqBy(array, iteratee) {
8453       return (array && array.length) ? baseUniq(array, getIteratee(iteratee, 2)) : [];
8454     }
8455
8456     /**
8457      * This method is like `_.uniq` except that it accepts `comparator` which
8458      * is invoked to compare elements of `array`. The order of result values is
8459      * determined by the order they occur in the array.The comparator is invoked
8460      * with two arguments: (arrVal, othVal).
8461      *
8462      * @static
8463      * @memberOf _
8464      * @since 4.0.0
8465      * @category Array
8466      * @param {Array} array The array to inspect.
8467      * @param {Function} [comparator] The comparator invoked per element.
8468      * @returns {Array} Returns the new duplicate free array.
8469      * @example
8470      *
8471      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
8472      *
8473      * _.uniqWith(objects, _.isEqual);
8474      * // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
8475      */
8476     function uniqWith(array, comparator) {
8477       comparator = typeof comparator == 'function' ? comparator : undefined;
8478       return (array && array.length) ? baseUniq(array, undefined, comparator) : [];
8479     }
8480
8481     /**
8482      * This method is like `_.zip` except that it accepts an array of grouped
8483      * elements and creates an array regrouping the elements to their pre-zip
8484      * configuration.
8485      *
8486      * @static
8487      * @memberOf _
8488      * @since 1.2.0
8489      * @category Array
8490      * @param {Array} array The array of grouped elements to process.
8491      * @returns {Array} Returns the new array of regrouped elements.
8492      * @example
8493      *
8494      * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]);
8495      * // => [['a', 1, true], ['b', 2, false]]
8496      *
8497      * _.unzip(zipped);
8498      * // => [['a', 'b'], [1, 2], [true, false]]
8499      */
8500     function unzip(array) {
8501       if (!(array && array.length)) {
8502         return [];
8503       }
8504       var length = 0;
8505       array = arrayFilter(array, function(group) {
8506         if (isArrayLikeObject(group)) {
8507           length = nativeMax(group.length, length);
8508           return true;
8509         }
8510       });
8511       return baseTimes(length, function(index) {
8512         return arrayMap(array, baseProperty(index));
8513       });
8514     }
8515
8516     /**
8517      * This method is like `_.unzip` except that it accepts `iteratee` to specify
8518      * how regrouped values should be combined. The iteratee is invoked with the
8519      * elements of each group: (...group).
8520      *
8521      * @static
8522      * @memberOf _
8523      * @since 3.8.0
8524      * @category Array
8525      * @param {Array} array The array of grouped elements to process.
8526      * @param {Function} [iteratee=_.identity] The function to combine
8527      *  regrouped values.
8528      * @returns {Array} Returns the new array of regrouped elements.
8529      * @example
8530      *
8531      * var zipped = _.zip([1, 2], [10, 20], [100, 200]);
8532      * // => [[1, 10, 100], [2, 20, 200]]
8533      *
8534      * _.unzipWith(zipped, _.add);
8535      * // => [3, 30, 300]
8536      */
8537     function unzipWith(array, iteratee) {
8538       if (!(array && array.length)) {
8539         return [];
8540       }
8541       var result = unzip(array);
8542       if (iteratee == null) {
8543         return result;
8544       }
8545       return arrayMap(result, function(group) {
8546         return apply(iteratee, undefined, group);
8547       });
8548     }
8549
8550     /**
8551      * Creates an array excluding all given values using
8552      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
8553      * for equality comparisons.
8554      *
8555      * **Note:** Unlike `_.pull`, this method returns a new array.
8556      *
8557      * @static
8558      * @memberOf _
8559      * @since 0.1.0
8560      * @category Array
8561      * @param {Array} array The array to inspect.
8562      * @param {...*} [values] The values to exclude.
8563      * @returns {Array} Returns the new array of filtered values.
8564      * @see _.difference, _.xor
8565      * @example
8566      *
8567      * _.without([2, 1, 2, 3], 1, 2);
8568      * // => [3]
8569      */
8570     var without = baseRest(function(array, values) {
8571       return isArrayLikeObject(array)
8572         ? baseDifference(array, values)
8573         : [];
8574     });
8575
8576     /**
8577      * Creates an array of unique values that is the
8578      * [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
8579      * of the given arrays. The order of result values is determined by the order
8580      * they occur in the arrays.
8581      *
8582      * @static
8583      * @memberOf _
8584      * @since 2.4.0
8585      * @category Array
8586      * @param {...Array} [arrays] The arrays to inspect.
8587      * @returns {Array} Returns the new array of filtered values.
8588      * @see _.difference, _.without
8589      * @example
8590      *
8591      * _.xor([2, 1], [2, 3]);
8592      * // => [1, 3]
8593      */
8594     var xor = baseRest(function(arrays) {
8595       return baseXor(arrayFilter(arrays, isArrayLikeObject));
8596     });
8597
8598     /**
8599      * This method is like `_.xor` except that it accepts `iteratee` which is
8600      * invoked for each element of each `arrays` to generate the criterion by
8601      * which by which they're compared. The order of result values is determined
8602      * by the order they occur in the arrays. The iteratee is invoked with one
8603      * argument: (value).
8604      *
8605      * @static
8606      * @memberOf _
8607      * @since 4.0.0
8608      * @category Array
8609      * @param {...Array} [arrays] The arrays to inspect.
8610      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
8611      * @returns {Array} Returns the new array of filtered values.
8612      * @example
8613      *
8614      * _.xorBy([2.1, 1.2], [2.3, 3.4], Math.floor);
8615      * // => [1.2, 3.4]
8616      *
8617      * // The `_.property` iteratee shorthand.
8618      * _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
8619      * // => [{ 'x': 2 }]
8620      */
8621     var xorBy = baseRest(function(arrays) {
8622       var iteratee = last(arrays);
8623       if (isArrayLikeObject(iteratee)) {
8624         iteratee = undefined;
8625       }
8626       return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee, 2));
8627     });
8628
8629     /**
8630      * This method is like `_.xor` except that it accepts `comparator` which is
8631      * invoked to compare elements of `arrays`. The order of result values is
8632      * determined by the order they occur in the arrays. The comparator is invoked
8633      * with two arguments: (arrVal, othVal).
8634      *
8635      * @static
8636      * @memberOf _
8637      * @since 4.0.0
8638      * @category Array
8639      * @param {...Array} [arrays] The arrays to inspect.
8640      * @param {Function} [comparator] The comparator invoked per element.
8641      * @returns {Array} Returns the new array of filtered values.
8642      * @example
8643      *
8644      * var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
8645      * var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
8646      *
8647      * _.xorWith(objects, others, _.isEqual);
8648      * // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
8649      */
8650     var xorWith = baseRest(function(arrays) {
8651       var comparator = last(arrays);
8652       comparator = typeof comparator == 'function' ? comparator : undefined;
8653       return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator);
8654     });
8655
8656     /**
8657      * Creates an array of grouped elements, the first of which contains the
8658      * first elements of the given arrays, the second of which contains the
8659      * second elements of the given arrays, and so on.
8660      *
8661      * @static
8662      * @memberOf _
8663      * @since 0.1.0
8664      * @category Array
8665      * @param {...Array} [arrays] The arrays to process.
8666      * @returns {Array} Returns the new array of grouped elements.
8667      * @example
8668      *
8669      * _.zip(['a', 'b'], [1, 2], [true, false]);
8670      * // => [['a', 1, true], ['b', 2, false]]
8671      */
8672     var zip = baseRest(unzip);
8673
8674     /**
8675      * This method is like `_.fromPairs` except that it accepts two arrays,
8676      * one of property identifiers and one of corresponding values.
8677      *
8678      * @static
8679      * @memberOf _
8680      * @since 0.4.0
8681      * @category Array
8682      * @param {Array} [props=[]] The property identifiers.
8683      * @param {Array} [values=[]] The property values.
8684      * @returns {Object} Returns the new object.
8685      * @example
8686      *
8687      * _.zipObject(['a', 'b'], [1, 2]);
8688      * // => { 'a': 1, 'b': 2 }
8689      */
8690     function zipObject(props, values) {
8691       return baseZipObject(props || [], values || [], assignValue);
8692     }
8693
8694     /**
8695      * This method is like `_.zipObject` except that it supports property paths.
8696      *
8697      * @static
8698      * @memberOf _
8699      * @since 4.1.0
8700      * @category Array
8701      * @param {Array} [props=[]] The property identifiers.
8702      * @param {Array} [values=[]] The property values.
8703      * @returns {Object} Returns the new object.
8704      * @example
8705      *
8706      * _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
8707      * // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
8708      */
8709     function zipObjectDeep(props, values) {
8710       return baseZipObject(props || [], values || [], baseSet);
8711     }
8712
8713     /**
8714      * This method is like `_.zip` except that it accepts `iteratee` to specify
8715      * how grouped values should be combined. The iteratee is invoked with the
8716      * elements of each group: (...group).
8717      *
8718      * @static
8719      * @memberOf _
8720      * @since 3.8.0
8721      * @category Array
8722      * @param {...Array} [arrays] The arrays to process.
8723      * @param {Function} [iteratee=_.identity] The function to combine
8724      *  grouped values.
8725      * @returns {Array} Returns the new array of grouped elements.
8726      * @example
8727      *
8728      * _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
8729      *   return a + b + c;
8730      * });
8731      * // => [111, 222]
8732      */
8733     var zipWith = baseRest(function(arrays) {
8734       var length = arrays.length,
8735           iteratee = length > 1 ? arrays[length - 1] : undefined;
8736
8737       iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined;
8738       return unzipWith(arrays, iteratee);
8739     });
8740
8741     /*------------------------------------------------------------------------*/
8742
8743     /**
8744      * Creates a `lodash` wrapper instance that wraps `value` with explicit method
8745      * chain sequences enabled. The result of such sequences must be unwrapped
8746      * with `_#value`.
8747      *
8748      * @static
8749      * @memberOf _
8750      * @since 1.3.0
8751      * @category Seq
8752      * @param {*} value The value to wrap.
8753      * @returns {Object} Returns the new `lodash` wrapper instance.
8754      * @example
8755      *
8756      * var users = [
8757      *   { 'user': 'barney',  'age': 36 },
8758      *   { 'user': 'fred',    'age': 40 },
8759      *   { 'user': 'pebbles', 'age': 1 }
8760      * ];
8761      *
8762      * var youngest = _
8763      *   .chain(users)
8764      *   .sortBy('age')
8765      *   .map(function(o) {
8766      *     return o.user + ' is ' + o.age;
8767      *   })
8768      *   .head()
8769      *   .value();
8770      * // => 'pebbles is 1'
8771      */
8772     function chain(value) {
8773       var result = lodash(value);
8774       result.__chain__ = true;
8775       return result;
8776     }
8777
8778     /**
8779      * This method invokes `interceptor` and returns `value`. The interceptor
8780      * is invoked with one argument; (value). The purpose of this method is to
8781      * "tap into" a method chain sequence in order to modify intermediate results.
8782      *
8783      * @static
8784      * @memberOf _
8785      * @since 0.1.0
8786      * @category Seq
8787      * @param {*} value The value to provide to `interceptor`.
8788      * @param {Function} interceptor The function to invoke.
8789      * @returns {*} Returns `value`.
8790      * @example
8791      *
8792      * _([1, 2, 3])
8793      *  .tap(function(array) {
8794      *    // Mutate input array.
8795      *    array.pop();
8796      *  })
8797      *  .reverse()
8798      *  .value();
8799      * // => [2, 1]
8800      */
8801     function tap(value, interceptor) {
8802       interceptor(value);
8803       return value;
8804     }
8805
8806     /**
8807      * This method is like `_.tap` except that it returns the result of `interceptor`.
8808      * The purpose of this method is to "pass thru" values replacing intermediate
8809      * results in a method chain sequence.
8810      *
8811      * @static
8812      * @memberOf _
8813      * @since 3.0.0
8814      * @category Seq
8815      * @param {*} value The value to provide to `interceptor`.
8816      * @param {Function} interceptor The function to invoke.
8817      * @returns {*} Returns the result of `interceptor`.
8818      * @example
8819      *
8820      * _('  abc  ')
8821      *  .chain()
8822      *  .trim()
8823      *  .thru(function(value) {
8824      *    return [value];
8825      *  })
8826      *  .value();
8827      * // => ['abc']
8828      */
8829     function thru(value, interceptor) {
8830       return interceptor(value);
8831     }
8832
8833     /**
8834      * This method is the wrapper version of `_.at`.
8835      *
8836      * @name at
8837      * @memberOf _
8838      * @since 1.0.0
8839      * @category Seq
8840      * @param {...(string|string[])} [paths] The property paths to pick.
8841      * @returns {Object} Returns the new `lodash` wrapper instance.
8842      * @example
8843      *
8844      * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
8845      *
8846      * _(object).at(['a[0].b.c', 'a[1]']).value();
8847      * // => [3, 4]
8848      */
8849     var wrapperAt = flatRest(function(paths) {
8850       var length = paths.length,
8851           start = length ? paths[0] : 0,
8852           value = this.__wrapped__,
8853           interceptor = function(object) { return baseAt(object, paths); };
8854
8855       if (length > 1 || this.__actions__.length ||
8856           !(value instanceof LazyWrapper) || !isIndex(start)) {
8857         return this.thru(interceptor);
8858       }
8859       value = value.slice(start, +start + (length ? 1 : 0));
8860       value.__actions__.push({
8861         'func': thru,
8862         'args': [interceptor],
8863         'thisArg': undefined
8864       });
8865       return new LodashWrapper(value, this.__chain__).thru(function(array) {
8866         if (length && !array.length) {
8867           array.push(undefined);
8868         }
8869         return array;
8870       });
8871     });
8872
8873     /**
8874      * Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
8875      *
8876      * @name chain
8877      * @memberOf _
8878      * @since 0.1.0
8879      * @category Seq
8880      * @returns {Object} Returns the new `lodash` wrapper instance.
8881      * @example
8882      *
8883      * var users = [
8884      *   { 'user': 'barney', 'age': 36 },
8885      *   { 'user': 'fred',   'age': 40 }
8886      * ];
8887      *
8888      * // A sequence without explicit chaining.
8889      * _(users).head();
8890      * // => { 'user': 'barney', 'age': 36 }
8891      *
8892      * // A sequence with explicit chaining.
8893      * _(users)
8894      *   .chain()
8895      *   .head()
8896      *   .pick('user')
8897      *   .value();
8898      * // => { 'user': 'barney' }
8899      */
8900     function wrapperChain() {
8901       return chain(this);
8902     }
8903
8904     /**
8905      * Executes the chain sequence and returns the wrapped result.
8906      *
8907      * @name commit
8908      * @memberOf _
8909      * @since 3.2.0
8910      * @category Seq
8911      * @returns {Object} Returns the new `lodash` wrapper instance.
8912      * @example
8913      *
8914      * var array = [1, 2];
8915      * var wrapped = _(array).push(3);
8916      *
8917      * console.log(array);
8918      * // => [1, 2]
8919      *
8920      * wrapped = wrapped.commit();
8921      * console.log(array);
8922      * // => [1, 2, 3]
8923      *
8924      * wrapped.last();
8925      * // => 3
8926      *
8927      * console.log(array);
8928      * // => [1, 2, 3]
8929      */
8930     function wrapperCommit() {
8931       return new LodashWrapper(this.value(), this.__chain__);
8932     }
8933
8934     /**
8935      * Gets the next value on a wrapped object following the
8936      * [iterator protocol](https://mdn.io/iteration_protocols#iterator).
8937      *
8938      * @name next
8939      * @memberOf _
8940      * @since 4.0.0
8941      * @category Seq
8942      * @returns {Object} Returns the next iterator value.
8943      * @example
8944      *
8945      * var wrapped = _([1, 2]);
8946      *
8947      * wrapped.next();
8948      * // => { 'done': false, 'value': 1 }
8949      *
8950      * wrapped.next();
8951      * // => { 'done': false, 'value': 2 }
8952      *
8953      * wrapped.next();
8954      * // => { 'done': true, 'value': undefined }
8955      */
8956     function wrapperNext() {
8957       if (this.__values__ === undefined) {
8958         this.__values__ = toArray(this.value());
8959       }
8960       var done = this.__index__ >= this.__values__.length,
8961           value = done ? undefined : this.__values__[this.__index__++];
8962
8963       return { 'done': done, 'value': value };
8964     }
8965
8966     /**
8967      * Enables the wrapper to be iterable.
8968      *
8969      * @name Symbol.iterator
8970      * @memberOf _
8971      * @since 4.0.0
8972      * @category Seq
8973      * @returns {Object} Returns the wrapper object.
8974      * @example
8975      *
8976      * var wrapped = _([1, 2]);
8977      *
8978      * wrapped[Symbol.iterator]() === wrapped;
8979      * // => true
8980      *
8981      * Array.from(wrapped);
8982      * // => [1, 2]
8983      */
8984     function wrapperToIterator() {
8985       return this;
8986     }
8987
8988     /**
8989      * Creates a clone of the chain sequence planting `value` as the wrapped value.
8990      *
8991      * @name plant
8992      * @memberOf _
8993      * @since 3.2.0
8994      * @category Seq
8995      * @param {*} value The value to plant.
8996      * @returns {Object} Returns the new `lodash` wrapper instance.
8997      * @example
8998      *
8999      * function square(n) {
9000      *   return n * n;
9001      * }
9002      *
9003      * var wrapped = _([1, 2]).map(square);
9004      * var other = wrapped.plant([3, 4]);
9005      *
9006      * other.value();
9007      * // => [9, 16]
9008      *
9009      * wrapped.value();
9010      * // => [1, 4]
9011      */
9012     function wrapperPlant(value) {
9013       var result,
9014           parent = this;
9015
9016       while (parent instanceof baseLodash) {
9017         var clone = wrapperClone(parent);
9018         clone.__index__ = 0;
9019         clone.__values__ = undefined;
9020         if (result) {
9021           previous.__wrapped__ = clone;
9022         } else {
9023           result = clone;
9024         }
9025         var previous = clone;
9026         parent = parent.__wrapped__;
9027       }
9028       previous.__wrapped__ = value;
9029       return result;
9030     }
9031
9032     /**
9033      * This method is the wrapper version of `_.reverse`.
9034      *
9035      * **Note:** This method mutates the wrapped array.
9036      *
9037      * @name reverse
9038      * @memberOf _
9039      * @since 0.1.0
9040      * @category Seq
9041      * @returns {Object} Returns the new `lodash` wrapper instance.
9042      * @example
9043      *
9044      * var array = [1, 2, 3];
9045      *
9046      * _(array).reverse().value()
9047      * // => [3, 2, 1]
9048      *
9049      * console.log(array);
9050      * // => [3, 2, 1]
9051      */
9052     function wrapperReverse() {
9053       var value = this.__wrapped__;
9054       if (value instanceof LazyWrapper) {
9055         var wrapped = value;
9056         if (this.__actions__.length) {
9057           wrapped = new LazyWrapper(this);
9058         }
9059         wrapped = wrapped.reverse();
9060         wrapped.__actions__.push({
9061           'func': thru,
9062           'args': [reverse],
9063           'thisArg': undefined
9064         });
9065         return new LodashWrapper(wrapped, this.__chain__);
9066       }
9067       return this.thru(reverse);
9068     }
9069
9070     /**
9071      * Executes the chain sequence to resolve the unwrapped value.
9072      *
9073      * @name value
9074      * @memberOf _
9075      * @since 0.1.0
9076      * @alias toJSON, valueOf
9077      * @category Seq
9078      * @returns {*} Returns the resolved unwrapped value.
9079      * @example
9080      *
9081      * _([1, 2, 3]).value();
9082      * // => [1, 2, 3]
9083      */
9084     function wrapperValue() {
9085       return baseWrapperValue(this.__wrapped__, this.__actions__);
9086     }
9087
9088     /*------------------------------------------------------------------------*/
9089
9090     /**
9091      * Creates an object composed of keys generated from the results of running
9092      * each element of `collection` thru `iteratee`. The corresponding value of
9093      * each key is the number of times the key was returned by `iteratee`. The
9094      * iteratee is invoked with one argument: (value).
9095      *
9096      * @static
9097      * @memberOf _
9098      * @since 0.5.0
9099      * @category Collection
9100      * @param {Array|Object} collection The collection to iterate over.
9101      * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
9102      * @returns {Object} Returns the composed aggregate object.
9103      * @example
9104      *
9105      * _.countBy([6.1, 4.2, 6.3], Math.floor);
9106      * // => { '4': 1, '6': 2 }
9107      *
9108      * // The `_.property` iteratee shorthand.
9109      * _.countBy(['one', 'two', 'three'], 'length');
9110      * // => { '3': 2, '5': 1 }
9111      */
9112     var countBy = createAggregator(function(result, value, key) {
9113       if (hasOwnProperty.call(result, key)) {
9114         ++result[key];
9115       } else {
9116         baseAssignValue(result, key, 1);
9117       }
9118     });
9119
9120     /**
9121      * Checks if `predicate` returns truthy for **all** elements of `collection`.
9122      * Iteration is stopped once `predicate` returns falsey. The predicate is
9123      * invoked with three arguments: (value, index|key, collection).
9124      *
9125      * **Note:** This method returns `true` for
9126      * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because
9127      * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of
9128      * elements of empty collections.
9129      *
9130      * @static
9131      * @memberOf _
9132      * @since 0.1.0
9133      * @category Collection
9134      * @param {Array|Object} collection The collection to iterate over.
9135      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9136      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9137      * @returns {boolean} Returns `true` if all elements pass the predicate check,
9138      *  else `false`.
9139      * @example
9140      *
9141      * _.every([true, 1, null, 'yes'], Boolean);
9142      * // => false
9143      *
9144      * var users = [
9145      *   { 'user': 'barney', 'age': 36, 'active': false },
9146      *   { 'user': 'fred',   'age': 40, 'active': false }
9147      * ];
9148      *
9149      * // The `_.matches` iteratee shorthand.
9150      * _.every(users, { 'user': 'barney', 'active': false });
9151      * // => false
9152      *
9153      * // The `_.matchesProperty` iteratee shorthand.
9154      * _.every(users, ['active', false]);
9155      * // => true
9156      *
9157      * // The `_.property` iteratee shorthand.
9158      * _.every(users, 'active');
9159      * // => false
9160      */
9161     function every(collection, predicate, guard) {
9162       var func = isArray(collection) ? arrayEvery : baseEvery;
9163       if (guard && isIterateeCall(collection, predicate, guard)) {
9164         predicate = undefined;
9165       }
9166       return func(collection, getIteratee(predicate, 3));
9167     }
9168
9169     /**
9170      * Iterates over elements of `collection`, returning an array of all elements
9171      * `predicate` returns truthy for. The predicate is invoked with three
9172      * arguments: (value, index|key, collection).
9173      *
9174      * **Note:** Unlike `_.remove`, this method returns a new array.
9175      *
9176      * @static
9177      * @memberOf _
9178      * @since 0.1.0
9179      * @category Collection
9180      * @param {Array|Object} collection The collection to iterate over.
9181      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9182      * @returns {Array} Returns the new filtered array.
9183      * @see _.reject
9184      * @example
9185      *
9186      * var users = [
9187      *   { 'user': 'barney', 'age': 36, 'active': true },
9188      *   { 'user': 'fred',   'age': 40, 'active': false }
9189      * ];
9190      *
9191      * _.filter(users, function(o) { return !o.active; });
9192      * // => objects for ['fred']
9193      *
9194      * // The `_.matches` iteratee shorthand.
9195      * _.filter(users, { 'age': 36, 'active': true });
9196      * // => objects for ['barney']
9197      *
9198      * // The `_.matchesProperty` iteratee shorthand.
9199      * _.filter(users, ['active', false]);
9200      * // => objects for ['fred']
9201      *
9202      * // The `_.property` iteratee shorthand.
9203      * _.filter(users, 'active');
9204      * // => objects for ['barney']
9205      */
9206     function filter(collection, predicate) {
9207       var func = isArray(collection) ? arrayFilter : baseFilter;
9208       return func(collection, getIteratee(predicate, 3));
9209     }
9210
9211     /**
9212      * Iterates over elements of `collection`, returning the first element
9213      * `predicate` returns truthy for. The predicate is invoked with three
9214      * arguments: (value, index|key, collection).
9215      *
9216      * @static
9217      * @memberOf _
9218      * @since 0.1.0
9219      * @category Collection
9220      * @param {Array|Object} collection The collection to inspect.
9221      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9222      * @param {number} [fromIndex=0] The index to search from.
9223      * @returns {*} Returns the matched element, else `undefined`.
9224      * @example
9225      *
9226      * var users = [
9227      *   { 'user': 'barney',  'age': 36, 'active': true },
9228      *   { 'user': 'fred',    'age': 40, 'active': false },
9229      *   { 'user': 'pebbles', 'age': 1,  'active': true }
9230      * ];
9231      *
9232      * _.find(users, function(o) { return o.age < 40; });
9233      * // => object for 'barney'
9234      *
9235      * // The `_.matches` iteratee shorthand.
9236      * _.find(users, { 'age': 1, 'active': true });
9237      * // => object for 'pebbles'
9238      *
9239      * // The `_.matchesProperty` iteratee shorthand.
9240      * _.find(users, ['active', false]);
9241      * // => object for 'fred'
9242      *
9243      * // The `_.property` iteratee shorthand.
9244      * _.find(users, 'active');
9245      * // => object for 'barney'
9246      */
9247     var find = createFind(findIndex);
9248
9249     /**
9250      * This method is like `_.find` except that it iterates over elements of
9251      * `collection` from right to left.
9252      *
9253      * @static
9254      * @memberOf _
9255      * @since 2.0.0
9256      * @category Collection
9257      * @param {Array|Object} collection The collection to inspect.
9258      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9259      * @param {number} [fromIndex=collection.length-1] The index to search from.
9260      * @returns {*} Returns the matched element, else `undefined`.
9261      * @example
9262      *
9263      * _.findLast([1, 2, 3, 4], function(n) {
9264      *   return n % 2 == 1;
9265      * });
9266      * // => 3
9267      */
9268     var findLast = createFind(findLastIndex);
9269
9270     /**
9271      * Creates a flattened array of values by running each element in `collection`
9272      * thru `iteratee` and flattening the mapped results. The iteratee is invoked
9273      * with three arguments: (value, index|key, collection).
9274      *
9275      * @static
9276      * @memberOf _
9277      * @since 4.0.0
9278      * @category Collection
9279      * @param {Array|Object} collection The collection to iterate over.
9280      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9281      * @returns {Array} Returns the new flattened array.
9282      * @example
9283      *
9284      * function duplicate(n) {
9285      *   return [n, n];
9286      * }
9287      *
9288      * _.flatMap([1, 2], duplicate);
9289      * // => [1, 1, 2, 2]
9290      */
9291     function flatMap(collection, iteratee) {
9292       return baseFlatten(map(collection, iteratee), 1);
9293     }
9294
9295     /**
9296      * This method is like `_.flatMap` except that it recursively flattens the
9297      * mapped results.
9298      *
9299      * @static
9300      * @memberOf _
9301      * @since 4.7.0
9302      * @category Collection
9303      * @param {Array|Object} collection The collection to iterate over.
9304      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9305      * @returns {Array} Returns the new flattened array.
9306      * @example
9307      *
9308      * function duplicate(n) {
9309      *   return [[[n, n]]];
9310      * }
9311      *
9312      * _.flatMapDeep([1, 2], duplicate);
9313      * // => [1, 1, 2, 2]
9314      */
9315     function flatMapDeep(collection, iteratee) {
9316       return baseFlatten(map(collection, iteratee), INFINITY);
9317     }
9318
9319     /**
9320      * This method is like `_.flatMap` except that it recursively flattens the
9321      * mapped results up to `depth` times.
9322      *
9323      * @static
9324      * @memberOf _
9325      * @since 4.7.0
9326      * @category Collection
9327      * @param {Array|Object} collection The collection to iterate over.
9328      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9329      * @param {number} [depth=1] The maximum recursion depth.
9330      * @returns {Array} Returns the new flattened array.
9331      * @example
9332      *
9333      * function duplicate(n) {
9334      *   return [[[n, n]]];
9335      * }
9336      *
9337      * _.flatMapDepth([1, 2], duplicate, 2);
9338      * // => [[1, 1], [2, 2]]
9339      */
9340     function flatMapDepth(collection, iteratee, depth) {
9341       depth = depth === undefined ? 1 : toInteger(depth);
9342       return baseFlatten(map(collection, iteratee), depth);
9343     }
9344
9345     /**
9346      * Iterates over elements of `collection` and invokes `iteratee` for each element.
9347      * The iteratee is invoked with three arguments: (value, index|key, collection).
9348      * Iteratee functions may exit iteration early by explicitly returning `false`.
9349      *
9350      * **Note:** As with other "Collections" methods, objects with a "length"
9351      * property are iterated like arrays. To avoid this behavior use `_.forIn`
9352      * or `_.forOwn` for object iteration.
9353      *
9354      * @static
9355      * @memberOf _
9356      * @since 0.1.0
9357      * @alias each
9358      * @category Collection
9359      * @param {Array|Object} collection The collection to iterate over.
9360      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9361      * @returns {Array|Object} Returns `collection`.
9362      * @see _.forEachRight
9363      * @example
9364      *
9365      * _.forEach([1, 2], function(value) {
9366      *   console.log(value);
9367      * });
9368      * // => Logs `1` then `2`.
9369      *
9370      * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
9371      *   console.log(key);
9372      * });
9373      * // => Logs 'a' then 'b' (iteration order is not guaranteed).
9374      */
9375     function forEach(collection, iteratee) {
9376       var func = isArray(collection) ? arrayEach : baseEach;
9377       return func(collection, getIteratee(iteratee, 3));
9378     }
9379
9380     /**
9381      * This method is like `_.forEach` except that it iterates over elements of
9382      * `collection` from right to left.
9383      *
9384      * @static
9385      * @memberOf _
9386      * @since 2.0.0
9387      * @alias eachRight
9388      * @category Collection
9389      * @param {Array|Object} collection The collection to iterate over.
9390      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9391      * @returns {Array|Object} Returns `collection`.
9392      * @see _.forEach
9393      * @example
9394      *
9395      * _.forEachRight([1, 2], function(value) {
9396      *   console.log(value);
9397      * });
9398      * // => Logs `2` then `1`.
9399      */
9400     function forEachRight(collection, iteratee) {
9401       var func = isArray(collection) ? arrayEachRight : baseEachRight;
9402       return func(collection, getIteratee(iteratee, 3));
9403     }
9404
9405     /**
9406      * Creates an object composed of keys generated from the results of running
9407      * each element of `collection` thru `iteratee`. The order of grouped values
9408      * is determined by the order they occur in `collection`. The corresponding
9409      * value of each key is an array of elements responsible for generating the
9410      * key. The iteratee is invoked with one argument: (value).
9411      *
9412      * @static
9413      * @memberOf _
9414      * @since 0.1.0
9415      * @category Collection
9416      * @param {Array|Object} collection The collection to iterate over.
9417      * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
9418      * @returns {Object} Returns the composed aggregate object.
9419      * @example
9420      *
9421      * _.groupBy([6.1, 4.2, 6.3], Math.floor);
9422      * // => { '4': [4.2], '6': [6.1, 6.3] }
9423      *
9424      * // The `_.property` iteratee shorthand.
9425      * _.groupBy(['one', 'two', 'three'], 'length');
9426      * // => { '3': ['one', 'two'], '5': ['three'] }
9427      */
9428     var groupBy = createAggregator(function(result, value, key) {
9429       if (hasOwnProperty.call(result, key)) {
9430         result[key].push(value);
9431       } else {
9432         baseAssignValue(result, key, [value]);
9433       }
9434     });
9435
9436     /**
9437      * Checks if `value` is in `collection`. If `collection` is a string, it's
9438      * checked for a substring of `value`, otherwise
9439      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
9440      * is used for equality comparisons. If `fromIndex` is negative, it's used as
9441      * the offset from the end of `collection`.
9442      *
9443      * @static
9444      * @memberOf _
9445      * @since 0.1.0
9446      * @category Collection
9447      * @param {Array|Object|string} collection The collection to inspect.
9448      * @param {*} value The value to search for.
9449      * @param {number} [fromIndex=0] The index to search from.
9450      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
9451      * @returns {boolean} Returns `true` if `value` is found, else `false`.
9452      * @example
9453      *
9454      * _.includes([1, 2, 3], 1);
9455      * // => true
9456      *
9457      * _.includes([1, 2, 3], 1, 2);
9458      * // => false
9459      *
9460      * _.includes({ 'a': 1, 'b': 2 }, 1);
9461      * // => true
9462      *
9463      * _.includes('abcd', 'bc');
9464      * // => true
9465      */
9466     function includes(collection, value, fromIndex, guard) {
9467       collection = isArrayLike(collection) ? collection : values(collection);
9468       fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;
9469
9470       var length = collection.length;
9471       if (fromIndex < 0) {
9472         fromIndex = nativeMax(length + fromIndex, 0);
9473       }
9474       return isString(collection)
9475         ? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
9476         : (!!length && baseIndexOf(collection, value, fromIndex) > -1);
9477     }
9478
9479     /**
9480      * Invokes the method at `path` of each element in `collection`, returning
9481      * an array of the results of each invoked method. Any additional arguments
9482      * are provided to each invoked method. If `path` is a function, it's invoked
9483      * for, and `this` bound to, each element in `collection`.
9484      *
9485      * @static
9486      * @memberOf _
9487      * @since 4.0.0
9488      * @category Collection
9489      * @param {Array|Object} collection The collection to iterate over.
9490      * @param {Array|Function|string} path The path of the method to invoke or
9491      *  the function invoked per iteration.
9492      * @param {...*} [args] The arguments to invoke each method with.
9493      * @returns {Array} Returns the array of results.
9494      * @example
9495      *
9496      * _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
9497      * // => [[1, 5, 7], [1, 2, 3]]
9498      *
9499      * _.invokeMap([123, 456], String.prototype.split, '');
9500      * // => [['1', '2', '3'], ['4', '5', '6']]
9501      */
9502     var invokeMap = baseRest(function(collection, path, args) {
9503       var index = -1,
9504           isFunc = typeof path == 'function',
9505           result = isArrayLike(collection) ? Array(collection.length) : [];
9506
9507       baseEach(collection, function(value) {
9508         result[++index] = isFunc ? apply(path, value, args) : baseInvoke(value, path, args);
9509       });
9510       return result;
9511     });
9512
9513     /**
9514      * Creates an object composed of keys generated from the results of running
9515      * each element of `collection` thru `iteratee`. The corresponding value of
9516      * each key is the last element responsible for generating the key. The
9517      * iteratee is invoked with one argument: (value).
9518      *
9519      * @static
9520      * @memberOf _
9521      * @since 4.0.0
9522      * @category Collection
9523      * @param {Array|Object} collection The collection to iterate over.
9524      * @param {Function} [iteratee=_.identity] The iteratee to transform keys.
9525      * @returns {Object} Returns the composed aggregate object.
9526      * @example
9527      *
9528      * var array = [
9529      *   { 'dir': 'left', 'code': 97 },
9530      *   { 'dir': 'right', 'code': 100 }
9531      * ];
9532      *
9533      * _.keyBy(array, function(o) {
9534      *   return String.fromCharCode(o.code);
9535      * });
9536      * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
9537      *
9538      * _.keyBy(array, 'dir');
9539      * // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
9540      */
9541     var keyBy = createAggregator(function(result, value, key) {
9542       baseAssignValue(result, key, value);
9543     });
9544
9545     /**
9546      * Creates an array of values by running each element in `collection` thru
9547      * `iteratee`. The iteratee is invoked with three arguments:
9548      * (value, index|key, collection).
9549      *
9550      * Many lodash methods are guarded to work as iteratees for methods like
9551      * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
9552      *
9553      * The guarded methods are:
9554      * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
9555      * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
9556      * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
9557      * `template`, `trim`, `trimEnd`, `trimStart`, and `words`
9558      *
9559      * @static
9560      * @memberOf _
9561      * @since 0.1.0
9562      * @category Collection
9563      * @param {Array|Object} collection The collection to iterate over.
9564      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9565      * @returns {Array} Returns the new mapped array.
9566      * @example
9567      *
9568      * function square(n) {
9569      *   return n * n;
9570      * }
9571      *
9572      * _.map([4, 8], square);
9573      * // => [16, 64]
9574      *
9575      * _.map({ 'a': 4, 'b': 8 }, square);
9576      * // => [16, 64] (iteration order is not guaranteed)
9577      *
9578      * var users = [
9579      *   { 'user': 'barney' },
9580      *   { 'user': 'fred' }
9581      * ];
9582      *
9583      * // The `_.property` iteratee shorthand.
9584      * _.map(users, 'user');
9585      * // => ['barney', 'fred']
9586      */
9587     function map(collection, iteratee) {
9588       var func = isArray(collection) ? arrayMap : baseMap;
9589       return func(collection, getIteratee(iteratee, 3));
9590     }
9591
9592     /**
9593      * This method is like `_.sortBy` except that it allows specifying the sort
9594      * orders of the iteratees to sort by. If `orders` is unspecified, all values
9595      * are sorted in ascending order. Otherwise, specify an order of "desc" for
9596      * descending or "asc" for ascending sort order of corresponding values.
9597      *
9598      * @static
9599      * @memberOf _
9600      * @since 4.0.0
9601      * @category Collection
9602      * @param {Array|Object} collection The collection to iterate over.
9603      * @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]]
9604      *  The iteratees to sort by.
9605      * @param {string[]} [orders] The sort orders of `iteratees`.
9606      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
9607      * @returns {Array} Returns the new sorted array.
9608      * @example
9609      *
9610      * var users = [
9611      *   { 'user': 'fred',   'age': 48 },
9612      *   { 'user': 'barney', 'age': 34 },
9613      *   { 'user': 'fred',   'age': 40 },
9614      *   { 'user': 'barney', 'age': 36 }
9615      * ];
9616      *
9617      * // Sort by `user` in ascending order and by `age` in descending order.
9618      * _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
9619      * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
9620      */
9621     function orderBy(collection, iteratees, orders, guard) {
9622       if (collection == null) {
9623         return [];
9624       }
9625       if (!isArray(iteratees)) {
9626         iteratees = iteratees == null ? [] : [iteratees];
9627       }
9628       orders = guard ? undefined : orders;
9629       if (!isArray(orders)) {
9630         orders = orders == null ? [] : [orders];
9631       }
9632       return baseOrderBy(collection, iteratees, orders);
9633     }
9634
9635     /**
9636      * Creates an array of elements split into two groups, the first of which
9637      * contains elements `predicate` returns truthy for, the second of which
9638      * contains elements `predicate` returns falsey for. The predicate is
9639      * invoked with one argument: (value).
9640      *
9641      * @static
9642      * @memberOf _
9643      * @since 3.0.0
9644      * @category Collection
9645      * @param {Array|Object} collection The collection to iterate over.
9646      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9647      * @returns {Array} Returns the array of grouped elements.
9648      * @example
9649      *
9650      * var users = [
9651      *   { 'user': 'barney',  'age': 36, 'active': false },
9652      *   { 'user': 'fred',    'age': 40, 'active': true },
9653      *   { 'user': 'pebbles', 'age': 1,  'active': false }
9654      * ];
9655      *
9656      * _.partition(users, function(o) { return o.active; });
9657      * // => objects for [['fred'], ['barney', 'pebbles']]
9658      *
9659      * // The `_.matches` iteratee shorthand.
9660      * _.partition(users, { 'age': 1, 'active': false });
9661      * // => objects for [['pebbles'], ['barney', 'fred']]
9662      *
9663      * // The `_.matchesProperty` iteratee shorthand.
9664      * _.partition(users, ['active', false]);
9665      * // => objects for [['barney', 'pebbles'], ['fred']]
9666      *
9667      * // The `_.property` iteratee shorthand.
9668      * _.partition(users, 'active');
9669      * // => objects for [['fred'], ['barney', 'pebbles']]
9670      */
9671     var partition = createAggregator(function(result, value, key) {
9672       result[key ? 0 : 1].push(value);
9673     }, function() { return [[], []]; });
9674
9675     /**
9676      * Reduces `collection` to a value which is the accumulated result of running
9677      * each element in `collection` thru `iteratee`, where each successive
9678      * invocation is supplied the return value of the previous. If `accumulator`
9679      * is not given, the first element of `collection` is used as the initial
9680      * value. The iteratee is invoked with four arguments:
9681      * (accumulator, value, index|key, collection).
9682      *
9683      * Many lodash methods are guarded to work as iteratees for methods like
9684      * `_.reduce`, `_.reduceRight`, and `_.transform`.
9685      *
9686      * The guarded methods are:
9687      * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
9688      * and `sortBy`
9689      *
9690      * @static
9691      * @memberOf _
9692      * @since 0.1.0
9693      * @category Collection
9694      * @param {Array|Object} collection The collection to iterate over.
9695      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9696      * @param {*} [accumulator] The initial value.
9697      * @returns {*} Returns the accumulated value.
9698      * @see _.reduceRight
9699      * @example
9700      *
9701      * _.reduce([1, 2], function(sum, n) {
9702      *   return sum + n;
9703      * }, 0);
9704      * // => 3
9705      *
9706      * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
9707      *   (result[value] || (result[value] = [])).push(key);
9708      *   return result;
9709      * }, {});
9710      * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
9711      */
9712     function reduce(collection, iteratee, accumulator) {
9713       var func = isArray(collection) ? arrayReduce : baseReduce,
9714           initAccum = arguments.length < 3;
9715
9716       return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
9717     }
9718
9719     /**
9720      * This method is like `_.reduce` except that it iterates over elements of
9721      * `collection` from right to left.
9722      *
9723      * @static
9724      * @memberOf _
9725      * @since 0.1.0
9726      * @category Collection
9727      * @param {Array|Object} collection The collection to iterate over.
9728      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
9729      * @param {*} [accumulator] The initial value.
9730      * @returns {*} Returns the accumulated value.
9731      * @see _.reduce
9732      * @example
9733      *
9734      * var array = [[0, 1], [2, 3], [4, 5]];
9735      *
9736      * _.reduceRight(array, function(flattened, other) {
9737      *   return flattened.concat(other);
9738      * }, []);
9739      * // => [4, 5, 2, 3, 0, 1]
9740      */
9741     function reduceRight(collection, iteratee, accumulator) {
9742       var func = isArray(collection) ? arrayReduceRight : baseReduce,
9743           initAccum = arguments.length < 3;
9744
9745       return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight);
9746     }
9747
9748     /**
9749      * The opposite of `_.filter`; this method returns the elements of `collection`
9750      * that `predicate` does **not** return truthy for.
9751      *
9752      * @static
9753      * @memberOf _
9754      * @since 0.1.0
9755      * @category Collection
9756      * @param {Array|Object} collection The collection to iterate over.
9757      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9758      * @returns {Array} Returns the new filtered array.
9759      * @see _.filter
9760      * @example
9761      *
9762      * var users = [
9763      *   { 'user': 'barney', 'age': 36, 'active': false },
9764      *   { 'user': 'fred',   'age': 40, 'active': true }
9765      * ];
9766      *
9767      * _.reject(users, function(o) { return !o.active; });
9768      * // => objects for ['fred']
9769      *
9770      * // The `_.matches` iteratee shorthand.
9771      * _.reject(users, { 'age': 40, 'active': true });
9772      * // => objects for ['barney']
9773      *
9774      * // The `_.matchesProperty` iteratee shorthand.
9775      * _.reject(users, ['active', false]);
9776      * // => objects for ['fred']
9777      *
9778      * // The `_.property` iteratee shorthand.
9779      * _.reject(users, 'active');
9780      * // => objects for ['barney']
9781      */
9782     function reject(collection, predicate) {
9783       var func = isArray(collection) ? arrayFilter : baseFilter;
9784       return func(collection, negate(getIteratee(predicate, 3)));
9785     }
9786
9787     /**
9788      * Gets a random element from `collection`.
9789      *
9790      * @static
9791      * @memberOf _
9792      * @since 2.0.0
9793      * @category Collection
9794      * @param {Array|Object} collection The collection to sample.
9795      * @returns {*} Returns the random element.
9796      * @example
9797      *
9798      * _.sample([1, 2, 3, 4]);
9799      * // => 2
9800      */
9801     function sample(collection) {
9802       var func = isArray(collection) ? arraySample : baseSample;
9803       return func(collection);
9804     }
9805
9806     /**
9807      * Gets `n` random elements at unique keys from `collection` up to the
9808      * size of `collection`.
9809      *
9810      * @static
9811      * @memberOf _
9812      * @since 4.0.0
9813      * @category Collection
9814      * @param {Array|Object} collection The collection to sample.
9815      * @param {number} [n=1] The number of elements to sample.
9816      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9817      * @returns {Array} Returns the random elements.
9818      * @example
9819      *
9820      * _.sampleSize([1, 2, 3], 2);
9821      * // => [3, 1]
9822      *
9823      * _.sampleSize([1, 2, 3], 4);
9824      * // => [2, 3, 1]
9825      */
9826     function sampleSize(collection, n, guard) {
9827       if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) {
9828         n = 1;
9829       } else {
9830         n = toInteger(n);
9831       }
9832       var func = isArray(collection) ? arraySampleSize : baseSampleSize;
9833       return func(collection, n);
9834     }
9835
9836     /**
9837      * Creates an array of shuffled values, using a version of the
9838      * [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
9839      *
9840      * @static
9841      * @memberOf _
9842      * @since 0.1.0
9843      * @category Collection
9844      * @param {Array|Object} collection The collection to shuffle.
9845      * @returns {Array} Returns the new shuffled array.
9846      * @example
9847      *
9848      * _.shuffle([1, 2, 3, 4]);
9849      * // => [4, 1, 3, 2]
9850      */
9851     function shuffle(collection) {
9852       var func = isArray(collection) ? arrayShuffle : baseShuffle;
9853       return func(collection);
9854     }
9855
9856     /**
9857      * Gets the size of `collection` by returning its length for array-like
9858      * values or the number of own enumerable string keyed properties for objects.
9859      *
9860      * @static
9861      * @memberOf _
9862      * @since 0.1.0
9863      * @category Collection
9864      * @param {Array|Object|string} collection The collection to inspect.
9865      * @returns {number} Returns the collection size.
9866      * @example
9867      *
9868      * _.size([1, 2, 3]);
9869      * // => 3
9870      *
9871      * _.size({ 'a': 1, 'b': 2 });
9872      * // => 2
9873      *
9874      * _.size('pebbles');
9875      * // => 7
9876      */
9877     function size(collection) {
9878       if (collection == null) {
9879         return 0;
9880       }
9881       if (isArrayLike(collection)) {
9882         return isString(collection) ? stringSize(collection) : collection.length;
9883       }
9884       var tag = getTag(collection);
9885       if (tag == mapTag || tag == setTag) {
9886         return collection.size;
9887       }
9888       return baseKeys(collection).length;
9889     }
9890
9891     /**
9892      * Checks if `predicate` returns truthy for **any** element of `collection`.
9893      * Iteration is stopped once `predicate` returns truthy. The predicate is
9894      * invoked with three arguments: (value, index|key, collection).
9895      *
9896      * @static
9897      * @memberOf _
9898      * @since 0.1.0
9899      * @category Collection
9900      * @param {Array|Object} collection The collection to iterate over.
9901      * @param {Function} [predicate=_.identity] The function invoked per iteration.
9902      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
9903      * @returns {boolean} Returns `true` if any element passes the predicate check,
9904      *  else `false`.
9905      * @example
9906      *
9907      * _.some([null, 0, 'yes', false], Boolean);
9908      * // => true
9909      *
9910      * var users = [
9911      *   { 'user': 'barney', 'active': true },
9912      *   { 'user': 'fred',   'active': false }
9913      * ];
9914      *
9915      * // The `_.matches` iteratee shorthand.
9916      * _.some(users, { 'user': 'barney', 'active': false });
9917      * // => false
9918      *
9919      * // The `_.matchesProperty` iteratee shorthand.
9920      * _.some(users, ['active', false]);
9921      * // => true
9922      *
9923      * // The `_.property` iteratee shorthand.
9924      * _.some(users, 'active');
9925      * // => true
9926      */
9927     function some(collection, predicate, guard) {
9928       var func = isArray(collection) ? arraySome : baseSome;
9929       if (guard && isIterateeCall(collection, predicate, guard)) {
9930         predicate = undefined;
9931       }
9932       return func(collection, getIteratee(predicate, 3));
9933     }
9934
9935     /**
9936      * Creates an array of elements, sorted in ascending order by the results of
9937      * running each element in a collection thru each iteratee. This method
9938      * performs a stable sort, that is, it preserves the original sort order of
9939      * equal elements. The iteratees are invoked with one argument: (value).
9940      *
9941      * @static
9942      * @memberOf _
9943      * @since 0.1.0
9944      * @category Collection
9945      * @param {Array|Object} collection The collection to iterate over.
9946      * @param {...(Function|Function[])} [iteratees=[_.identity]]
9947      *  The iteratees to sort by.
9948      * @returns {Array} Returns the new sorted array.
9949      * @example
9950      *
9951      * var users = [
9952      *   { 'user': 'fred',   'age': 48 },
9953      *   { 'user': 'barney', 'age': 36 },
9954      *   { 'user': 'fred',   'age': 40 },
9955      *   { 'user': 'barney', 'age': 34 }
9956      * ];
9957      *
9958      * _.sortBy(users, [function(o) { return o.user; }]);
9959      * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
9960      *
9961      * _.sortBy(users, ['user', 'age']);
9962      * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]
9963      */
9964     var sortBy = baseRest(function(collection, iteratees) {
9965       if (collection == null) {
9966         return [];
9967       }
9968       var length = iteratees.length;
9969       if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
9970         iteratees = [];
9971       } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
9972         iteratees = [iteratees[0]];
9973       }
9974       return baseOrderBy(collection, baseFlatten(iteratees, 1), []);
9975     });
9976
9977     /*------------------------------------------------------------------------*/
9978
9979     /**
9980      * Gets the timestamp of the number of milliseconds that have elapsed since
9981      * the Unix epoch (1 January 1970 00:00:00 UTC).
9982      *
9983      * @static
9984      * @memberOf _
9985      * @since 2.4.0
9986      * @category Date
9987      * @returns {number} Returns the timestamp.
9988      * @example
9989      *
9990      * _.defer(function(stamp) {
9991      *   console.log(_.now() - stamp);
9992      * }, _.now());
9993      * // => Logs the number of milliseconds it took for the deferred invocation.
9994      */
9995     var now = ctxNow || function() {
9996       return root.Date.now();
9997     };
9998
9999     /*------------------------------------------------------------------------*/
10000
10001     /**
10002      * The opposite of `_.before`; this method creates a function that invokes
10003      * `func` once it's called `n` or more times.
10004      *
10005      * @static
10006      * @memberOf _
10007      * @since 0.1.0
10008      * @category Function
10009      * @param {number} n The number of calls before `func` is invoked.
10010      * @param {Function} func The function to restrict.
10011      * @returns {Function} Returns the new restricted function.
10012      * @example
10013      *
10014      * var saves = ['profile', 'settings'];
10015      *
10016      * var done = _.after(saves.length, function() {
10017      *   console.log('done saving!');
10018      * });
10019      *
10020      * _.forEach(saves, function(type) {
10021      *   asyncSave({ 'type': type, 'complete': done });
10022      * });
10023      * // => Logs 'done saving!' after the two async saves have completed.
10024      */
10025     function after(n, func) {
10026       if (typeof func != 'function') {
10027         throw new TypeError(FUNC_ERROR_TEXT);
10028       }
10029       n = toInteger(n);
10030       return function() {
10031         if (--n < 1) {
10032           return func.apply(this, arguments);
10033         }
10034       };
10035     }
10036
10037     /**
10038      * Creates a function that invokes `func`, with up to `n` arguments,
10039      * ignoring any additional arguments.
10040      *
10041      * @static
10042      * @memberOf _
10043      * @since 3.0.0
10044      * @category Function
10045      * @param {Function} func The function to cap arguments for.
10046      * @param {number} [n=func.length] The arity cap.
10047      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10048      * @returns {Function} Returns the new capped function.
10049      * @example
10050      *
10051      * _.map(['6', '8', '10'], _.ary(parseInt, 1));
10052      * // => [6, 8, 10]
10053      */
10054     function ary(func, n, guard) {
10055       n = guard ? undefined : n;
10056       n = (func && n == null) ? func.length : n;
10057       return createWrap(func, WRAP_ARY_FLAG, undefined, undefined, undefined, undefined, n);
10058     }
10059
10060     /**
10061      * Creates a function that invokes `func`, with the `this` binding and arguments
10062      * of the created function, while it's called less than `n` times. Subsequent
10063      * calls to the created function return the result of the last `func` invocation.
10064      *
10065      * @static
10066      * @memberOf _
10067      * @since 3.0.0
10068      * @category Function
10069      * @param {number} n The number of calls at which `func` is no longer invoked.
10070      * @param {Function} func The function to restrict.
10071      * @returns {Function} Returns the new restricted function.
10072      * @example
10073      *
10074      * jQuery(element).on('click', _.before(5, addContactToList));
10075      * // => Allows adding up to 4 contacts to the list.
10076      */
10077     function before(n, func) {
10078       var result;
10079       if (typeof func != 'function') {
10080         throw new TypeError(FUNC_ERROR_TEXT);
10081       }
10082       n = toInteger(n);
10083       return function() {
10084         if (--n > 0) {
10085           result = func.apply(this, arguments);
10086         }
10087         if (n <= 1) {
10088           func = undefined;
10089         }
10090         return result;
10091       };
10092     }
10093
10094     /**
10095      * Creates a function that invokes `func` with the `this` binding of `thisArg`
10096      * and `partials` prepended to the arguments it receives.
10097      *
10098      * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
10099      * may be used as a placeholder for partially applied arguments.
10100      *
10101      * **Note:** Unlike native `Function#bind`, this method doesn't set the "length"
10102      * property of bound functions.
10103      *
10104      * @static
10105      * @memberOf _
10106      * @since 0.1.0
10107      * @category Function
10108      * @param {Function} func The function to bind.
10109      * @param {*} thisArg The `this` binding of `func`.
10110      * @param {...*} [partials] The arguments to be partially applied.
10111      * @returns {Function} Returns the new bound function.
10112      * @example
10113      *
10114      * function greet(greeting, punctuation) {
10115      *   return greeting + ' ' + this.user + punctuation;
10116      * }
10117      *
10118      * var object = { 'user': 'fred' };
10119      *
10120      * var bound = _.bind(greet, object, 'hi');
10121      * bound('!');
10122      * // => 'hi fred!'
10123      *
10124      * // Bound with placeholders.
10125      * var bound = _.bind(greet, object, _, '!');
10126      * bound('hi');
10127      * // => 'hi fred!'
10128      */
10129     var bind = baseRest(function(func, thisArg, partials) {
10130       var bitmask = WRAP_BIND_FLAG;
10131       if (partials.length) {
10132         var holders = replaceHolders(partials, getHolder(bind));
10133         bitmask |= WRAP_PARTIAL_FLAG;
10134       }
10135       return createWrap(func, bitmask, thisArg, partials, holders);
10136     });
10137
10138     /**
10139      * Creates a function that invokes the method at `object[key]` with `partials`
10140      * prepended to the arguments it receives.
10141      *
10142      * This method differs from `_.bind` by allowing bound functions to reference
10143      * methods that may be redefined or don't yet exist. See
10144      * [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
10145      * for more details.
10146      *
10147      * The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
10148      * builds, may be used as a placeholder for partially applied arguments.
10149      *
10150      * @static
10151      * @memberOf _
10152      * @since 0.10.0
10153      * @category Function
10154      * @param {Object} object The object to invoke the method on.
10155      * @param {string} key The key of the method.
10156      * @param {...*} [partials] The arguments to be partially applied.
10157      * @returns {Function} Returns the new bound function.
10158      * @example
10159      *
10160      * var object = {
10161      *   'user': 'fred',
10162      *   'greet': function(greeting, punctuation) {
10163      *     return greeting + ' ' + this.user + punctuation;
10164      *   }
10165      * };
10166      *
10167      * var bound = _.bindKey(object, 'greet', 'hi');
10168      * bound('!');
10169      * // => 'hi fred!'
10170      *
10171      * object.greet = function(greeting, punctuation) {
10172      *   return greeting + 'ya ' + this.user + punctuation;
10173      * };
10174      *
10175      * bound('!');
10176      * // => 'hiya fred!'
10177      *
10178      * // Bound with placeholders.
10179      * var bound = _.bindKey(object, 'greet', _, '!');
10180      * bound('hi');
10181      * // => 'hiya fred!'
10182      */
10183     var bindKey = baseRest(function(object, key, partials) {
10184       var bitmask = WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG;
10185       if (partials.length) {
10186         var holders = replaceHolders(partials, getHolder(bindKey));
10187         bitmask |= WRAP_PARTIAL_FLAG;
10188       }
10189       return createWrap(key, bitmask, object, partials, holders);
10190     });
10191
10192     /**
10193      * Creates a function that accepts arguments of `func` and either invokes
10194      * `func` returning its result, if at least `arity` number of arguments have
10195      * been provided, or returns a function that accepts the remaining `func`
10196      * arguments, and so on. The arity of `func` may be specified if `func.length`
10197      * is not sufficient.
10198      *
10199      * The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
10200      * may be used as a placeholder for provided arguments.
10201      *
10202      * **Note:** This method doesn't set the "length" property of curried functions.
10203      *
10204      * @static
10205      * @memberOf _
10206      * @since 2.0.0
10207      * @category Function
10208      * @param {Function} func The function to curry.
10209      * @param {number} [arity=func.length] The arity of `func`.
10210      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10211      * @returns {Function} Returns the new curried function.
10212      * @example
10213      *
10214      * var abc = function(a, b, c) {
10215      *   return [a, b, c];
10216      * };
10217      *
10218      * var curried = _.curry(abc);
10219      *
10220      * curried(1)(2)(3);
10221      * // => [1, 2, 3]
10222      *
10223      * curried(1, 2)(3);
10224      * // => [1, 2, 3]
10225      *
10226      * curried(1, 2, 3);
10227      * // => [1, 2, 3]
10228      *
10229      * // Curried with placeholders.
10230      * curried(1)(_, 3)(2);
10231      * // => [1, 2, 3]
10232      */
10233     function curry(func, arity, guard) {
10234       arity = guard ? undefined : arity;
10235       var result = createWrap(func, WRAP_CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
10236       result.placeholder = curry.placeholder;
10237       return result;
10238     }
10239
10240     /**
10241      * This method is like `_.curry` except that arguments are applied to `func`
10242      * in the manner of `_.partialRight` instead of `_.partial`.
10243      *
10244      * The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
10245      * builds, may be used as a placeholder for provided arguments.
10246      *
10247      * **Note:** This method doesn't set the "length" property of curried functions.
10248      *
10249      * @static
10250      * @memberOf _
10251      * @since 3.0.0
10252      * @category Function
10253      * @param {Function} func The function to curry.
10254      * @param {number} [arity=func.length] The arity of `func`.
10255      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
10256      * @returns {Function} Returns the new curried function.
10257      * @example
10258      *
10259      * var abc = function(a, b, c) {
10260      *   return [a, b, c];
10261      * };
10262      *
10263      * var curried = _.curryRight(abc);
10264      *
10265      * curried(3)(2)(1);
10266      * // => [1, 2, 3]
10267      *
10268      * curried(2, 3)(1);
10269      * // => [1, 2, 3]
10270      *
10271      * curried(1, 2, 3);
10272      * // => [1, 2, 3]
10273      *
10274      * // Curried with placeholders.
10275      * curried(3)(1, _)(2);
10276      * // => [1, 2, 3]
10277      */
10278     function curryRight(func, arity, guard) {
10279       arity = guard ? undefined : arity;
10280       var result = createWrap(func, WRAP_CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
10281       result.placeholder = curryRight.placeholder;
10282       return result;
10283     }
10284
10285     /**
10286      * Creates a debounced function that delays invoking `func` until after `wait`
10287      * milliseconds have elapsed since the last time the debounced function was
10288      * invoked. The debounced function comes with a `cancel` method to cancel
10289      * delayed `func` invocations and a `flush` method to immediately invoke them.
10290      * Provide `options` to indicate whether `func` should be invoked on the
10291      * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
10292      * with the last arguments provided to the debounced function. Subsequent
10293      * calls to the debounced function return the result of the last `func`
10294      * invocation.
10295      *
10296      * **Note:** If `leading` and `trailing` options are `true`, `func` is
10297      * invoked on the trailing edge of the timeout only if the debounced function
10298      * is invoked more than once during the `wait` timeout.
10299      *
10300      * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
10301      * until to the next tick, similar to `setTimeout` with a timeout of `0`.
10302      *
10303      * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
10304      * for details over the differences between `_.debounce` and `_.throttle`.
10305      *
10306      * @static
10307      * @memberOf _
10308      * @since 0.1.0
10309      * @category Function
10310      * @param {Function} func The function to debounce.
10311      * @param {number} [wait=0] The number of milliseconds to delay.
10312      * @param {Object} [options={}] The options object.
10313      * @param {boolean} [options.leading=false]
10314      *  Specify invoking on the leading edge of the timeout.
10315      * @param {number} [options.maxWait]
10316      *  The maximum time `func` is allowed to be delayed before it's invoked.
10317      * @param {boolean} [options.trailing=true]
10318      *  Specify invoking on the trailing edge of the timeout.
10319      * @returns {Function} Returns the new debounced function.
10320      * @example
10321      *
10322      * // Avoid costly calculations while the window size is in flux.
10323      * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
10324      *
10325      * // Invoke `sendMail` when clicked, debouncing subsequent calls.
10326      * jQuery(element).on('click', _.debounce(sendMail, 300, {
10327      *   'leading': true,
10328      *   'trailing': false
10329      * }));
10330      *
10331      * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
10332      * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
10333      * var source = new EventSource('/stream');
10334      * jQuery(source).on('message', debounced);
10335      *
10336      * // Cancel the trailing debounced invocation.
10337      * jQuery(window).on('popstate', debounced.cancel);
10338      */
10339     function debounce(func, wait, options) {
10340       var lastArgs,
10341           lastThis,
10342           maxWait,
10343           result,
10344           timerId,
10345           lastCallTime,
10346           lastInvokeTime = 0,
10347           leading = false,
10348           maxing = false,
10349           trailing = true;
10350
10351       if (typeof func != 'function') {
10352         throw new TypeError(FUNC_ERROR_TEXT);
10353       }
10354       wait = toNumber(wait) || 0;
10355       if (isObject(options)) {
10356         leading = !!options.leading;
10357         maxing = 'maxWait' in options;
10358         maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
10359         trailing = 'trailing' in options ? !!options.trailing : trailing;
10360       }
10361
10362       function invokeFunc(time) {
10363         var args = lastArgs,
10364             thisArg = lastThis;
10365
10366         lastArgs = lastThis = undefined;
10367         lastInvokeTime = time;
10368         result = func.apply(thisArg, args);
10369         return result;
10370       }
10371
10372       function leadingEdge(time) {
10373         // Reset any `maxWait` timer.
10374         lastInvokeTime = time;
10375         // Start the timer for the trailing edge.
10376         timerId = setTimeout(timerExpired, wait);
10377         // Invoke the leading edge.
10378         return leading ? invokeFunc(time) : result;
10379       }
10380
10381       function remainingWait(time) {
10382         var timeSinceLastCall = time - lastCallTime,
10383             timeSinceLastInvoke = time - lastInvokeTime,
10384             result = wait - timeSinceLastCall;
10385
10386         return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
10387       }
10388
10389       function shouldInvoke(time) {
10390         var timeSinceLastCall = time - lastCallTime,
10391             timeSinceLastInvoke = time - lastInvokeTime;
10392
10393         // Either this is the first call, activity has stopped and we're at the
10394         // trailing edge, the system time has gone backwards and we're treating
10395         // it as the trailing edge, or we've hit the `maxWait` limit.
10396         return (lastCallTime === undefined || (timeSinceLastCall >= wait) ||
10397           (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
10398       }
10399
10400       function timerExpired() {
10401         var time = now();
10402         if (shouldInvoke(time)) {
10403           return trailingEdge(time);
10404         }
10405         // Restart the timer.
10406         timerId = setTimeout(timerExpired, remainingWait(time));
10407       }
10408
10409       function trailingEdge(time) {
10410         timerId = undefined;
10411
10412         // Only invoke if we have `lastArgs` which means `func` has been
10413         // debounced at least once.
10414         if (trailing && lastArgs) {
10415           return invokeFunc(time);
10416         }
10417         lastArgs = lastThis = undefined;
10418         return result;
10419       }
10420
10421       function cancel() {
10422         if (timerId !== undefined) {
10423           clearTimeout(timerId);
10424         }
10425         lastInvokeTime = 0;
10426         lastArgs = lastCallTime = lastThis = timerId = undefined;
10427       }
10428
10429       function flush() {
10430         return timerId === undefined ? result : trailingEdge(now());
10431       }
10432
10433       function debounced() {
10434         var time = now(),
10435             isInvoking = shouldInvoke(time);
10436
10437         lastArgs = arguments;
10438         lastThis = this;
10439         lastCallTime = time;
10440
10441         if (isInvoking) {
10442           if (timerId === undefined) {
10443             return leadingEdge(lastCallTime);
10444           }
10445           if (maxing) {
10446             // Handle invocations in a tight loop.
10447             timerId = setTimeout(timerExpired, wait);
10448             return invokeFunc(lastCallTime);
10449           }
10450         }
10451         if (timerId === undefined) {
10452           timerId = setTimeout(timerExpired, wait);
10453         }
10454         return result;
10455       }
10456       debounced.cancel = cancel;
10457       debounced.flush = flush;
10458       return debounced;
10459     }
10460
10461     /**
10462      * Defers invoking the `func` until the current call stack has cleared. Any
10463      * additional arguments are provided to `func` when it's invoked.
10464      *
10465      * @static
10466      * @memberOf _
10467      * @since 0.1.0
10468      * @category Function
10469      * @param {Function} func The function to defer.
10470      * @param {...*} [args] The arguments to invoke `func` with.
10471      * @returns {number} Returns the timer id.
10472      * @example
10473      *
10474      * _.defer(function(text) {
10475      *   console.log(text);
10476      * }, 'deferred');
10477      * // => Logs 'deferred' after one millisecond.
10478      */
10479     var defer = baseRest(function(func, args) {
10480       return baseDelay(func, 1, args);
10481     });
10482
10483     /**
10484      * Invokes `func` after `wait` milliseconds. Any additional arguments are
10485      * provided to `func` when it's invoked.
10486      *
10487      * @static
10488      * @memberOf _
10489      * @since 0.1.0
10490      * @category Function
10491      * @param {Function} func The function to delay.
10492      * @param {number} wait The number of milliseconds to delay invocation.
10493      * @param {...*} [args] The arguments to invoke `func` with.
10494      * @returns {number} Returns the timer id.
10495      * @example
10496      *
10497      * _.delay(function(text) {
10498      *   console.log(text);
10499      * }, 1000, 'later');
10500      * // => Logs 'later' after one second.
10501      */
10502     var delay = baseRest(function(func, wait, args) {
10503       return baseDelay(func, toNumber(wait) || 0, args);
10504     });
10505
10506     /**
10507      * Creates a function that invokes `func` with arguments reversed.
10508      *
10509      * @static
10510      * @memberOf _
10511      * @since 4.0.0
10512      * @category Function
10513      * @param {Function} func The function to flip arguments for.
10514      * @returns {Function} Returns the new flipped function.
10515      * @example
10516      *
10517      * var flipped = _.flip(function() {
10518      *   return _.toArray(arguments);
10519      * });
10520      *
10521      * flipped('a', 'b', 'c', 'd');
10522      * // => ['d', 'c', 'b', 'a']
10523      */
10524     function flip(func) {
10525       return createWrap(func, WRAP_FLIP_FLAG);
10526     }
10527
10528     /**
10529      * Creates a function that memoizes the result of `func`. If `resolver` is
10530      * provided, it determines the cache key for storing the result based on the
10531      * arguments provided to the memoized function. By default, the first argument
10532      * provided to the memoized function is used as the map cache key. The `func`
10533      * is invoked with the `this` binding of the memoized function.
10534      *
10535      * **Note:** The cache is exposed as the `cache` property on the memoized
10536      * function. Its creation may be customized by replacing the `_.memoize.Cache`
10537      * constructor with one whose instances implement the
10538      * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object)
10539      * method interface of `clear`, `delete`, `get`, `has`, and `set`.
10540      *
10541      * @static
10542      * @memberOf _
10543      * @since 0.1.0
10544      * @category Function
10545      * @param {Function} func The function to have its output memoized.
10546      * @param {Function} [resolver] The function to resolve the cache key.
10547      * @returns {Function} Returns the new memoized function.
10548      * @example
10549      *
10550      * var object = { 'a': 1, 'b': 2 };
10551      * var other = { 'c': 3, 'd': 4 };
10552      *
10553      * var values = _.memoize(_.values);
10554      * values(object);
10555      * // => [1, 2]
10556      *
10557      * values(other);
10558      * // => [3, 4]
10559      *
10560      * object.a = 2;
10561      * values(object);
10562      * // => [1, 2]
10563      *
10564      * // Modify the result cache.
10565      * values.cache.set(object, ['a', 'b']);
10566      * values(object);
10567      * // => ['a', 'b']
10568      *
10569      * // Replace `_.memoize.Cache`.
10570      * _.memoize.Cache = WeakMap;
10571      */
10572     function memoize(func, resolver) {
10573       if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) {
10574         throw new TypeError(FUNC_ERROR_TEXT);
10575       }
10576       var memoized = function() {
10577         var args = arguments,
10578             key = resolver ? resolver.apply(this, args) : args[0],
10579             cache = memoized.cache;
10580
10581         if (cache.has(key)) {
10582           return cache.get(key);
10583         }
10584         var result = func.apply(this, args);
10585         memoized.cache = cache.set(key, result) || cache;
10586         return result;
10587       };
10588       memoized.cache = new (memoize.Cache || MapCache);
10589       return memoized;
10590     }
10591
10592     // Expose `MapCache`.
10593     memoize.Cache = MapCache;
10594
10595     /**
10596      * Creates a function that negates the result of the predicate `func`. The
10597      * `func` predicate is invoked with the `this` binding and arguments of the
10598      * created function.
10599      *
10600      * @static
10601      * @memberOf _
10602      * @since 3.0.0
10603      * @category Function
10604      * @param {Function} predicate The predicate to negate.
10605      * @returns {Function} Returns the new negated function.
10606      * @example
10607      *
10608      * function isEven(n) {
10609      *   return n % 2 == 0;
10610      * }
10611      *
10612      * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
10613      * // => [1, 3, 5]
10614      */
10615     function negate(predicate) {
10616       if (typeof predicate != 'function') {
10617         throw new TypeError(FUNC_ERROR_TEXT);
10618       }
10619       return function() {
10620         var args = arguments;
10621         switch (args.length) {
10622           case 0: return !predicate.call(this);
10623           case 1: return !predicate.call(this, args[0]);
10624           case 2: return !predicate.call(this, args[0], args[1]);
10625           case 3: return !predicate.call(this, args[0], args[1], args[2]);
10626         }
10627         return !predicate.apply(this, args);
10628       };
10629     }
10630
10631     /**
10632      * Creates a function that is restricted to invoking `func` once. Repeat calls
10633      * to the function return the value of the first invocation. The `func` is
10634      * invoked with the `this` binding and arguments of the created function.
10635      *
10636      * @static
10637      * @memberOf _
10638      * @since 0.1.0
10639      * @category Function
10640      * @param {Function} func The function to restrict.
10641      * @returns {Function} Returns the new restricted function.
10642      * @example
10643      *
10644      * var initialize = _.once(createApplication);
10645      * initialize();
10646      * initialize();
10647      * // => `createApplication` is invoked once
10648      */
10649     function once(func) {
10650       return before(2, func);
10651     }
10652
10653     /**
10654      * Creates a function that invokes `func` with its arguments transformed.
10655      *
10656      * @static
10657      * @since 4.0.0
10658      * @memberOf _
10659      * @category Function
10660      * @param {Function} func The function to wrap.
10661      * @param {...(Function|Function[])} [transforms=[_.identity]]
10662      *  The argument transforms.
10663      * @returns {Function} Returns the new function.
10664      * @example
10665      *
10666      * function doubled(n) {
10667      *   return n * 2;
10668      * }
10669      *
10670      * function square(n) {
10671      *   return n * n;
10672      * }
10673      *
10674      * var func = _.overArgs(function(x, y) {
10675      *   return [x, y];
10676      * }, [square, doubled]);
10677      *
10678      * func(9, 3);
10679      * // => [81, 6]
10680      *
10681      * func(10, 5);
10682      * // => [100, 10]
10683      */
10684     var overArgs = castRest(function(func, transforms) {
10685       transforms = (transforms.length == 1 && isArray(transforms[0]))
10686         ? arrayMap(transforms[0], baseUnary(getIteratee()))
10687         : arrayMap(baseFlatten(transforms, 1), baseUnary(getIteratee()));
10688
10689       var funcsLength = transforms.length;
10690       return baseRest(function(args) {
10691         var index = -1,
10692             length = nativeMin(args.length, funcsLength);
10693
10694         while (++index < length) {
10695           args[index] = transforms[index].call(this, args[index]);
10696         }
10697         return apply(func, this, args);
10698       });
10699     });
10700
10701     /**
10702      * Creates a function that invokes `func` with `partials` prepended to the
10703      * arguments it receives. This method is like `_.bind` except it does **not**
10704      * alter the `this` binding.
10705      *
10706      * The `_.partial.placeholder` value, which defaults to `_` in monolithic
10707      * builds, may be used as a placeholder for partially applied arguments.
10708      *
10709      * **Note:** This method doesn't set the "length" property of partially
10710      * applied functions.
10711      *
10712      * @static
10713      * @memberOf _
10714      * @since 0.2.0
10715      * @category Function
10716      * @param {Function} func The function to partially apply arguments to.
10717      * @param {...*} [partials] The arguments to be partially applied.
10718      * @returns {Function} Returns the new partially applied function.
10719      * @example
10720      *
10721      * function greet(greeting, name) {
10722      *   return greeting + ' ' + name;
10723      * }
10724      *
10725      * var sayHelloTo = _.partial(greet, 'hello');
10726      * sayHelloTo('fred');
10727      * // => 'hello fred'
10728      *
10729      * // Partially applied with placeholders.
10730      * var greetFred = _.partial(greet, _, 'fred');
10731      * greetFred('hi');
10732      * // => 'hi fred'
10733      */
10734     var partial = baseRest(function(func, partials) {
10735       var holders = replaceHolders(partials, getHolder(partial));
10736       return createWrap(func, WRAP_PARTIAL_FLAG, undefined, partials, holders);
10737     });
10738
10739     /**
10740      * This method is like `_.partial` except that partially applied arguments
10741      * are appended to the arguments it receives.
10742      *
10743      * The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
10744      * builds, may be used as a placeholder for partially applied arguments.
10745      *
10746      * **Note:** This method doesn't set the "length" property of partially
10747      * applied functions.
10748      *
10749      * @static
10750      * @memberOf _
10751      * @since 1.0.0
10752      * @category Function
10753      * @param {Function} func The function to partially apply arguments to.
10754      * @param {...*} [partials] The arguments to be partially applied.
10755      * @returns {Function} Returns the new partially applied function.
10756      * @example
10757      *
10758      * function greet(greeting, name) {
10759      *   return greeting + ' ' + name;
10760      * }
10761      *
10762      * var greetFred = _.partialRight(greet, 'fred');
10763      * greetFred('hi');
10764      * // => 'hi fred'
10765      *
10766      * // Partially applied with placeholders.
10767      * var sayHelloTo = _.partialRight(greet, 'hello', _);
10768      * sayHelloTo('fred');
10769      * // => 'hello fred'
10770      */
10771     var partialRight = baseRest(function(func, partials) {
10772       var holders = replaceHolders(partials, getHolder(partialRight));
10773       return createWrap(func, WRAP_PARTIAL_RIGHT_FLAG, undefined, partials, holders);
10774     });
10775
10776     /**
10777      * Creates a function that invokes `func` with arguments arranged according
10778      * to the specified `indexes` where the argument value at the first index is
10779      * provided as the first argument, the argument value at the second index is
10780      * provided as the second argument, and so on.
10781      *
10782      * @static
10783      * @memberOf _
10784      * @since 3.0.0
10785      * @category Function
10786      * @param {Function} func The function to rearrange arguments for.
10787      * @param {...(number|number[])} indexes The arranged argument indexes.
10788      * @returns {Function} Returns the new function.
10789      * @example
10790      *
10791      * var rearged = _.rearg(function(a, b, c) {
10792      *   return [a, b, c];
10793      * }, [2, 0, 1]);
10794      *
10795      * rearged('b', 'c', 'a')
10796      * // => ['a', 'b', 'c']
10797      */
10798     var rearg = flatRest(function(func, indexes) {
10799       return createWrap(func, WRAP_REARG_FLAG, undefined, undefined, undefined, indexes);
10800     });
10801
10802     /**
10803      * Creates a function that invokes `func` with the `this` binding of the
10804      * created function and arguments from `start` and beyond provided as
10805      * an array.
10806      *
10807      * **Note:** This method is based on the
10808      * [rest parameter](https://mdn.io/rest_parameters).
10809      *
10810      * @static
10811      * @memberOf _
10812      * @since 4.0.0
10813      * @category Function
10814      * @param {Function} func The function to apply a rest parameter to.
10815      * @param {number} [start=func.length-1] The start position of the rest parameter.
10816      * @returns {Function} Returns the new function.
10817      * @example
10818      *
10819      * var say = _.rest(function(what, names) {
10820      *   return what + ' ' + _.initial(names).join(', ') +
10821      *     (_.size(names) > 1 ? ', & ' : '') + _.last(names);
10822      * });
10823      *
10824      * say('hello', 'fred', 'barney', 'pebbles');
10825      * // => 'hello fred, barney, & pebbles'
10826      */
10827     function rest(func, start) {
10828       if (typeof func != 'function') {
10829         throw new TypeError(FUNC_ERROR_TEXT);
10830       }
10831       start = start === undefined ? start : toInteger(start);
10832       return baseRest(func, start);
10833     }
10834
10835     /**
10836      * Creates a function that invokes `func` with the `this` binding of the
10837      * create function and an array of arguments much like
10838      * [`Function#apply`](http://www.ecma-international.org/ecma-262/7.0/#sec-function.prototype.apply).
10839      *
10840      * **Note:** This method is based on the
10841      * [spread operator](https://mdn.io/spread_operator).
10842      *
10843      * @static
10844      * @memberOf _
10845      * @since 3.2.0
10846      * @category Function
10847      * @param {Function} func The function to spread arguments over.
10848      * @param {number} [start=0] The start position of the spread.
10849      * @returns {Function} Returns the new function.
10850      * @example
10851      *
10852      * var say = _.spread(function(who, what) {
10853      *   return who + ' says ' + what;
10854      * });
10855      *
10856      * say(['fred', 'hello']);
10857      * // => 'fred says hello'
10858      *
10859      * var numbers = Promise.all([
10860      *   Promise.resolve(40),
10861      *   Promise.resolve(36)
10862      * ]);
10863      *
10864      * numbers.then(_.spread(function(x, y) {
10865      *   return x + y;
10866      * }));
10867      * // => a Promise of 76
10868      */
10869     function spread(func, start) {
10870       if (typeof func != 'function') {
10871         throw new TypeError(FUNC_ERROR_TEXT);
10872       }
10873       start = start == null ? 0 : nativeMax(toInteger(start), 0);
10874       return baseRest(function(args) {
10875         var array = args[start],
10876             otherArgs = castSlice(args, 0, start);
10877
10878         if (array) {
10879           arrayPush(otherArgs, array);
10880         }
10881         return apply(func, this, otherArgs);
10882       });
10883     }
10884
10885     /**
10886      * Creates a throttled function that only invokes `func` at most once per
10887      * every `wait` milliseconds. The throttled function comes with a `cancel`
10888      * method to cancel delayed `func` invocations and a `flush` method to
10889      * immediately invoke them. Provide `options` to indicate whether `func`
10890      * should be invoked on the leading and/or trailing edge of the `wait`
10891      * timeout. The `func` is invoked with the last arguments provided to the
10892      * throttled function. Subsequent calls to the throttled function return the
10893      * result of the last `func` invocation.
10894      *
10895      * **Note:** If `leading` and `trailing` options are `true`, `func` is
10896      * invoked on the trailing edge of the timeout only if the throttled function
10897      * is invoked more than once during the `wait` timeout.
10898      *
10899      * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
10900      * until to the next tick, similar to `setTimeout` with a timeout of `0`.
10901      *
10902      * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
10903      * for details over the differences between `_.throttle` and `_.debounce`.
10904      *
10905      * @static
10906      * @memberOf _
10907      * @since 0.1.0
10908      * @category Function
10909      * @param {Function} func The function to throttle.
10910      * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
10911      * @param {Object} [options={}] The options object.
10912      * @param {boolean} [options.leading=true]
10913      *  Specify invoking on the leading edge of the timeout.
10914      * @param {boolean} [options.trailing=true]
10915      *  Specify invoking on the trailing edge of the timeout.
10916      * @returns {Function} Returns the new throttled function.
10917      * @example
10918      *
10919      * // Avoid excessively updating the position while scrolling.
10920      * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
10921      *
10922      * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
10923      * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
10924      * jQuery(element).on('click', throttled);
10925      *
10926      * // Cancel the trailing throttled invocation.
10927      * jQuery(window).on('popstate', throttled.cancel);
10928      */
10929     function throttle(func, wait, options) {
10930       var leading = true,
10931           trailing = true;
10932
10933       if (typeof func != 'function') {
10934         throw new TypeError(FUNC_ERROR_TEXT);
10935       }
10936       if (isObject(options)) {
10937         leading = 'leading' in options ? !!options.leading : leading;
10938         trailing = 'trailing' in options ? !!options.trailing : trailing;
10939       }
10940       return debounce(func, wait, {
10941         'leading': leading,
10942         'maxWait': wait,
10943         'trailing': trailing
10944       });
10945     }
10946
10947     /**
10948      * Creates a function that accepts up to one argument, ignoring any
10949      * additional arguments.
10950      *
10951      * @static
10952      * @memberOf _
10953      * @since 4.0.0
10954      * @category Function
10955      * @param {Function} func The function to cap arguments for.
10956      * @returns {Function} Returns the new capped function.
10957      * @example
10958      *
10959      * _.map(['6', '8', '10'], _.unary(parseInt));
10960      * // => [6, 8, 10]
10961      */
10962     function unary(func) {
10963       return ary(func, 1);
10964     }
10965
10966     /**
10967      * Creates a function that provides `value` to `wrapper` as its first
10968      * argument. Any additional arguments provided to the function are appended
10969      * to those provided to the `wrapper`. The wrapper is invoked with the `this`
10970      * binding of the created function.
10971      *
10972      * @static
10973      * @memberOf _
10974      * @since 0.1.0
10975      * @category Function
10976      * @param {*} value The value to wrap.
10977      * @param {Function} [wrapper=identity] The wrapper function.
10978      * @returns {Function} Returns the new function.
10979      * @example
10980      *
10981      * var p = _.wrap(_.escape, function(func, text) {
10982      *   return '<p>' + func(text) + '</p>';
10983      * });
10984      *
10985      * p('fred, barney, & pebbles');
10986      * // => '<p>fred, barney, &amp; pebbles</p>'
10987      */
10988     function wrap(value, wrapper) {
10989       return partial(castFunction(wrapper), value);
10990     }
10991
10992     /*------------------------------------------------------------------------*/
10993
10994     /**
10995      * Casts `value` as an array if it's not one.
10996      *
10997      * @static
10998      * @memberOf _
10999      * @since 4.4.0
11000      * @category Lang
11001      * @param {*} value The value to inspect.
11002      * @returns {Array} Returns the cast array.
11003      * @example
11004      *
11005      * _.castArray(1);
11006      * // => [1]
11007      *
11008      * _.castArray({ 'a': 1 });
11009      * // => [{ 'a': 1 }]
11010      *
11011      * _.castArray('abc');
11012      * // => ['abc']
11013      *
11014      * _.castArray(null);
11015      * // => [null]
11016      *
11017      * _.castArray(undefined);
11018      * // => [undefined]
11019      *
11020      * _.castArray();
11021      * // => []
11022      *
11023      * var array = [1, 2, 3];
11024      * console.log(_.castArray(array) === array);
11025      * // => true
11026      */
11027     function castArray() {
11028       if (!arguments.length) {
11029         return [];
11030       }
11031       var value = arguments[0];
11032       return isArray(value) ? value : [value];
11033     }
11034
11035     /**
11036      * Creates a shallow clone of `value`.
11037      *
11038      * **Note:** This method is loosely based on the
11039      * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
11040      * and supports cloning arrays, array buffers, booleans, date objects, maps,
11041      * numbers, `Object` objects, regexes, sets, strings, symbols, and typed
11042      * arrays. The own enumerable properties of `arguments` objects are cloned
11043      * as plain objects. An empty object is returned for uncloneable values such
11044      * as error objects, functions, DOM nodes, and WeakMaps.
11045      *
11046      * @static
11047      * @memberOf _
11048      * @since 0.1.0
11049      * @category Lang
11050      * @param {*} value The value to clone.
11051      * @returns {*} Returns the cloned value.
11052      * @see _.cloneDeep
11053      * @example
11054      *
11055      * var objects = [{ 'a': 1 }, { 'b': 2 }];
11056      *
11057      * var shallow = _.clone(objects);
11058      * console.log(shallow[0] === objects[0]);
11059      * // => true
11060      */
11061     function clone(value) {
11062       return baseClone(value, CLONE_SYMBOLS_FLAG);
11063     }
11064
11065     /**
11066      * This method is like `_.clone` except that it accepts `customizer` which
11067      * is invoked to produce the cloned value. If `customizer` returns `undefined`,
11068      * cloning is handled by the method instead. The `customizer` is invoked with
11069      * up to four arguments; (value [, index|key, object, stack]).
11070      *
11071      * @static
11072      * @memberOf _
11073      * @since 4.0.0
11074      * @category Lang
11075      * @param {*} value The value to clone.
11076      * @param {Function} [customizer] The function to customize cloning.
11077      * @returns {*} Returns the cloned value.
11078      * @see _.cloneDeepWith
11079      * @example
11080      *
11081      * function customizer(value) {
11082      *   if (_.isElement(value)) {
11083      *     return value.cloneNode(false);
11084      *   }
11085      * }
11086      *
11087      * var el = _.cloneWith(document.body, customizer);
11088      *
11089      * console.log(el === document.body);
11090      * // => false
11091      * console.log(el.nodeName);
11092      * // => 'BODY'
11093      * console.log(el.childNodes.length);
11094      * // => 0
11095      */
11096     function cloneWith(value, customizer) {
11097       customizer = typeof customizer == 'function' ? customizer : undefined;
11098       return baseClone(value, CLONE_SYMBOLS_FLAG, customizer);
11099     }
11100
11101     /**
11102      * This method is like `_.clone` except that it recursively clones `value`.
11103      *
11104      * @static
11105      * @memberOf _
11106      * @since 1.0.0
11107      * @category Lang
11108      * @param {*} value The value to recursively clone.
11109      * @returns {*} Returns the deep cloned value.
11110      * @see _.clone
11111      * @example
11112      *
11113      * var objects = [{ 'a': 1 }, { 'b': 2 }];
11114      *
11115      * var deep = _.cloneDeep(objects);
11116      * console.log(deep[0] === objects[0]);
11117      * // => false
11118      */
11119     function cloneDeep(value) {
11120       return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);
11121     }
11122
11123     /**
11124      * This method is like `_.cloneWith` except that it recursively clones `value`.
11125      *
11126      * @static
11127      * @memberOf _
11128      * @since 4.0.0
11129      * @category Lang
11130      * @param {*} value The value to recursively clone.
11131      * @param {Function} [customizer] The function to customize cloning.
11132      * @returns {*} Returns the deep cloned value.
11133      * @see _.cloneWith
11134      * @example
11135      *
11136      * function customizer(value) {
11137      *   if (_.isElement(value)) {
11138      *     return value.cloneNode(true);
11139      *   }
11140      * }
11141      *
11142      * var el = _.cloneDeepWith(document.body, customizer);
11143      *
11144      * console.log(el === document.body);
11145      * // => false
11146      * console.log(el.nodeName);
11147      * // => 'BODY'
11148      * console.log(el.childNodes.length);
11149      * // => 20
11150      */
11151     function cloneDeepWith(value, customizer) {
11152       customizer = typeof customizer == 'function' ? customizer : undefined;
11153       return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);
11154     }
11155
11156     /**
11157      * Checks if `object` conforms to `source` by invoking the predicate
11158      * properties of `source` with the corresponding property values of `object`.
11159      *
11160      * **Note:** This method is equivalent to `_.conforms` when `source` is
11161      * partially applied.
11162      *
11163      * @static
11164      * @memberOf _
11165      * @since 4.14.0
11166      * @category Lang
11167      * @param {Object} object The object to inspect.
11168      * @param {Object} source The object of property predicates to conform to.
11169      * @returns {boolean} Returns `true` if `object` conforms, else `false`.
11170      * @example
11171      *
11172      * var object = { 'a': 1, 'b': 2 };
11173      *
11174      * _.conformsTo(object, { 'b': function(n) { return n > 1; } });
11175      * // => true
11176      *
11177      * _.conformsTo(object, { 'b': function(n) { return n > 2; } });
11178      * // => false
11179      */
11180     function conformsTo(object, source) {
11181       return source == null || baseConformsTo(object, source, keys(source));
11182     }
11183
11184     /**
11185      * Performs a
11186      * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)
11187      * comparison between two values to determine if they are equivalent.
11188      *
11189      * @static
11190      * @memberOf _
11191      * @since 4.0.0
11192      * @category Lang
11193      * @param {*} value The value to compare.
11194      * @param {*} other The other value to compare.
11195      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11196      * @example
11197      *
11198      * var object = { 'a': 1 };
11199      * var other = { 'a': 1 };
11200      *
11201      * _.eq(object, object);
11202      * // => true
11203      *
11204      * _.eq(object, other);
11205      * // => false
11206      *
11207      * _.eq('a', 'a');
11208      * // => true
11209      *
11210      * _.eq('a', Object('a'));
11211      * // => false
11212      *
11213      * _.eq(NaN, NaN);
11214      * // => true
11215      */
11216     function eq(value, other) {
11217       return value === other || (value !== value && other !== other);
11218     }
11219
11220     /**
11221      * Checks if `value` is greater than `other`.
11222      *
11223      * @static
11224      * @memberOf _
11225      * @since 3.9.0
11226      * @category Lang
11227      * @param {*} value The value to compare.
11228      * @param {*} other The other value to compare.
11229      * @returns {boolean} Returns `true` if `value` is greater than `other`,
11230      *  else `false`.
11231      * @see _.lt
11232      * @example
11233      *
11234      * _.gt(3, 1);
11235      * // => true
11236      *
11237      * _.gt(3, 3);
11238      * // => false
11239      *
11240      * _.gt(1, 3);
11241      * // => false
11242      */
11243     var gt = createRelationalOperation(baseGt);
11244
11245     /**
11246      * Checks if `value` is greater than or equal to `other`.
11247      *
11248      * @static
11249      * @memberOf _
11250      * @since 3.9.0
11251      * @category Lang
11252      * @param {*} value The value to compare.
11253      * @param {*} other The other value to compare.
11254      * @returns {boolean} Returns `true` if `value` is greater than or equal to
11255      *  `other`, else `false`.
11256      * @see _.lte
11257      * @example
11258      *
11259      * _.gte(3, 1);
11260      * // => true
11261      *
11262      * _.gte(3, 3);
11263      * // => true
11264      *
11265      * _.gte(1, 3);
11266      * // => false
11267      */
11268     var gte = createRelationalOperation(function(value, other) {
11269       return value >= other;
11270     });
11271
11272     /**
11273      * Checks if `value` is likely an `arguments` object.
11274      *
11275      * @static
11276      * @memberOf _
11277      * @since 0.1.0
11278      * @category Lang
11279      * @param {*} value The value to check.
11280      * @returns {boolean} Returns `true` if `value` is an `arguments` object,
11281      *  else `false`.
11282      * @example
11283      *
11284      * _.isArguments(function() { return arguments; }());
11285      * // => true
11286      *
11287      * _.isArguments([1, 2, 3]);
11288      * // => false
11289      */
11290     var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {
11291       return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&
11292         !propertyIsEnumerable.call(value, 'callee');
11293     };
11294
11295     /**
11296      * Checks if `value` is classified as an `Array` object.
11297      *
11298      * @static
11299      * @memberOf _
11300      * @since 0.1.0
11301      * @category Lang
11302      * @param {*} value The value to check.
11303      * @returns {boolean} Returns `true` if `value` is an array, else `false`.
11304      * @example
11305      *
11306      * _.isArray([1, 2, 3]);
11307      * // => true
11308      *
11309      * _.isArray(document.body.children);
11310      * // => false
11311      *
11312      * _.isArray('abc');
11313      * // => false
11314      *
11315      * _.isArray(_.noop);
11316      * // => false
11317      */
11318     var isArray = Array.isArray;
11319
11320     /**
11321      * Checks if `value` is classified as an `ArrayBuffer` object.
11322      *
11323      * @static
11324      * @memberOf _
11325      * @since 4.3.0
11326      * @category Lang
11327      * @param {*} value The value to check.
11328      * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.
11329      * @example
11330      *
11331      * _.isArrayBuffer(new ArrayBuffer(2));
11332      * // => true
11333      *
11334      * _.isArrayBuffer(new Array(2));
11335      * // => false
11336      */
11337     var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer;
11338
11339     /**
11340      * Checks if `value` is array-like. A value is considered array-like if it's
11341      * not a function and has a `value.length` that's an integer greater than or
11342      * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
11343      *
11344      * @static
11345      * @memberOf _
11346      * @since 4.0.0
11347      * @category Lang
11348      * @param {*} value The value to check.
11349      * @returns {boolean} Returns `true` if `value` is array-like, else `false`.
11350      * @example
11351      *
11352      * _.isArrayLike([1, 2, 3]);
11353      * // => true
11354      *
11355      * _.isArrayLike(document.body.children);
11356      * // => true
11357      *
11358      * _.isArrayLike('abc');
11359      * // => true
11360      *
11361      * _.isArrayLike(_.noop);
11362      * // => false
11363      */
11364     function isArrayLike(value) {
11365       return value != null && isLength(value.length) && !isFunction(value);
11366     }
11367
11368     /**
11369      * This method is like `_.isArrayLike` except that it also checks if `value`
11370      * is an object.
11371      *
11372      * @static
11373      * @memberOf _
11374      * @since 4.0.0
11375      * @category Lang
11376      * @param {*} value The value to check.
11377      * @returns {boolean} Returns `true` if `value` is an array-like object,
11378      *  else `false`.
11379      * @example
11380      *
11381      * _.isArrayLikeObject([1, 2, 3]);
11382      * // => true
11383      *
11384      * _.isArrayLikeObject(document.body.children);
11385      * // => true
11386      *
11387      * _.isArrayLikeObject('abc');
11388      * // => false
11389      *
11390      * _.isArrayLikeObject(_.noop);
11391      * // => false
11392      */
11393     function isArrayLikeObject(value) {
11394       return isObjectLike(value) && isArrayLike(value);
11395     }
11396
11397     /**
11398      * Checks if `value` is classified as a boolean primitive or object.
11399      *
11400      * @static
11401      * @memberOf _
11402      * @since 0.1.0
11403      * @category Lang
11404      * @param {*} value The value to check.
11405      * @returns {boolean} Returns `true` if `value` is a boolean, else `false`.
11406      * @example
11407      *
11408      * _.isBoolean(false);
11409      * // => true
11410      *
11411      * _.isBoolean(null);
11412      * // => false
11413      */
11414     function isBoolean(value) {
11415       return value === true || value === false ||
11416         (isObjectLike(value) && baseGetTag(value) == boolTag);
11417     }
11418
11419     /**
11420      * Checks if `value` is a buffer.
11421      *
11422      * @static
11423      * @memberOf _
11424      * @since 4.3.0
11425      * @category Lang
11426      * @param {*} value The value to check.
11427      * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
11428      * @example
11429      *
11430      * _.isBuffer(new Buffer(2));
11431      * // => true
11432      *
11433      * _.isBuffer(new Uint8Array(2));
11434      * // => false
11435      */
11436     var isBuffer = nativeIsBuffer || stubFalse;
11437
11438     /**
11439      * Checks if `value` is classified as a `Date` object.
11440      *
11441      * @static
11442      * @memberOf _
11443      * @since 0.1.0
11444      * @category Lang
11445      * @param {*} value The value to check.
11446      * @returns {boolean} Returns `true` if `value` is a date object, else `false`.
11447      * @example
11448      *
11449      * _.isDate(new Date);
11450      * // => true
11451      *
11452      * _.isDate('Mon April 23 2012');
11453      * // => false
11454      */
11455     var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;
11456
11457     /**
11458      * Checks if `value` is likely a DOM element.
11459      *
11460      * @static
11461      * @memberOf _
11462      * @since 0.1.0
11463      * @category Lang
11464      * @param {*} value The value to check.
11465      * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.
11466      * @example
11467      *
11468      * _.isElement(document.body);
11469      * // => true
11470      *
11471      * _.isElement('<body>');
11472      * // => false
11473      */
11474     function isElement(value) {
11475       return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);
11476     }
11477
11478     /**
11479      * Checks if `value` is an empty object, collection, map, or set.
11480      *
11481      * Objects are considered empty if they have no own enumerable string keyed
11482      * properties.
11483      *
11484      * Array-like values such as `arguments` objects, arrays, buffers, strings, or
11485      * jQuery-like collections are considered empty if they have a `length` of `0`.
11486      * Similarly, maps and sets are considered empty if they have a `size` of `0`.
11487      *
11488      * @static
11489      * @memberOf _
11490      * @since 0.1.0
11491      * @category Lang
11492      * @param {*} value The value to check.
11493      * @returns {boolean} Returns `true` if `value` is empty, else `false`.
11494      * @example
11495      *
11496      * _.isEmpty(null);
11497      * // => true
11498      *
11499      * _.isEmpty(true);
11500      * // => true
11501      *
11502      * _.isEmpty(1);
11503      * // => true
11504      *
11505      * _.isEmpty([1, 2, 3]);
11506      * // => false
11507      *
11508      * _.isEmpty({ 'a': 1 });
11509      * // => false
11510      */
11511     function isEmpty(value) {
11512       if (value == null) {
11513         return true;
11514       }
11515       if (isArrayLike(value) &&
11516           (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' ||
11517             isBuffer(value) || isTypedArray(value) || isArguments(value))) {
11518         return !value.length;
11519       }
11520       var tag = getTag(value);
11521       if (tag == mapTag || tag == setTag) {
11522         return !value.size;
11523       }
11524       if (isPrototype(value)) {
11525         return !baseKeys(value).length;
11526       }
11527       for (var key in value) {
11528         if (hasOwnProperty.call(value, key)) {
11529           return false;
11530         }
11531       }
11532       return true;
11533     }
11534
11535     /**
11536      * Performs a deep comparison between two values to determine if they are
11537      * equivalent.
11538      *
11539      * **Note:** This method supports comparing arrays, array buffers, booleans,
11540      * date objects, error objects, maps, numbers, `Object` objects, regexes,
11541      * sets, strings, symbols, and typed arrays. `Object` objects are compared
11542      * by their own, not inherited, enumerable properties. Functions and DOM
11543      * nodes are compared by strict equality, i.e. `===`.
11544      *
11545      * @static
11546      * @memberOf _
11547      * @since 0.1.0
11548      * @category Lang
11549      * @param {*} value The value to compare.
11550      * @param {*} other The other value to compare.
11551      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11552      * @example
11553      *
11554      * var object = { 'a': 1 };
11555      * var other = { 'a': 1 };
11556      *
11557      * _.isEqual(object, other);
11558      * // => true
11559      *
11560      * object === other;
11561      * // => false
11562      */
11563     function isEqual(value, other) {
11564       return baseIsEqual(value, other);
11565     }
11566
11567     /**
11568      * This method is like `_.isEqual` except that it accepts `customizer` which
11569      * is invoked to compare values. If `customizer` returns `undefined`, comparisons
11570      * are handled by the method instead. The `customizer` is invoked with up to
11571      * six arguments: (objValue, othValue [, index|key, object, other, stack]).
11572      *
11573      * @static
11574      * @memberOf _
11575      * @since 4.0.0
11576      * @category Lang
11577      * @param {*} value The value to compare.
11578      * @param {*} other The other value to compare.
11579      * @param {Function} [customizer] The function to customize comparisons.
11580      * @returns {boolean} Returns `true` if the values are equivalent, else `false`.
11581      * @example
11582      *
11583      * function isGreeting(value) {
11584      *   return /^h(?:i|ello)$/.test(value);
11585      * }
11586      *
11587      * function customizer(objValue, othValue) {
11588      *   if (isGreeting(objValue) && isGreeting(othValue)) {
11589      *     return true;
11590      *   }
11591      * }
11592      *
11593      * var array = ['hello', 'goodbye'];
11594      * var other = ['hi', 'goodbye'];
11595      *
11596      * _.isEqualWith(array, other, customizer);
11597      * // => true
11598      */
11599     function isEqualWith(value, other, customizer) {
11600       customizer = typeof customizer == 'function' ? customizer : undefined;
11601       var result = customizer ? customizer(value, other) : undefined;
11602       return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;
11603     }
11604
11605     /**
11606      * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
11607      * `SyntaxError`, `TypeError`, or `URIError` object.
11608      *
11609      * @static
11610      * @memberOf _
11611      * @since 3.0.0
11612      * @category Lang
11613      * @param {*} value The value to check.
11614      * @returns {boolean} Returns `true` if `value` is an error object, else `false`.
11615      * @example
11616      *
11617      * _.isError(new Error);
11618      * // => true
11619      *
11620      * _.isError(Error);
11621      * // => false
11622      */
11623     function isError(value) {
11624       if (!isObjectLike(value)) {
11625         return false;
11626       }
11627       var tag = baseGetTag(value);
11628       return tag == errorTag || tag == domExcTag ||
11629         (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value));
11630     }
11631
11632     /**
11633      * Checks if `value` is a finite primitive number.
11634      *
11635      * **Note:** This method is based on
11636      * [`Number.isFinite`](https://mdn.io/Number/isFinite).
11637      *
11638      * @static
11639      * @memberOf _
11640      * @since 0.1.0
11641      * @category Lang
11642      * @param {*} value The value to check.
11643      * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.
11644      * @example
11645      *
11646      * _.isFinite(3);
11647      * // => true
11648      *
11649      * _.isFinite(Number.MIN_VALUE);
11650      * // => true
11651      *
11652      * _.isFinite(Infinity);
11653      * // => false
11654      *
11655      * _.isFinite('3');
11656      * // => false
11657      */
11658     function isFinite(value) {
11659       return typeof value == 'number' && nativeIsFinite(value);
11660     }
11661
11662     /**
11663      * Checks if `value` is classified as a `Function` object.
11664      *
11665      * @static
11666      * @memberOf _
11667      * @since 0.1.0
11668      * @category Lang
11669      * @param {*} value The value to check.
11670      * @returns {boolean} Returns `true` if `value` is a function, else `false`.
11671      * @example
11672      *
11673      * _.isFunction(_);
11674      * // => true
11675      *
11676      * _.isFunction(/abc/);
11677      * // => false
11678      */
11679     function isFunction(value) {
11680       if (!isObject(value)) {
11681         return false;
11682       }
11683       // The use of `Object#toString` avoids issues with the `typeof` operator
11684       // in Safari 9 which returns 'object' for typed arrays and other constructors.
11685       var tag = baseGetTag(value);
11686       return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;
11687     }
11688
11689     /**
11690      * Checks if `value` is an integer.
11691      *
11692      * **Note:** This method is based on
11693      * [`Number.isInteger`](https://mdn.io/Number/isInteger).
11694      *
11695      * @static
11696      * @memberOf _
11697      * @since 4.0.0
11698      * @category Lang
11699      * @param {*} value The value to check.
11700      * @returns {boolean} Returns `true` if `value` is an integer, else `false`.
11701      * @example
11702      *
11703      * _.isInteger(3);
11704      * // => true
11705      *
11706      * _.isInteger(Number.MIN_VALUE);
11707      * // => false
11708      *
11709      * _.isInteger(Infinity);
11710      * // => false
11711      *
11712      * _.isInteger('3');
11713      * // => false
11714      */
11715     function isInteger(value) {
11716       return typeof value == 'number' && value == toInteger(value);
11717     }
11718
11719     /**
11720      * Checks if `value` is a valid array-like length.
11721      *
11722      * **Note:** This method is loosely based on
11723      * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
11724      *
11725      * @static
11726      * @memberOf _
11727      * @since 4.0.0
11728      * @category Lang
11729      * @param {*} value The value to check.
11730      * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.
11731      * @example
11732      *
11733      * _.isLength(3);
11734      * // => true
11735      *
11736      * _.isLength(Number.MIN_VALUE);
11737      * // => false
11738      *
11739      * _.isLength(Infinity);
11740      * // => false
11741      *
11742      * _.isLength('3');
11743      * // => false
11744      */
11745     function isLength(value) {
11746       return typeof value == 'number' &&
11747         value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
11748     }
11749
11750     /**
11751      * Checks if `value` is the
11752      * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
11753      * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
11754      *
11755      * @static
11756      * @memberOf _
11757      * @since 0.1.0
11758      * @category Lang
11759      * @param {*} value The value to check.
11760      * @returns {boolean} Returns `true` if `value` is an object, else `false`.
11761      * @example
11762      *
11763      * _.isObject({});
11764      * // => true
11765      *
11766      * _.isObject([1, 2, 3]);
11767      * // => true
11768      *
11769      * _.isObject(_.noop);
11770      * // => true
11771      *
11772      * _.isObject(null);
11773      * // => false
11774      */
11775     function isObject(value) {
11776       var type = typeof value;
11777       return value != null && (type == 'object' || type == 'function');
11778     }
11779
11780     /**
11781      * Checks if `value` is object-like. A value is object-like if it's not `null`
11782      * and has a `typeof` result of "object".
11783      *
11784      * @static
11785      * @memberOf _
11786      * @since 4.0.0
11787      * @category Lang
11788      * @param {*} value The value to check.
11789      * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
11790      * @example
11791      *
11792      * _.isObjectLike({});
11793      * // => true
11794      *
11795      * _.isObjectLike([1, 2, 3]);
11796      * // => true
11797      *
11798      * _.isObjectLike(_.noop);
11799      * // => false
11800      *
11801      * _.isObjectLike(null);
11802      * // => false
11803      */
11804     function isObjectLike(value) {
11805       return value != null && typeof value == 'object';
11806     }
11807
11808     /**
11809      * Checks if `value` is classified as a `Map` object.
11810      *
11811      * @static
11812      * @memberOf _
11813      * @since 4.3.0
11814      * @category Lang
11815      * @param {*} value The value to check.
11816      * @returns {boolean} Returns `true` if `value` is a map, else `false`.
11817      * @example
11818      *
11819      * _.isMap(new Map);
11820      * // => true
11821      *
11822      * _.isMap(new WeakMap);
11823      * // => false
11824      */
11825     var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;
11826
11827     /**
11828      * Performs a partial deep comparison between `object` and `source` to
11829      * determine if `object` contains equivalent property values.
11830      *
11831      * **Note:** This method is equivalent to `_.matches` when `source` is
11832      * partially applied.
11833      *
11834      * Partial comparisons will match empty array and empty object `source`
11835      * values against any array or object value, respectively. See `_.isEqual`
11836      * for a list of supported value comparisons.
11837      *
11838      * @static
11839      * @memberOf _
11840      * @since 3.0.0
11841      * @category Lang
11842      * @param {Object} object The object to inspect.
11843      * @param {Object} source The object of property values to match.
11844      * @returns {boolean} Returns `true` if `object` is a match, else `false`.
11845      * @example
11846      *
11847      * var object = { 'a': 1, 'b': 2 };
11848      *
11849      * _.isMatch(object, { 'b': 2 });
11850      * // => true
11851      *
11852      * _.isMatch(object, { 'b': 1 });
11853      * // => false
11854      */
11855     function isMatch(object, source) {
11856       return object === source || baseIsMatch(object, source, getMatchData(source));
11857     }
11858
11859     /**
11860      * This method is like `_.isMatch` except that it accepts `customizer` which
11861      * is invoked to compare values. If `customizer` returns `undefined`, comparisons
11862      * are handled by the method instead. The `customizer` is invoked with five
11863      * arguments: (objValue, srcValue, index|key, object, source).
11864      *
11865      * @static
11866      * @memberOf _
11867      * @since 4.0.0
11868      * @category Lang
11869      * @param {Object} object The object to inspect.
11870      * @param {Object} source The object of property values to match.
11871      * @param {Function} [customizer] The function to customize comparisons.
11872      * @returns {boolean} Returns `true` if `object` is a match, else `false`.
11873      * @example
11874      *
11875      * function isGreeting(value) {
11876      *   return /^h(?:i|ello)$/.test(value);
11877      * }
11878      *
11879      * function customizer(objValue, srcValue) {
11880      *   if (isGreeting(objValue) && isGreeting(srcValue)) {
11881      *     return true;
11882      *   }
11883      * }
11884      *
11885      * var object = { 'greeting': 'hello' };
11886      * var source = { 'greeting': 'hi' };
11887      *
11888      * _.isMatchWith(object, source, customizer);
11889      * // => true
11890      */
11891     function isMatchWith(object, source, customizer) {
11892       customizer = typeof customizer == 'function' ? customizer : undefined;
11893       return baseIsMatch(object, source, getMatchData(source), customizer);
11894     }
11895
11896     /**
11897      * Checks if `value` is `NaN`.
11898      *
11899      * **Note:** This method is based on
11900      * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as
11901      * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for
11902      * `undefined` and other non-number values.
11903      *
11904      * @static
11905      * @memberOf _
11906      * @since 0.1.0
11907      * @category Lang
11908      * @param {*} value The value to check.
11909      * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
11910      * @example
11911      *
11912      * _.isNaN(NaN);
11913      * // => true
11914      *
11915      * _.isNaN(new Number(NaN));
11916      * // => true
11917      *
11918      * isNaN(undefined);
11919      * // => true
11920      *
11921      * _.isNaN(undefined);
11922      * // => false
11923      */
11924     function isNaN(value) {
11925       // An `NaN` primitive is the only value that is not equal to itself.
11926       // Perform the `toStringTag` check first to avoid errors with some
11927       // ActiveX objects in IE.
11928       return isNumber(value) && value != +value;
11929     }
11930
11931     /**
11932      * Checks if `value` is a pristine native function.
11933      *
11934      * **Note:** This method can't reliably detect native functions in the presence
11935      * of the core-js package because core-js circumvents this kind of detection.
11936      * Despite multiple requests, the core-js maintainer has made it clear: any
11937      * attempt to fix the detection will be obstructed. As a result, we're left
11938      * with little choice but to throw an error. Unfortunately, this also affects
11939      * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill),
11940      * which rely on core-js.
11941      *
11942      * @static
11943      * @memberOf _
11944      * @since 3.0.0
11945      * @category Lang
11946      * @param {*} value The value to check.
11947      * @returns {boolean} Returns `true` if `value` is a native function,
11948      *  else `false`.
11949      * @example
11950      *
11951      * _.isNative(Array.prototype.push);
11952      * // => true
11953      *
11954      * _.isNative(_);
11955      * // => false
11956      */
11957     function isNative(value) {
11958       if (isMaskable(value)) {
11959         throw new Error(CORE_ERROR_TEXT);
11960       }
11961       return baseIsNative(value);
11962     }
11963
11964     /**
11965      * Checks if `value` is `null`.
11966      *
11967      * @static
11968      * @memberOf _
11969      * @since 0.1.0
11970      * @category Lang
11971      * @param {*} value The value to check.
11972      * @returns {boolean} Returns `true` if `value` is `null`, else `false`.
11973      * @example
11974      *
11975      * _.isNull(null);
11976      * // => true
11977      *
11978      * _.isNull(void 0);
11979      * // => false
11980      */
11981     function isNull(value) {
11982       return value === null;
11983     }
11984
11985     /**
11986      * Checks if `value` is `null` or `undefined`.
11987      *
11988      * @static
11989      * @memberOf _
11990      * @since 4.0.0
11991      * @category Lang
11992      * @param {*} value The value to check.
11993      * @returns {boolean} Returns `true` if `value` is nullish, else `false`.
11994      * @example
11995      *
11996      * _.isNil(null);
11997      * // => true
11998      *
11999      * _.isNil(void 0);
12000      * // => true
12001      *
12002      * _.isNil(NaN);
12003      * // => false
12004      */
12005     function isNil(value) {
12006       return value == null;
12007     }
12008
12009     /**
12010      * Checks if `value` is classified as a `Number` primitive or object.
12011      *
12012      * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are
12013      * classified as numbers, use the `_.isFinite` method.
12014      *
12015      * @static
12016      * @memberOf _
12017      * @since 0.1.0
12018      * @category Lang
12019      * @param {*} value The value to check.
12020      * @returns {boolean} Returns `true` if `value` is a number, else `false`.
12021      * @example
12022      *
12023      * _.isNumber(3);
12024      * // => true
12025      *
12026      * _.isNumber(Number.MIN_VALUE);
12027      * // => true
12028      *
12029      * _.isNumber(Infinity);
12030      * // => true
12031      *
12032      * _.isNumber('3');
12033      * // => false
12034      */
12035     function isNumber(value) {
12036       return typeof value == 'number' ||
12037         (isObjectLike(value) && baseGetTag(value) == numberTag);
12038     }
12039
12040     /**
12041      * Checks if `value` is a plain object, that is, an object created by the
12042      * `Object` constructor or one with a `[[Prototype]]` of `null`.
12043      *
12044      * @static
12045      * @memberOf _
12046      * @since 0.8.0
12047      * @category Lang
12048      * @param {*} value The value to check.
12049      * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
12050      * @example
12051      *
12052      * function Foo() {
12053      *   this.a = 1;
12054      * }
12055      *
12056      * _.isPlainObject(new Foo);
12057      * // => false
12058      *
12059      * _.isPlainObject([1, 2, 3]);
12060      * // => false
12061      *
12062      * _.isPlainObject({ 'x': 0, 'y': 0 });
12063      * // => true
12064      *
12065      * _.isPlainObject(Object.create(null));
12066      * // => true
12067      */
12068     function isPlainObject(value) {
12069       if (!isObjectLike(value) || baseGetTag(value) != objectTag) {
12070         return false;
12071       }
12072       var proto = getPrototype(value);
12073       if (proto === null) {
12074         return true;
12075       }
12076       var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
12077       return typeof Ctor == 'function' && Ctor instanceof Ctor &&
12078         funcToString.call(Ctor) == objectCtorString;
12079     }
12080
12081     /**
12082      * Checks if `value` is classified as a `RegExp` object.
12083      *
12084      * @static
12085      * @memberOf _
12086      * @since 0.1.0
12087      * @category Lang
12088      * @param {*} value The value to check.
12089      * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.
12090      * @example
12091      *
12092      * _.isRegExp(/abc/);
12093      * // => true
12094      *
12095      * _.isRegExp('/abc/');
12096      * // => false
12097      */
12098     var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp;
12099
12100     /**
12101      * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754
12102      * double precision number which isn't the result of a rounded unsafe integer.
12103      *
12104      * **Note:** This method is based on
12105      * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger).
12106      *
12107      * @static
12108      * @memberOf _
12109      * @since 4.0.0
12110      * @category Lang
12111      * @param {*} value The value to check.
12112      * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`.
12113      * @example
12114      *
12115      * _.isSafeInteger(3);
12116      * // => true
12117      *
12118      * _.isSafeInteger(Number.MIN_VALUE);
12119      * // => false
12120      *
12121      * _.isSafeInteger(Infinity);
12122      * // => false
12123      *
12124      * _.isSafeInteger('3');
12125      * // => false
12126      */
12127     function isSafeInteger(value) {
12128       return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
12129     }
12130
12131     /**
12132      * Checks if `value` is classified as a `Set` object.
12133      *
12134      * @static
12135      * @memberOf _
12136      * @since 4.3.0
12137      * @category Lang
12138      * @param {*} value The value to check.
12139      * @returns {boolean} Returns `true` if `value` is a set, else `false`.
12140      * @example
12141      *
12142      * _.isSet(new Set);
12143      * // => true
12144      *
12145      * _.isSet(new WeakSet);
12146      * // => false
12147      */
12148     var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;
12149
12150     /**
12151      * Checks if `value` is classified as a `String` primitive or object.
12152      *
12153      * @static
12154      * @since 0.1.0
12155      * @memberOf _
12156      * @category Lang
12157      * @param {*} value The value to check.
12158      * @returns {boolean} Returns `true` if `value` is a string, else `false`.
12159      * @example
12160      *
12161      * _.isString('abc');
12162      * // => true
12163      *
12164      * _.isString(1);
12165      * // => false
12166      */
12167     function isString(value) {
12168       return typeof value == 'string' ||
12169         (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);
12170     }
12171
12172     /**
12173      * Checks if `value` is classified as a `Symbol` primitive or object.
12174      *
12175      * @static
12176      * @memberOf _
12177      * @since 4.0.0
12178      * @category Lang
12179      * @param {*} value The value to check.
12180      * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
12181      * @example
12182      *
12183      * _.isSymbol(Symbol.iterator);
12184      * // => true
12185      *
12186      * _.isSymbol('abc');
12187      * // => false
12188      */
12189     function isSymbol(value) {
12190       return typeof value == 'symbol' ||
12191         (isObjectLike(value) && baseGetTag(value) == symbolTag);
12192     }
12193
12194     /**
12195      * Checks if `value` is classified as a typed array.
12196      *
12197      * @static
12198      * @memberOf _
12199      * @since 3.0.0
12200      * @category Lang
12201      * @param {*} value The value to check.
12202      * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.
12203      * @example
12204      *
12205      * _.isTypedArray(new Uint8Array);
12206      * // => true
12207      *
12208      * _.isTypedArray([]);
12209      * // => false
12210      */
12211     var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;
12212
12213     /**
12214      * Checks if `value` is `undefined`.
12215      *
12216      * @static
12217      * @since 0.1.0
12218      * @memberOf _
12219      * @category Lang
12220      * @param {*} value The value to check.
12221      * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
12222      * @example
12223      *
12224      * _.isUndefined(void 0);
12225      * // => true
12226      *
12227      * _.isUndefined(null);
12228      * // => false
12229      */
12230     function isUndefined(value) {
12231       return value === undefined;
12232     }
12233
12234     /**
12235      * Checks if `value` is classified as a `WeakMap` object.
12236      *
12237      * @static
12238      * @memberOf _
12239      * @since 4.3.0
12240      * @category Lang
12241      * @param {*} value The value to check.
12242      * @returns {boolean} Returns `true` if `value` is a weak map, else `false`.
12243      * @example
12244      *
12245      * _.isWeakMap(new WeakMap);
12246      * // => true
12247      *
12248      * _.isWeakMap(new Map);
12249      * // => false
12250      */
12251     function isWeakMap(value) {
12252       return isObjectLike(value) && getTag(value) == weakMapTag;
12253     }
12254
12255     /**
12256      * Checks if `value` is classified as a `WeakSet` object.
12257      *
12258      * @static
12259      * @memberOf _
12260      * @since 4.3.0
12261      * @category Lang
12262      * @param {*} value The value to check.
12263      * @returns {boolean} Returns `true` if `value` is a weak set, else `false`.
12264      * @example
12265      *
12266      * _.isWeakSet(new WeakSet);
12267      * // => true
12268      *
12269      * _.isWeakSet(new Set);
12270      * // => false
12271      */
12272     function isWeakSet(value) {
12273       return isObjectLike(value) && baseGetTag(value) == weakSetTag;
12274     }
12275
12276     /**
12277      * Checks if `value` is less than `other`.
12278      *
12279      * @static
12280      * @memberOf _
12281      * @since 3.9.0
12282      * @category Lang
12283      * @param {*} value The value to compare.
12284      * @param {*} other The other value to compare.
12285      * @returns {boolean} Returns `true` if `value` is less than `other`,
12286      *  else `false`.
12287      * @see _.gt
12288      * @example
12289      *
12290      * _.lt(1, 3);
12291      * // => true
12292      *
12293      * _.lt(3, 3);
12294      * // => false
12295      *
12296      * _.lt(3, 1);
12297      * // => false
12298      */
12299     var lt = createRelationalOperation(baseLt);
12300
12301     /**
12302      * Checks if `value` is less than or equal to `other`.
12303      *
12304      * @static
12305      * @memberOf _
12306      * @since 3.9.0
12307      * @category Lang
12308      * @param {*} value The value to compare.
12309      * @param {*} other The other value to compare.
12310      * @returns {boolean} Returns `true` if `value` is less than or equal to
12311      *  `other`, else `false`.
12312      * @see _.gte
12313      * @example
12314      *
12315      * _.lte(1, 3);
12316      * // => true
12317      *
12318      * _.lte(3, 3);
12319      * // => true
12320      *
12321      * _.lte(3, 1);
12322      * // => false
12323      */
12324     var lte = createRelationalOperation(function(value, other) {
12325       return value <= other;
12326     });
12327
12328     /**
12329      * Converts `value` to an array.
12330      *
12331      * @static
12332      * @since 0.1.0
12333      * @memberOf _
12334      * @category Lang
12335      * @param {*} value The value to convert.
12336      * @returns {Array} Returns the converted array.
12337      * @example
12338      *
12339      * _.toArray({ 'a': 1, 'b': 2 });
12340      * // => [1, 2]
12341      *
12342      * _.toArray('abc');
12343      * // => ['a', 'b', 'c']
12344      *
12345      * _.toArray(1);
12346      * // => []
12347      *
12348      * _.toArray(null);
12349      * // => []
12350      */
12351     function toArray(value) {
12352       if (!value) {
12353         return [];
12354       }
12355       if (isArrayLike(value)) {
12356         return isString(value) ? stringToArray(value) : copyArray(value);
12357       }
12358       if (symIterator && value[symIterator]) {
12359         return iteratorToArray(value[symIterator]());
12360       }
12361       var tag = getTag(value),
12362           func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);
12363
12364       return func(value);
12365     }
12366
12367     /**
12368      * Converts `value` to a finite number.
12369      *
12370      * @static
12371      * @memberOf _
12372      * @since 4.12.0
12373      * @category Lang
12374      * @param {*} value The value to convert.
12375      * @returns {number} Returns the converted number.
12376      * @example
12377      *
12378      * _.toFinite(3.2);
12379      * // => 3.2
12380      *
12381      * _.toFinite(Number.MIN_VALUE);
12382      * // => 5e-324
12383      *
12384      * _.toFinite(Infinity);
12385      * // => 1.7976931348623157e+308
12386      *
12387      * _.toFinite('3.2');
12388      * // => 3.2
12389      */
12390     function toFinite(value) {
12391       if (!value) {
12392         return value === 0 ? value : 0;
12393       }
12394       value = toNumber(value);
12395       if (value === INFINITY || value === -INFINITY) {
12396         var sign = (value < 0 ? -1 : 1);
12397         return sign * MAX_INTEGER;
12398       }
12399       return value === value ? value : 0;
12400     }
12401
12402     /**
12403      * Converts `value` to an integer.
12404      *
12405      * **Note:** This method is loosely based on
12406      * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).
12407      *
12408      * @static
12409      * @memberOf _
12410      * @since 4.0.0
12411      * @category Lang
12412      * @param {*} value The value to convert.
12413      * @returns {number} Returns the converted integer.
12414      * @example
12415      *
12416      * _.toInteger(3.2);
12417      * // => 3
12418      *
12419      * _.toInteger(Number.MIN_VALUE);
12420      * // => 0
12421      *
12422      * _.toInteger(Infinity);
12423      * // => 1.7976931348623157e+308
12424      *
12425      * _.toInteger('3.2');
12426      * // => 3
12427      */
12428     function toInteger(value) {
12429       var result = toFinite(value),
12430           remainder = result % 1;
12431
12432       return result === result ? (remainder ? result - remainder : result) : 0;
12433     }
12434
12435     /**
12436      * Converts `value` to an integer suitable for use as the length of an
12437      * array-like object.
12438      *
12439      * **Note:** This method is based on
12440      * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).
12441      *
12442      * @static
12443      * @memberOf _
12444      * @since 4.0.0
12445      * @category Lang
12446      * @param {*} value The value to convert.
12447      * @returns {number} Returns the converted integer.
12448      * @example
12449      *
12450      * _.toLength(3.2);
12451      * // => 3
12452      *
12453      * _.toLength(Number.MIN_VALUE);
12454      * // => 0
12455      *
12456      * _.toLength(Infinity);
12457      * // => 4294967295
12458      *
12459      * _.toLength('3.2');
12460      * // => 3
12461      */
12462     function toLength(value) {
12463       return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0;
12464     }
12465
12466     /**
12467      * Converts `value` to a number.
12468      *
12469      * @static
12470      * @memberOf _
12471      * @since 4.0.0
12472      * @category Lang
12473      * @param {*} value The value to process.
12474      * @returns {number} Returns the number.
12475      * @example
12476      *
12477      * _.toNumber(3.2);
12478      * // => 3.2
12479      *
12480      * _.toNumber(Number.MIN_VALUE);
12481      * // => 5e-324
12482      *
12483      * _.toNumber(Infinity);
12484      * // => Infinity
12485      *
12486      * _.toNumber('3.2');
12487      * // => 3.2
12488      */
12489     function toNumber(value) {
12490       if (typeof value == 'number') {
12491         return value;
12492       }
12493       if (isSymbol(value)) {
12494         return NAN;
12495       }
12496       if (isObject(value)) {
12497         var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
12498         value = isObject(other) ? (other + '') : other;
12499       }
12500       if (typeof value != 'string') {
12501         return value === 0 ? value : +value;
12502       }
12503       value = value.replace(reTrim, '');
12504       var isBinary = reIsBinary.test(value);
12505       return (isBinary || reIsOctal.test(value))
12506         ? freeParseInt(value.slice(2), isBinary ? 2 : 8)
12507         : (reIsBadHex.test(value) ? NAN : +value);
12508     }
12509
12510     /**
12511      * Converts `value` to a plain object flattening inherited enumerable string
12512      * keyed properties of `value` to own properties of the plain object.
12513      *
12514      * @static
12515      * @memberOf _
12516      * @since 3.0.0
12517      * @category Lang
12518      * @param {*} value The value to convert.
12519      * @returns {Object} Returns the converted plain object.
12520      * @example
12521      *
12522      * function Foo() {
12523      *   this.b = 2;
12524      * }
12525      *
12526      * Foo.prototype.c = 3;
12527      *
12528      * _.assign({ 'a': 1 }, new Foo);
12529      * // => { 'a': 1, 'b': 2 }
12530      *
12531      * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
12532      * // => { 'a': 1, 'b': 2, 'c': 3 }
12533      */
12534     function toPlainObject(value) {
12535       return copyObject(value, keysIn(value));
12536     }
12537
12538     /**
12539      * Converts `value` to a safe integer. A safe integer can be compared and
12540      * represented correctly.
12541      *
12542      * @static
12543      * @memberOf _
12544      * @since 4.0.0
12545      * @category Lang
12546      * @param {*} value The value to convert.
12547      * @returns {number} Returns the converted integer.
12548      * @example
12549      *
12550      * _.toSafeInteger(3.2);
12551      * // => 3
12552      *
12553      * _.toSafeInteger(Number.MIN_VALUE);
12554      * // => 0
12555      *
12556      * _.toSafeInteger(Infinity);
12557      * // => 9007199254740991
12558      *
12559      * _.toSafeInteger('3.2');
12560      * // => 3
12561      */
12562     function toSafeInteger(value) {
12563       return value
12564         ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER)
12565         : (value === 0 ? value : 0);
12566     }
12567
12568     /**
12569      * Converts `value` to a string. An empty string is returned for `null`
12570      * and `undefined` values. The sign of `-0` is preserved.
12571      *
12572      * @static
12573      * @memberOf _
12574      * @since 4.0.0
12575      * @category Lang
12576      * @param {*} value The value to convert.
12577      * @returns {string} Returns the converted string.
12578      * @example
12579      *
12580      * _.toString(null);
12581      * // => ''
12582      *
12583      * _.toString(-0);
12584      * // => '-0'
12585      *
12586      * _.toString([1, 2, 3]);
12587      * // => '1,2,3'
12588      */
12589     function toString(value) {
12590       return value == null ? '' : baseToString(value);
12591     }
12592
12593     /*------------------------------------------------------------------------*/
12594
12595     /**
12596      * Assigns own enumerable string keyed properties of source objects to the
12597      * destination object. Source objects are applied from left to right.
12598      * Subsequent sources overwrite property assignments of previous sources.
12599      *
12600      * **Note:** This method mutates `object` and is loosely based on
12601      * [`Object.assign`](https://mdn.io/Object/assign).
12602      *
12603      * @static
12604      * @memberOf _
12605      * @since 0.10.0
12606      * @category Object
12607      * @param {Object} object The destination object.
12608      * @param {...Object} [sources] The source objects.
12609      * @returns {Object} Returns `object`.
12610      * @see _.assignIn
12611      * @example
12612      *
12613      * function Foo() {
12614      *   this.a = 1;
12615      * }
12616      *
12617      * function Bar() {
12618      *   this.c = 3;
12619      * }
12620      *
12621      * Foo.prototype.b = 2;
12622      * Bar.prototype.d = 4;
12623      *
12624      * _.assign({ 'a': 0 }, new Foo, new Bar);
12625      * // => { 'a': 1, 'c': 3 }
12626      */
12627     var assign = createAssigner(function(object, source) {
12628       if (isPrototype(source) || isArrayLike(source)) {
12629         copyObject(source, keys(source), object);
12630         return;
12631       }
12632       for (var key in source) {
12633         if (hasOwnProperty.call(source, key)) {
12634           assignValue(object, key, source[key]);
12635         }
12636       }
12637     });
12638
12639     /**
12640      * This method is like `_.assign` except that it iterates over own and
12641      * inherited source properties.
12642      *
12643      * **Note:** This method mutates `object`.
12644      *
12645      * @static
12646      * @memberOf _
12647      * @since 4.0.0
12648      * @alias extend
12649      * @category Object
12650      * @param {Object} object The destination object.
12651      * @param {...Object} [sources] The source objects.
12652      * @returns {Object} Returns `object`.
12653      * @see _.assign
12654      * @example
12655      *
12656      * function Foo() {
12657      *   this.a = 1;
12658      * }
12659      *
12660      * function Bar() {
12661      *   this.c = 3;
12662      * }
12663      *
12664      * Foo.prototype.b = 2;
12665      * Bar.prototype.d = 4;
12666      *
12667      * _.assignIn({ 'a': 0 }, new Foo, new Bar);
12668      * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }
12669      */
12670     var assignIn = createAssigner(function(object, source) {
12671       copyObject(source, keysIn(source), object);
12672     });
12673
12674     /**
12675      * This method is like `_.assignIn` except that it accepts `customizer`
12676      * which is invoked to produce the assigned values. If `customizer` returns
12677      * `undefined`, assignment is handled by the method instead. The `customizer`
12678      * is invoked with five arguments: (objValue, srcValue, key, object, source).
12679      *
12680      * **Note:** This method mutates `object`.
12681      *
12682      * @static
12683      * @memberOf _
12684      * @since 4.0.0
12685      * @alias extendWith
12686      * @category Object
12687      * @param {Object} object The destination object.
12688      * @param {...Object} sources The source objects.
12689      * @param {Function} [customizer] The function to customize assigned values.
12690      * @returns {Object} Returns `object`.
12691      * @see _.assignWith
12692      * @example
12693      *
12694      * function customizer(objValue, srcValue) {
12695      *   return _.isUndefined(objValue) ? srcValue : objValue;
12696      * }
12697      *
12698      * var defaults = _.partialRight(_.assignInWith, customizer);
12699      *
12700      * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
12701      * // => { 'a': 1, 'b': 2 }
12702      */
12703     var assignInWith = createAssigner(function(object, source, srcIndex, customizer) {
12704       copyObject(source, keysIn(source), object, customizer);
12705     });
12706
12707     /**
12708      * This method is like `_.assign` except that it accepts `customizer`
12709      * which is invoked to produce the assigned values. If `customizer` returns
12710      * `undefined`, assignment is handled by the method instead. The `customizer`
12711      * is invoked with five arguments: (objValue, srcValue, key, object, source).
12712      *
12713      * **Note:** This method mutates `object`.
12714      *
12715      * @static
12716      * @memberOf _
12717      * @since 4.0.0
12718      * @category Object
12719      * @param {Object} object The destination object.
12720      * @param {...Object} sources The source objects.
12721      * @param {Function} [customizer] The function to customize assigned values.
12722      * @returns {Object} Returns `object`.
12723      * @see _.assignInWith
12724      * @example
12725      *
12726      * function customizer(objValue, srcValue) {
12727      *   return _.isUndefined(objValue) ? srcValue : objValue;
12728      * }
12729      *
12730      * var defaults = _.partialRight(_.assignWith, customizer);
12731      *
12732      * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
12733      * // => { 'a': 1, 'b': 2 }
12734      */
12735     var assignWith = createAssigner(function(object, source, srcIndex, customizer) {
12736       copyObject(source, keys(source), object, customizer);
12737     });
12738
12739     /**
12740      * Creates an array of values corresponding to `paths` of `object`.
12741      *
12742      * @static
12743      * @memberOf _
12744      * @since 1.0.0
12745      * @category Object
12746      * @param {Object} object The object to iterate over.
12747      * @param {...(string|string[])} [paths] The property paths to pick.
12748      * @returns {Array} Returns the picked values.
12749      * @example
12750      *
12751      * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
12752      *
12753      * _.at(object, ['a[0].b.c', 'a[1]']);
12754      * // => [3, 4]
12755      */
12756     var at = flatRest(baseAt);
12757
12758     /**
12759      * Creates an object that inherits from the `prototype` object. If a
12760      * `properties` object is given, its own enumerable string keyed properties
12761      * are assigned to the created object.
12762      *
12763      * @static
12764      * @memberOf _
12765      * @since 2.3.0
12766      * @category Object
12767      * @param {Object} prototype The object to inherit from.
12768      * @param {Object} [properties] The properties to assign to the object.
12769      * @returns {Object} Returns the new object.
12770      * @example
12771      *
12772      * function Shape() {
12773      *   this.x = 0;
12774      *   this.y = 0;
12775      * }
12776      *
12777      * function Circle() {
12778      *   Shape.call(this);
12779      * }
12780      *
12781      * Circle.prototype = _.create(Shape.prototype, {
12782      *   'constructor': Circle
12783      * });
12784      *
12785      * var circle = new Circle;
12786      * circle instanceof Circle;
12787      * // => true
12788      *
12789      * circle instanceof Shape;
12790      * // => true
12791      */
12792     function create(prototype, properties) {
12793       var result = baseCreate(prototype);
12794       return properties == null ? result : baseAssign(result, properties);
12795     }
12796
12797     /**
12798      * Assigns own and inherited enumerable string keyed properties of source
12799      * objects to the destination object for all destination properties that
12800      * resolve to `undefined`. Source objects are applied from left to right.
12801      * Once a property is set, additional values of the same property are ignored.
12802      *
12803      * **Note:** This method mutates `object`.
12804      *
12805      * @static
12806      * @since 0.1.0
12807      * @memberOf _
12808      * @category Object
12809      * @param {Object} object The destination object.
12810      * @param {...Object} [sources] The source objects.
12811      * @returns {Object} Returns `object`.
12812      * @see _.defaultsDeep
12813      * @example
12814      *
12815      * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
12816      * // => { 'a': 1, 'b': 2 }
12817      */
12818     var defaults = baseRest(function(args) {
12819       args.push(undefined, customDefaultsAssignIn);
12820       return apply(assignInWith, undefined, args);
12821     });
12822
12823     /**
12824      * This method is like `_.defaults` except that it recursively assigns
12825      * default properties.
12826      *
12827      * **Note:** This method mutates `object`.
12828      *
12829      * @static
12830      * @memberOf _
12831      * @since 3.10.0
12832      * @category Object
12833      * @param {Object} object The destination object.
12834      * @param {...Object} [sources] The source objects.
12835      * @returns {Object} Returns `object`.
12836      * @see _.defaults
12837      * @example
12838      *
12839      * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });
12840      * // => { 'a': { 'b': 2, 'c': 3 } }
12841      */
12842     var defaultsDeep = baseRest(function(args) {
12843       args.push(undefined, customDefaultsMerge);
12844       return apply(mergeWith, undefined, args);
12845     });
12846
12847     /**
12848      * This method is like `_.find` except that it returns the key of the first
12849      * element `predicate` returns truthy for instead of the element itself.
12850      *
12851      * @static
12852      * @memberOf _
12853      * @since 1.1.0
12854      * @category Object
12855      * @param {Object} object The object to inspect.
12856      * @param {Function} [predicate=_.identity] The function invoked per iteration.
12857      * @returns {string|undefined} Returns the key of the matched element,
12858      *  else `undefined`.
12859      * @example
12860      *
12861      * var users = {
12862      *   'barney':  { 'age': 36, 'active': true },
12863      *   'fred':    { 'age': 40, 'active': false },
12864      *   'pebbles': { 'age': 1,  'active': true }
12865      * };
12866      *
12867      * _.findKey(users, function(o) { return o.age < 40; });
12868      * // => 'barney' (iteration order is not guaranteed)
12869      *
12870      * // The `_.matches` iteratee shorthand.
12871      * _.findKey(users, { 'age': 1, 'active': true });
12872      * // => 'pebbles'
12873      *
12874      * // The `_.matchesProperty` iteratee shorthand.
12875      * _.findKey(users, ['active', false]);
12876      * // => 'fred'
12877      *
12878      * // The `_.property` iteratee shorthand.
12879      * _.findKey(users, 'active');
12880      * // => 'barney'
12881      */
12882     function findKey(object, predicate) {
12883       return baseFindKey(object, getIteratee(predicate, 3), baseForOwn);
12884     }
12885
12886     /**
12887      * This method is like `_.findKey` except that it iterates over elements of
12888      * a collection in the opposite order.
12889      *
12890      * @static
12891      * @memberOf _
12892      * @since 2.0.0
12893      * @category Object
12894      * @param {Object} object The object to inspect.
12895      * @param {Function} [predicate=_.identity] The function invoked per iteration.
12896      * @returns {string|undefined} Returns the key of the matched element,
12897      *  else `undefined`.
12898      * @example
12899      *
12900      * var users = {
12901      *   'barney':  { 'age': 36, 'active': true },
12902      *   'fred':    { 'age': 40, 'active': false },
12903      *   'pebbles': { 'age': 1,  'active': true }
12904      * };
12905      *
12906      * _.findLastKey(users, function(o) { return o.age < 40; });
12907      * // => returns 'pebbles' assuming `_.findKey` returns 'barney'
12908      *
12909      * // The `_.matches` iteratee shorthand.
12910      * _.findLastKey(users, { 'age': 36, 'active': true });
12911      * // => 'barney'
12912      *
12913      * // The `_.matchesProperty` iteratee shorthand.
12914      * _.findLastKey(users, ['active', false]);
12915      * // => 'fred'
12916      *
12917      * // The `_.property` iteratee shorthand.
12918      * _.findLastKey(users, 'active');
12919      * // => 'pebbles'
12920      */
12921     function findLastKey(object, predicate) {
12922       return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight);
12923     }
12924
12925     /**
12926      * Iterates over own and inherited enumerable string keyed properties of an
12927      * object and invokes `iteratee` for each property. The iteratee is invoked
12928      * with three arguments: (value, key, object). Iteratee functions may exit
12929      * iteration early by explicitly returning `false`.
12930      *
12931      * @static
12932      * @memberOf _
12933      * @since 0.3.0
12934      * @category Object
12935      * @param {Object} object The object to iterate over.
12936      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12937      * @returns {Object} Returns `object`.
12938      * @see _.forInRight
12939      * @example
12940      *
12941      * function Foo() {
12942      *   this.a = 1;
12943      *   this.b = 2;
12944      * }
12945      *
12946      * Foo.prototype.c = 3;
12947      *
12948      * _.forIn(new Foo, function(value, key) {
12949      *   console.log(key);
12950      * });
12951      * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).
12952      */
12953     function forIn(object, iteratee) {
12954       return object == null
12955         ? object
12956         : baseFor(object, getIteratee(iteratee, 3), keysIn);
12957     }
12958
12959     /**
12960      * This method is like `_.forIn` except that it iterates over properties of
12961      * `object` in the opposite order.
12962      *
12963      * @static
12964      * @memberOf _
12965      * @since 2.0.0
12966      * @category Object
12967      * @param {Object} object The object to iterate over.
12968      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
12969      * @returns {Object} Returns `object`.
12970      * @see _.forIn
12971      * @example
12972      *
12973      * function Foo() {
12974      *   this.a = 1;
12975      *   this.b = 2;
12976      * }
12977      *
12978      * Foo.prototype.c = 3;
12979      *
12980      * _.forInRight(new Foo, function(value, key) {
12981      *   console.log(key);
12982      * });
12983      * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'.
12984      */
12985     function forInRight(object, iteratee) {
12986       return object == null
12987         ? object
12988         : baseForRight(object, getIteratee(iteratee, 3), keysIn);
12989     }
12990
12991     /**
12992      * Iterates over own enumerable string keyed properties of an object and
12993      * invokes `iteratee` for each property. The iteratee is invoked with three
12994      * arguments: (value, key, object). Iteratee functions may exit iteration
12995      * early by explicitly returning `false`.
12996      *
12997      * @static
12998      * @memberOf _
12999      * @since 0.3.0
13000      * @category Object
13001      * @param {Object} object The object to iterate over.
13002      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13003      * @returns {Object} Returns `object`.
13004      * @see _.forOwnRight
13005      * @example
13006      *
13007      * function Foo() {
13008      *   this.a = 1;
13009      *   this.b = 2;
13010      * }
13011      *
13012      * Foo.prototype.c = 3;
13013      *
13014      * _.forOwn(new Foo, function(value, key) {
13015      *   console.log(key);
13016      * });
13017      * // => Logs 'a' then 'b' (iteration order is not guaranteed).
13018      */
13019     function forOwn(object, iteratee) {
13020       return object && baseForOwn(object, getIteratee(iteratee, 3));
13021     }
13022
13023     /**
13024      * This method is like `_.forOwn` except that it iterates over properties of
13025      * `object` in the opposite order.
13026      *
13027      * @static
13028      * @memberOf _
13029      * @since 2.0.0
13030      * @category Object
13031      * @param {Object} object The object to iterate over.
13032      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13033      * @returns {Object} Returns `object`.
13034      * @see _.forOwn
13035      * @example
13036      *
13037      * function Foo() {
13038      *   this.a = 1;
13039      *   this.b = 2;
13040      * }
13041      *
13042      * Foo.prototype.c = 3;
13043      *
13044      * _.forOwnRight(new Foo, function(value, key) {
13045      *   console.log(key);
13046      * });
13047      * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.
13048      */
13049     function forOwnRight(object, iteratee) {
13050       return object && baseForOwnRight(object, getIteratee(iteratee, 3));
13051     }
13052
13053     /**
13054      * Creates an array of function property names from own enumerable properties
13055      * of `object`.
13056      *
13057      * @static
13058      * @since 0.1.0
13059      * @memberOf _
13060      * @category Object
13061      * @param {Object} object The object to inspect.
13062      * @returns {Array} Returns the function names.
13063      * @see _.functionsIn
13064      * @example
13065      *
13066      * function Foo() {
13067      *   this.a = _.constant('a');
13068      *   this.b = _.constant('b');
13069      * }
13070      *
13071      * Foo.prototype.c = _.constant('c');
13072      *
13073      * _.functions(new Foo);
13074      * // => ['a', 'b']
13075      */
13076     function functions(object) {
13077       return object == null ? [] : baseFunctions(object, keys(object));
13078     }
13079
13080     /**
13081      * Creates an array of function property names from own and inherited
13082      * enumerable properties of `object`.
13083      *
13084      * @static
13085      * @memberOf _
13086      * @since 4.0.0
13087      * @category Object
13088      * @param {Object} object The object to inspect.
13089      * @returns {Array} Returns the function names.
13090      * @see _.functions
13091      * @example
13092      *
13093      * function Foo() {
13094      *   this.a = _.constant('a');
13095      *   this.b = _.constant('b');
13096      * }
13097      *
13098      * Foo.prototype.c = _.constant('c');
13099      *
13100      * _.functionsIn(new Foo);
13101      * // => ['a', 'b', 'c']
13102      */
13103     function functionsIn(object) {
13104       return object == null ? [] : baseFunctions(object, keysIn(object));
13105     }
13106
13107     /**
13108      * Gets the value at `path` of `object`. If the resolved value is
13109      * `undefined`, the `defaultValue` is returned in its place.
13110      *
13111      * @static
13112      * @memberOf _
13113      * @since 3.7.0
13114      * @category Object
13115      * @param {Object} object The object to query.
13116      * @param {Array|string} path The path of the property to get.
13117      * @param {*} [defaultValue] The value returned for `undefined` resolved values.
13118      * @returns {*} Returns the resolved value.
13119      * @example
13120      *
13121      * var object = { 'a': [{ 'b': { 'c': 3 } }] };
13122      *
13123      * _.get(object, 'a[0].b.c');
13124      * // => 3
13125      *
13126      * _.get(object, ['a', '0', 'b', 'c']);
13127      * // => 3
13128      *
13129      * _.get(object, 'a.b.c', 'default');
13130      * // => 'default'
13131      */
13132     function get(object, path, defaultValue) {
13133       var result = object == null ? undefined : baseGet(object, path);
13134       return result === undefined ? defaultValue : result;
13135     }
13136
13137     /**
13138      * Checks if `path` is a direct property of `object`.
13139      *
13140      * @static
13141      * @since 0.1.0
13142      * @memberOf _
13143      * @category Object
13144      * @param {Object} object The object to query.
13145      * @param {Array|string} path The path to check.
13146      * @returns {boolean} Returns `true` if `path` exists, else `false`.
13147      * @example
13148      *
13149      * var object = { 'a': { 'b': 2 } };
13150      * var other = _.create({ 'a': _.create({ 'b': 2 }) });
13151      *
13152      * _.has(object, 'a');
13153      * // => true
13154      *
13155      * _.has(object, 'a.b');
13156      * // => true
13157      *
13158      * _.has(object, ['a', 'b']);
13159      * // => true
13160      *
13161      * _.has(other, 'a');
13162      * // => false
13163      */
13164     function has(object, path) {
13165       return object != null && hasPath(object, path, baseHas);
13166     }
13167
13168     /**
13169      * Checks if `path` is a direct or inherited property of `object`.
13170      *
13171      * @static
13172      * @memberOf _
13173      * @since 4.0.0
13174      * @category Object
13175      * @param {Object} object The object to query.
13176      * @param {Array|string} path The path to check.
13177      * @returns {boolean} Returns `true` if `path` exists, else `false`.
13178      * @example
13179      *
13180      * var object = _.create({ 'a': _.create({ 'b': 2 }) });
13181      *
13182      * _.hasIn(object, 'a');
13183      * // => true
13184      *
13185      * _.hasIn(object, 'a.b');
13186      * // => true
13187      *
13188      * _.hasIn(object, ['a', 'b']);
13189      * // => true
13190      *
13191      * _.hasIn(object, 'b');
13192      * // => false
13193      */
13194     function hasIn(object, path) {
13195       return object != null && hasPath(object, path, baseHasIn);
13196     }
13197
13198     /**
13199      * Creates an object composed of the inverted keys and values of `object`.
13200      * If `object` contains duplicate values, subsequent values overwrite
13201      * property assignments of previous values.
13202      *
13203      * @static
13204      * @memberOf _
13205      * @since 0.7.0
13206      * @category Object
13207      * @param {Object} object The object to invert.
13208      * @returns {Object} Returns the new inverted object.
13209      * @example
13210      *
13211      * var object = { 'a': 1, 'b': 2, 'c': 1 };
13212      *
13213      * _.invert(object);
13214      * // => { '1': 'c', '2': 'b' }
13215      */
13216     var invert = createInverter(function(result, value, key) {
13217       result[value] = key;
13218     }, constant(identity));
13219
13220     /**
13221      * This method is like `_.invert` except that the inverted object is generated
13222      * from the results of running each element of `object` thru `iteratee`. The
13223      * corresponding inverted value of each inverted key is an array of keys
13224      * responsible for generating the inverted value. The iteratee is invoked
13225      * with one argument: (value).
13226      *
13227      * @static
13228      * @memberOf _
13229      * @since 4.1.0
13230      * @category Object
13231      * @param {Object} object The object to invert.
13232      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
13233      * @returns {Object} Returns the new inverted object.
13234      * @example
13235      *
13236      * var object = { 'a': 1, 'b': 2, 'c': 1 };
13237      *
13238      * _.invertBy(object);
13239      * // => { '1': ['a', 'c'], '2': ['b'] }
13240      *
13241      * _.invertBy(object, function(value) {
13242      *   return 'group' + value;
13243      * });
13244      * // => { 'group1': ['a', 'c'], 'group2': ['b'] }
13245      */
13246     var invertBy = createInverter(function(result, value, key) {
13247       if (hasOwnProperty.call(result, value)) {
13248         result[value].push(key);
13249       } else {
13250         result[value] = [key];
13251       }
13252     }, getIteratee);
13253
13254     /**
13255      * Invokes the method at `path` of `object`.
13256      *
13257      * @static
13258      * @memberOf _
13259      * @since 4.0.0
13260      * @category Object
13261      * @param {Object} object The object to query.
13262      * @param {Array|string} path The path of the method to invoke.
13263      * @param {...*} [args] The arguments to invoke the method with.
13264      * @returns {*} Returns the result of the invoked method.
13265      * @example
13266      *
13267      * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] };
13268      *
13269      * _.invoke(object, 'a[0].b.c.slice', 1, 3);
13270      * // => [2, 3]
13271      */
13272     var invoke = baseRest(baseInvoke);
13273
13274     /**
13275      * Creates an array of the own enumerable property names of `object`.
13276      *
13277      * **Note:** Non-object values are coerced to objects. See the
13278      * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
13279      * for more details.
13280      *
13281      * @static
13282      * @since 0.1.0
13283      * @memberOf _
13284      * @category Object
13285      * @param {Object} object The object to query.
13286      * @returns {Array} Returns the array of property names.
13287      * @example
13288      *
13289      * function Foo() {
13290      *   this.a = 1;
13291      *   this.b = 2;
13292      * }
13293      *
13294      * Foo.prototype.c = 3;
13295      *
13296      * _.keys(new Foo);
13297      * // => ['a', 'b'] (iteration order is not guaranteed)
13298      *
13299      * _.keys('hi');
13300      * // => ['0', '1']
13301      */
13302     function keys(object) {
13303       return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
13304     }
13305
13306     /**
13307      * Creates an array of the own and inherited enumerable property names of `object`.
13308      *
13309      * **Note:** Non-object values are coerced to objects.
13310      *
13311      * @static
13312      * @memberOf _
13313      * @since 3.0.0
13314      * @category Object
13315      * @param {Object} object The object to query.
13316      * @returns {Array} Returns the array of property names.
13317      * @example
13318      *
13319      * function Foo() {
13320      *   this.a = 1;
13321      *   this.b = 2;
13322      * }
13323      *
13324      * Foo.prototype.c = 3;
13325      *
13326      * _.keysIn(new Foo);
13327      * // => ['a', 'b', 'c'] (iteration order is not guaranteed)
13328      */
13329     function keysIn(object) {
13330       return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);
13331     }
13332
13333     /**
13334      * The opposite of `_.mapValues`; this method creates an object with the
13335      * same values as `object` and keys generated by running each own enumerable
13336      * string keyed property of `object` thru `iteratee`. The iteratee is invoked
13337      * with three arguments: (value, key, object).
13338      *
13339      * @static
13340      * @memberOf _
13341      * @since 3.8.0
13342      * @category Object
13343      * @param {Object} object The object to iterate over.
13344      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13345      * @returns {Object} Returns the new mapped object.
13346      * @see _.mapValues
13347      * @example
13348      *
13349      * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
13350      *   return key + value;
13351      * });
13352      * // => { 'a1': 1, 'b2': 2 }
13353      */
13354     function mapKeys(object, iteratee) {
13355       var result = {};
13356       iteratee = getIteratee(iteratee, 3);
13357
13358       baseForOwn(object, function(value, key, object) {
13359         baseAssignValue(result, iteratee(value, key, object), value);
13360       });
13361       return result;
13362     }
13363
13364     /**
13365      * Creates an object with the same keys as `object` and values generated
13366      * by running each own enumerable string keyed property of `object` thru
13367      * `iteratee`. The iteratee is invoked with three arguments:
13368      * (value, key, object).
13369      *
13370      * @static
13371      * @memberOf _
13372      * @since 2.4.0
13373      * @category Object
13374      * @param {Object} object The object to iterate over.
13375      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13376      * @returns {Object} Returns the new mapped object.
13377      * @see _.mapKeys
13378      * @example
13379      *
13380      * var users = {
13381      *   'fred':    { 'user': 'fred',    'age': 40 },
13382      *   'pebbles': { 'user': 'pebbles', 'age': 1 }
13383      * };
13384      *
13385      * _.mapValues(users, function(o) { return o.age; });
13386      * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
13387      *
13388      * // The `_.property` iteratee shorthand.
13389      * _.mapValues(users, 'age');
13390      * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
13391      */
13392     function mapValues(object, iteratee) {
13393       var result = {};
13394       iteratee = getIteratee(iteratee, 3);
13395
13396       baseForOwn(object, function(value, key, object) {
13397         baseAssignValue(result, key, iteratee(value, key, object));
13398       });
13399       return result;
13400     }
13401
13402     /**
13403      * This method is like `_.assign` except that it recursively merges own and
13404      * inherited enumerable string keyed properties of source objects into the
13405      * destination object. Source properties that resolve to `undefined` are
13406      * skipped if a destination value exists. Array and plain object properties
13407      * are merged recursively. Other objects and value types are overridden by
13408      * assignment. Source objects are applied from left to right. Subsequent
13409      * sources overwrite property assignments of previous sources.
13410      *
13411      * **Note:** This method mutates `object`.
13412      *
13413      * @static
13414      * @memberOf _
13415      * @since 0.5.0
13416      * @category Object
13417      * @param {Object} object The destination object.
13418      * @param {...Object} [sources] The source objects.
13419      * @returns {Object} Returns `object`.
13420      * @example
13421      *
13422      * var object = {
13423      *   'a': [{ 'b': 2 }, { 'd': 4 }]
13424      * };
13425      *
13426      * var other = {
13427      *   'a': [{ 'c': 3 }, { 'e': 5 }]
13428      * };
13429      *
13430      * _.merge(object, other);
13431      * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }
13432      */
13433     var merge = createAssigner(function(object, source, srcIndex) {
13434       baseMerge(object, source, srcIndex);
13435     });
13436
13437     /**
13438      * This method is like `_.merge` except that it accepts `customizer` which
13439      * is invoked to produce the merged values of the destination and source
13440      * properties. If `customizer` returns `undefined`, merging is handled by the
13441      * method instead. The `customizer` is invoked with six arguments:
13442      * (objValue, srcValue, key, object, source, stack).
13443      *
13444      * **Note:** This method mutates `object`.
13445      *
13446      * @static
13447      * @memberOf _
13448      * @since 4.0.0
13449      * @category Object
13450      * @param {Object} object The destination object.
13451      * @param {...Object} sources The source objects.
13452      * @param {Function} customizer The function to customize assigned values.
13453      * @returns {Object} Returns `object`.
13454      * @example
13455      *
13456      * function customizer(objValue, srcValue) {
13457      *   if (_.isArray(objValue)) {
13458      *     return objValue.concat(srcValue);
13459      *   }
13460      * }
13461      *
13462      * var object = { 'a': [1], 'b': [2] };
13463      * var other = { 'a': [3], 'b': [4] };
13464      *
13465      * _.mergeWith(object, other, customizer);
13466      * // => { 'a': [1, 3], 'b': [2, 4] }
13467      */
13468     var mergeWith = createAssigner(function(object, source, srcIndex, customizer) {
13469       baseMerge(object, source, srcIndex, customizer);
13470     });
13471
13472     /**
13473      * The opposite of `_.pick`; this method creates an object composed of the
13474      * own and inherited enumerable property paths of `object` that are not omitted.
13475      *
13476      * **Note:** This method is considerably slower than `_.pick`.
13477      *
13478      * @static
13479      * @since 0.1.0
13480      * @memberOf _
13481      * @category Object
13482      * @param {Object} object The source object.
13483      * @param {...(string|string[])} [paths] The property paths to omit.
13484      * @returns {Object} Returns the new object.
13485      * @example
13486      *
13487      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13488      *
13489      * _.omit(object, ['a', 'c']);
13490      * // => { 'b': '2' }
13491      */
13492     var omit = flatRest(function(object, paths) {
13493       var result = {};
13494       if (object == null) {
13495         return result;
13496       }
13497       var isDeep = false;
13498       paths = arrayMap(paths, function(path) {
13499         path = castPath(path, object);
13500         isDeep || (isDeep = path.length > 1);
13501         return path;
13502       });
13503       copyObject(object, getAllKeysIn(object), result);
13504       if (isDeep) {
13505         result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone);
13506       }
13507       var length = paths.length;
13508       while (length--) {
13509         baseUnset(result, paths[length]);
13510       }
13511       return result;
13512     });
13513
13514     /**
13515      * The opposite of `_.pickBy`; this method creates an object composed of
13516      * the own and inherited enumerable string keyed properties of `object` that
13517      * `predicate` doesn't return truthy for. The predicate is invoked with two
13518      * arguments: (value, key).
13519      *
13520      * @static
13521      * @memberOf _
13522      * @since 4.0.0
13523      * @category Object
13524      * @param {Object} object The source object.
13525      * @param {Function} [predicate=_.identity] The function invoked per property.
13526      * @returns {Object} Returns the new object.
13527      * @example
13528      *
13529      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13530      *
13531      * _.omitBy(object, _.isNumber);
13532      * // => { 'b': '2' }
13533      */
13534     function omitBy(object, predicate) {
13535       return pickBy(object, negate(getIteratee(predicate)));
13536     }
13537
13538     /**
13539      * Creates an object composed of the picked `object` properties.
13540      *
13541      * @static
13542      * @since 0.1.0
13543      * @memberOf _
13544      * @category Object
13545      * @param {Object} object The source object.
13546      * @param {...(string|string[])} [paths] The property paths to pick.
13547      * @returns {Object} Returns the new object.
13548      * @example
13549      *
13550      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13551      *
13552      * _.pick(object, ['a', 'c']);
13553      * // => { 'a': 1, 'c': 3 }
13554      */
13555     var pick = flatRest(function(object, paths) {
13556       return object == null ? {} : basePick(object, paths);
13557     });
13558
13559     /**
13560      * Creates an object composed of the `object` properties `predicate` returns
13561      * truthy for. The predicate is invoked with two arguments: (value, key).
13562      *
13563      * @static
13564      * @memberOf _
13565      * @since 4.0.0
13566      * @category Object
13567      * @param {Object} object The source object.
13568      * @param {Function} [predicate=_.identity] The function invoked per property.
13569      * @returns {Object} Returns the new object.
13570      * @example
13571      *
13572      * var object = { 'a': 1, 'b': '2', 'c': 3 };
13573      *
13574      * _.pickBy(object, _.isNumber);
13575      * // => { 'a': 1, 'c': 3 }
13576      */
13577     function pickBy(object, predicate) {
13578       if (object == null) {
13579         return {};
13580       }
13581       var props = arrayMap(getAllKeysIn(object), function(prop) {
13582         return [prop];
13583       });
13584       predicate = getIteratee(predicate);
13585       return basePickBy(object, props, function(value, path) {
13586         return predicate(value, path[0]);
13587       });
13588     }
13589
13590     /**
13591      * This method is like `_.get` except that if the resolved value is a
13592      * function it's invoked with the `this` binding of its parent object and
13593      * its result is returned.
13594      *
13595      * @static
13596      * @since 0.1.0
13597      * @memberOf _
13598      * @category Object
13599      * @param {Object} object The object to query.
13600      * @param {Array|string} path The path of the property to resolve.
13601      * @param {*} [defaultValue] The value returned for `undefined` resolved values.
13602      * @returns {*} Returns the resolved value.
13603      * @example
13604      *
13605      * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
13606      *
13607      * _.result(object, 'a[0].b.c1');
13608      * // => 3
13609      *
13610      * _.result(object, 'a[0].b.c2');
13611      * // => 4
13612      *
13613      * _.result(object, 'a[0].b.c3', 'default');
13614      * // => 'default'
13615      *
13616      * _.result(object, 'a[0].b.c3', _.constant('default'));
13617      * // => 'default'
13618      */
13619     function result(object, path, defaultValue) {
13620       path = castPath(path, object);
13621
13622       var index = -1,
13623           length = path.length;
13624
13625       // Ensure the loop is entered when path is empty.
13626       if (!length) {
13627         length = 1;
13628         object = undefined;
13629       }
13630       while (++index < length) {
13631         var value = object == null ? undefined : object[toKey(path[index])];
13632         if (value === undefined) {
13633           index = length;
13634           value = defaultValue;
13635         }
13636         object = isFunction(value) ? value.call(object) : value;
13637       }
13638       return object;
13639     }
13640
13641     /**
13642      * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
13643      * it's created. Arrays are created for missing index properties while objects
13644      * are created for all other missing properties. Use `_.setWith` to customize
13645      * `path` creation.
13646      *
13647      * **Note:** This method mutates `object`.
13648      *
13649      * @static
13650      * @memberOf _
13651      * @since 3.7.0
13652      * @category Object
13653      * @param {Object} object The object to modify.
13654      * @param {Array|string} path The path of the property to set.
13655      * @param {*} value The value to set.
13656      * @returns {Object} Returns `object`.
13657      * @example
13658      *
13659      * var object = { 'a': [{ 'b': { 'c': 3 } }] };
13660      *
13661      * _.set(object, 'a[0].b.c', 4);
13662      * console.log(object.a[0].b.c);
13663      * // => 4
13664      *
13665      * _.set(object, ['x', '0', 'y', 'z'], 5);
13666      * console.log(object.x[0].y.z);
13667      * // => 5
13668      */
13669     function set(object, path, value) {
13670       return object == null ? object : baseSet(object, path, value);
13671     }
13672
13673     /**
13674      * This method is like `_.set` except that it accepts `customizer` which is
13675      * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
13676      * path creation is handled by the method instead. The `customizer` is invoked
13677      * with three arguments: (nsValue, key, nsObject).
13678      *
13679      * **Note:** This method mutates `object`.
13680      *
13681      * @static
13682      * @memberOf _
13683      * @since 4.0.0
13684      * @category Object
13685      * @param {Object} object The object to modify.
13686      * @param {Array|string} path The path of the property to set.
13687      * @param {*} value The value to set.
13688      * @param {Function} [customizer] The function to customize assigned values.
13689      * @returns {Object} Returns `object`.
13690      * @example
13691      *
13692      * var object = {};
13693      *
13694      * _.setWith(object, '[0][1]', 'a', Object);
13695      * // => { '0': { '1': 'a' } }
13696      */
13697     function setWith(object, path, value, customizer) {
13698       customizer = typeof customizer == 'function' ? customizer : undefined;
13699       return object == null ? object : baseSet(object, path, value, customizer);
13700     }
13701
13702     /**
13703      * Creates an array of own enumerable string keyed-value pairs for `object`
13704      * which can be consumed by `_.fromPairs`. If `object` is a map or set, its
13705      * entries are returned.
13706      *
13707      * @static
13708      * @memberOf _
13709      * @since 4.0.0
13710      * @alias entries
13711      * @category Object
13712      * @param {Object} object The object to query.
13713      * @returns {Array} Returns the key-value pairs.
13714      * @example
13715      *
13716      * function Foo() {
13717      *   this.a = 1;
13718      *   this.b = 2;
13719      * }
13720      *
13721      * Foo.prototype.c = 3;
13722      *
13723      * _.toPairs(new Foo);
13724      * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
13725      */
13726     var toPairs = createToPairs(keys);
13727
13728     /**
13729      * Creates an array of own and inherited enumerable string keyed-value pairs
13730      * for `object` which can be consumed by `_.fromPairs`. If `object` is a map
13731      * or set, its entries are returned.
13732      *
13733      * @static
13734      * @memberOf _
13735      * @since 4.0.0
13736      * @alias entriesIn
13737      * @category Object
13738      * @param {Object} object The object to query.
13739      * @returns {Array} Returns the key-value pairs.
13740      * @example
13741      *
13742      * function Foo() {
13743      *   this.a = 1;
13744      *   this.b = 2;
13745      * }
13746      *
13747      * Foo.prototype.c = 3;
13748      *
13749      * _.toPairsIn(new Foo);
13750      * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed)
13751      */
13752     var toPairsIn = createToPairs(keysIn);
13753
13754     /**
13755      * An alternative to `_.reduce`; this method transforms `object` to a new
13756      * `accumulator` object which is the result of running each of its own
13757      * enumerable string keyed properties thru `iteratee`, with each invocation
13758      * potentially mutating the `accumulator` object. If `accumulator` is not
13759      * provided, a new object with the same `[[Prototype]]` will be used. The
13760      * iteratee is invoked with four arguments: (accumulator, value, key, object).
13761      * Iteratee functions may exit iteration early by explicitly returning `false`.
13762      *
13763      * @static
13764      * @memberOf _
13765      * @since 1.3.0
13766      * @category Object
13767      * @param {Object} object The object to iterate over.
13768      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
13769      * @param {*} [accumulator] The custom accumulator value.
13770      * @returns {*} Returns the accumulated value.
13771      * @example
13772      *
13773      * _.transform([2, 3, 4], function(result, n) {
13774      *   result.push(n *= n);
13775      *   return n % 2 == 0;
13776      * }, []);
13777      * // => [4, 9]
13778      *
13779      * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
13780      *   (result[value] || (result[value] = [])).push(key);
13781      * }, {});
13782      * // => { '1': ['a', 'c'], '2': ['b'] }
13783      */
13784     function transform(object, iteratee, accumulator) {
13785       var isArr = isArray(object),
13786           isArrLike = isArr || isBuffer(object) || isTypedArray(object);
13787
13788       iteratee = getIteratee(iteratee, 4);
13789       if (accumulator == null) {
13790         var Ctor = object && object.constructor;
13791         if (isArrLike) {
13792           accumulator = isArr ? new Ctor : [];
13793         }
13794         else if (isObject(object)) {
13795           accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {};
13796         }
13797         else {
13798           accumulator = {};
13799         }
13800       }
13801       (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) {
13802         return iteratee(accumulator, value, index, object);
13803       });
13804       return accumulator;
13805     }
13806
13807     /**
13808      * Removes the property at `path` of `object`.
13809      *
13810      * **Note:** This method mutates `object`.
13811      *
13812      * @static
13813      * @memberOf _
13814      * @since 4.0.0
13815      * @category Object
13816      * @param {Object} object The object to modify.
13817      * @param {Array|string} path The path of the property to unset.
13818      * @returns {boolean} Returns `true` if the property is deleted, else `false`.
13819      * @example
13820      *
13821      * var object = { 'a': [{ 'b': { 'c': 7 } }] };
13822      * _.unset(object, 'a[0].b.c');
13823      * // => true
13824      *
13825      * console.log(object);
13826      * // => { 'a': [{ 'b': {} }] };
13827      *
13828      * _.unset(object, ['a', '0', 'b', 'c']);
13829      * // => true
13830      *
13831      * console.log(object);
13832      * // => { 'a': [{ 'b': {} }] };
13833      */
13834     function unset(object, path) {
13835       return object == null ? true : baseUnset(object, path);
13836     }
13837
13838     /**
13839      * This method is like `_.set` except that accepts `updater` to produce the
13840      * value to set. Use `_.updateWith` to customize `path` creation. The `updater`
13841      * is invoked with one argument: (value).
13842      *
13843      * **Note:** This method mutates `object`.
13844      *
13845      * @static
13846      * @memberOf _
13847      * @since 4.6.0
13848      * @category Object
13849      * @param {Object} object The object to modify.
13850      * @param {Array|string} path The path of the property to set.
13851      * @param {Function} updater The function to produce the updated value.
13852      * @returns {Object} Returns `object`.
13853      * @example
13854      *
13855      * var object = { 'a': [{ 'b': { 'c': 3 } }] };
13856      *
13857      * _.update(object, 'a[0].b.c', function(n) { return n * n; });
13858      * console.log(object.a[0].b.c);
13859      * // => 9
13860      *
13861      * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; });
13862      * console.log(object.x[0].y.z);
13863      * // => 0
13864      */
13865     function update(object, path, updater) {
13866       return object == null ? object : baseUpdate(object, path, castFunction(updater));
13867     }
13868
13869     /**
13870      * This method is like `_.update` except that it accepts `customizer` which is
13871      * invoked to produce the objects of `path`.  If `customizer` returns `undefined`
13872      * path creation is handled by the method instead. The `customizer` is invoked
13873      * with three arguments: (nsValue, key, nsObject).
13874      *
13875      * **Note:** This method mutates `object`.
13876      *
13877      * @static
13878      * @memberOf _
13879      * @since 4.6.0
13880      * @category Object
13881      * @param {Object} object The object to modify.
13882      * @param {Array|string} path The path of the property to set.
13883      * @param {Function} updater The function to produce the updated value.
13884      * @param {Function} [customizer] The function to customize assigned values.
13885      * @returns {Object} Returns `object`.
13886      * @example
13887      *
13888      * var object = {};
13889      *
13890      * _.updateWith(object, '[0][1]', _.constant('a'), Object);
13891      * // => { '0': { '1': 'a' } }
13892      */
13893     function updateWith(object, path, updater, customizer) {
13894       customizer = typeof customizer == 'function' ? customizer : undefined;
13895       return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer);
13896     }
13897
13898     /**
13899      * Creates an array of the own enumerable string keyed property values of `object`.
13900      *
13901      * **Note:** Non-object values are coerced to objects.
13902      *
13903      * @static
13904      * @since 0.1.0
13905      * @memberOf _
13906      * @category Object
13907      * @param {Object} object The object to query.
13908      * @returns {Array} Returns the array of property values.
13909      * @example
13910      *
13911      * function Foo() {
13912      *   this.a = 1;
13913      *   this.b = 2;
13914      * }
13915      *
13916      * Foo.prototype.c = 3;
13917      *
13918      * _.values(new Foo);
13919      * // => [1, 2] (iteration order is not guaranteed)
13920      *
13921      * _.values('hi');
13922      * // => ['h', 'i']
13923      */
13924     function values(object) {
13925       return object == null ? [] : baseValues(object, keys(object));
13926     }
13927
13928     /**
13929      * Creates an array of the own and inherited enumerable string keyed property
13930      * values of `object`.
13931      *
13932      * **Note:** Non-object values are coerced to objects.
13933      *
13934      * @static
13935      * @memberOf _
13936      * @since 3.0.0
13937      * @category Object
13938      * @param {Object} object The object to query.
13939      * @returns {Array} Returns the array of property values.
13940      * @example
13941      *
13942      * function Foo() {
13943      *   this.a = 1;
13944      *   this.b = 2;
13945      * }
13946      *
13947      * Foo.prototype.c = 3;
13948      *
13949      * _.valuesIn(new Foo);
13950      * // => [1, 2, 3] (iteration order is not guaranteed)
13951      */
13952     function valuesIn(object) {
13953       return object == null ? [] : baseValues(object, keysIn(object));
13954     }
13955
13956     /*------------------------------------------------------------------------*/
13957
13958     /**
13959      * Clamps `number` within the inclusive `lower` and `upper` bounds.
13960      *
13961      * @static
13962      * @memberOf _
13963      * @since 4.0.0
13964      * @category Number
13965      * @param {number} number The number to clamp.
13966      * @param {number} [lower] The lower bound.
13967      * @param {number} upper The upper bound.
13968      * @returns {number} Returns the clamped number.
13969      * @example
13970      *
13971      * _.clamp(-10, -5, 5);
13972      * // => -5
13973      *
13974      * _.clamp(10, -5, 5);
13975      * // => 5
13976      */
13977     function clamp(number, lower, upper) {
13978       if (upper === undefined) {
13979         upper = lower;
13980         lower = undefined;
13981       }
13982       if (upper !== undefined) {
13983         upper = toNumber(upper);
13984         upper = upper === upper ? upper : 0;
13985       }
13986       if (lower !== undefined) {
13987         lower = toNumber(lower);
13988         lower = lower === lower ? lower : 0;
13989       }
13990       return baseClamp(toNumber(number), lower, upper);
13991     }
13992
13993     /**
13994      * Checks if `n` is between `start` and up to, but not including, `end`. If
13995      * `end` is not specified, it's set to `start` with `start` then set to `0`.
13996      * If `start` is greater than `end` the params are swapped to support
13997      * negative ranges.
13998      *
13999      * @static
14000      * @memberOf _
14001      * @since 3.3.0
14002      * @category Number
14003      * @param {number} number The number to check.
14004      * @param {number} [start=0] The start of the range.
14005      * @param {number} end The end of the range.
14006      * @returns {boolean} Returns `true` if `number` is in the range, else `false`.
14007      * @see _.range, _.rangeRight
14008      * @example
14009      *
14010      * _.inRange(3, 2, 4);
14011      * // => true
14012      *
14013      * _.inRange(4, 8);
14014      * // => true
14015      *
14016      * _.inRange(4, 2);
14017      * // => false
14018      *
14019      * _.inRange(2, 2);
14020      * // => false
14021      *
14022      * _.inRange(1.2, 2);
14023      * // => true
14024      *
14025      * _.inRange(5.2, 4);
14026      * // => false
14027      *
14028      * _.inRange(-3, -2, -6);
14029      * // => true
14030      */
14031     function inRange(number, start, end) {
14032       start = toFinite(start);
14033       if (end === undefined) {
14034         end = start;
14035         start = 0;
14036       } else {
14037         end = toFinite(end);
14038       }
14039       number = toNumber(number);
14040       return baseInRange(number, start, end);
14041     }
14042
14043     /**
14044      * Produces a random number between the inclusive `lower` and `upper` bounds.
14045      * If only one argument is provided a number between `0` and the given number
14046      * is returned. If `floating` is `true`, or either `lower` or `upper` are
14047      * floats, a floating-point number is returned instead of an integer.
14048      *
14049      * **Note:** JavaScript follows the IEEE-754 standard for resolving
14050      * floating-point values which can produce unexpected results.
14051      *
14052      * @static
14053      * @memberOf _
14054      * @since 0.7.0
14055      * @category Number
14056      * @param {number} [lower=0] The lower bound.
14057      * @param {number} [upper=1] The upper bound.
14058      * @param {boolean} [floating] Specify returning a floating-point number.
14059      * @returns {number} Returns the random number.
14060      * @example
14061      *
14062      * _.random(0, 5);
14063      * // => an integer between 0 and 5
14064      *
14065      * _.random(5);
14066      * // => also an integer between 0 and 5
14067      *
14068      * _.random(5, true);
14069      * // => a floating-point number between 0 and 5
14070      *
14071      * _.random(1.2, 5.2);
14072      * // => a floating-point number between 1.2 and 5.2
14073      */
14074     function random(lower, upper, floating) {
14075       if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) {
14076         upper = floating = undefined;
14077       }
14078       if (floating === undefined) {
14079         if (typeof upper == 'boolean') {
14080           floating = upper;
14081           upper = undefined;
14082         }
14083         else if (typeof lower == 'boolean') {
14084           floating = lower;
14085           lower = undefined;
14086         }
14087       }
14088       if (lower === undefined && upper === undefined) {
14089         lower = 0;
14090         upper = 1;
14091       }
14092       else {
14093         lower = toFinite(lower);
14094         if (upper === undefined) {
14095           upper = lower;
14096           lower = 0;
14097         } else {
14098           upper = toFinite(upper);
14099         }
14100       }
14101       if (lower > upper) {
14102         var temp = lower;
14103         lower = upper;
14104         upper = temp;
14105       }
14106       if (floating || lower % 1 || upper % 1) {
14107         var rand = nativeRandom();
14108         return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper);
14109       }
14110       return baseRandom(lower, upper);
14111     }
14112
14113     /*------------------------------------------------------------------------*/
14114
14115     /**
14116      * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
14117      *
14118      * @static
14119      * @memberOf _
14120      * @since 3.0.0
14121      * @category String
14122      * @param {string} [string=''] The string to convert.
14123      * @returns {string} Returns the camel cased string.
14124      * @example
14125      *
14126      * _.camelCase('Foo Bar');
14127      * // => 'fooBar'
14128      *
14129      * _.camelCase('--foo-bar--');
14130      * // => 'fooBar'
14131      *
14132      * _.camelCase('__FOO_BAR__');
14133      * // => 'fooBar'
14134      */
14135     var camelCase = createCompounder(function(result, word, index) {
14136       word = word.toLowerCase();
14137       return result + (index ? capitalize(word) : word);
14138     });
14139
14140     /**
14141      * Converts the first character of `string` to upper case and the remaining
14142      * to lower case.
14143      *
14144      * @static
14145      * @memberOf _
14146      * @since 3.0.0
14147      * @category String
14148      * @param {string} [string=''] The string to capitalize.
14149      * @returns {string} Returns the capitalized string.
14150      * @example
14151      *
14152      * _.capitalize('FRED');
14153      * // => 'Fred'
14154      */
14155     function capitalize(string) {
14156       return upperFirst(toString(string).toLowerCase());
14157     }
14158
14159     /**
14160      * Deburrs `string` by converting
14161      * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
14162      * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)
14163      * letters to basic Latin letters and removing
14164      * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
14165      *
14166      * @static
14167      * @memberOf _
14168      * @since 3.0.0
14169      * @category String
14170      * @param {string} [string=''] The string to deburr.
14171      * @returns {string} Returns the deburred string.
14172      * @example
14173      *
14174      * _.deburr('déjà vu');
14175      * // => 'deja vu'
14176      */
14177     function deburr(string) {
14178       string = toString(string);
14179       return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
14180     }
14181
14182     /**
14183      * Checks if `string` ends with the given target string.
14184      *
14185      * @static
14186      * @memberOf _
14187      * @since 3.0.0
14188      * @category String
14189      * @param {string} [string=''] The string to inspect.
14190      * @param {string} [target] The string to search for.
14191      * @param {number} [position=string.length] The position to search up to.
14192      * @returns {boolean} Returns `true` if `string` ends with `target`,
14193      *  else `false`.
14194      * @example
14195      *
14196      * _.endsWith('abc', 'c');
14197      * // => true
14198      *
14199      * _.endsWith('abc', 'b');
14200      * // => false
14201      *
14202      * _.endsWith('abc', 'b', 2);
14203      * // => true
14204      */
14205     function endsWith(string, target, position) {
14206       string = toString(string);
14207       target = baseToString(target);
14208
14209       var length = string.length;
14210       position = position === undefined
14211         ? length
14212         : baseClamp(toInteger(position), 0, length);
14213
14214       var end = position;
14215       position -= target.length;
14216       return position >= 0 && string.slice(position, end) == target;
14217     }
14218
14219     /**
14220      * Converts the characters "&", "<", ">", '"', and "'" in `string` to their
14221      * corresponding HTML entities.
14222      *
14223      * **Note:** No other characters are escaped. To escape additional
14224      * characters use a third-party library like [_he_](https://mths.be/he).
14225      *
14226      * Though the ">" character is escaped for symmetry, characters like
14227      * ">" and "/" don't need escaping in HTML and have no special meaning
14228      * unless they're part of a tag or unquoted attribute value. See
14229      * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)
14230      * (under "semi-related fun fact") for more details.
14231      *
14232      * When working with HTML you should always
14233      * [quote attribute values](http://wonko.com/post/html-escaping) to reduce
14234      * XSS vectors.
14235      *
14236      * @static
14237      * @since 0.1.0
14238      * @memberOf _
14239      * @category String
14240      * @param {string} [string=''] The string to escape.
14241      * @returns {string} Returns the escaped string.
14242      * @example
14243      *
14244      * _.escape('fred, barney, & pebbles');
14245      * // => 'fred, barney, &amp; pebbles'
14246      */
14247     function escape(string) {
14248       string = toString(string);
14249       return (string && reHasUnescapedHtml.test(string))
14250         ? string.replace(reUnescapedHtml, escapeHtmlChar)
14251         : string;
14252     }
14253
14254     /**
14255      * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
14256      * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
14257      *
14258      * @static
14259      * @memberOf _
14260      * @since 3.0.0
14261      * @category String
14262      * @param {string} [string=''] The string to escape.
14263      * @returns {string} Returns the escaped string.
14264      * @example
14265      *
14266      * _.escapeRegExp('[lodash](https://lodash.com/)');
14267      * // => '\[lodash\]\(https://lodash\.com/\)'
14268      */
14269     function escapeRegExp(string) {
14270       string = toString(string);
14271       return (string && reHasRegExpChar.test(string))
14272         ? string.replace(reRegExpChar, '\\$&')
14273         : string;
14274     }
14275
14276     /**
14277      * Converts `string` to
14278      * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
14279      *
14280      * @static
14281      * @memberOf _
14282      * @since 3.0.0
14283      * @category String
14284      * @param {string} [string=''] The string to convert.
14285      * @returns {string} Returns the kebab cased string.
14286      * @example
14287      *
14288      * _.kebabCase('Foo Bar');
14289      * // => 'foo-bar'
14290      *
14291      * _.kebabCase('fooBar');
14292      * // => 'foo-bar'
14293      *
14294      * _.kebabCase('__FOO_BAR__');
14295      * // => 'foo-bar'
14296      */
14297     var kebabCase = createCompounder(function(result, word, index) {
14298       return result + (index ? '-' : '') + word.toLowerCase();
14299     });
14300
14301     /**
14302      * Converts `string`, as space separated words, to lower case.
14303      *
14304      * @static
14305      * @memberOf _
14306      * @since 4.0.0
14307      * @category String
14308      * @param {string} [string=''] The string to convert.
14309      * @returns {string} Returns the lower cased string.
14310      * @example
14311      *
14312      * _.lowerCase('--Foo-Bar--');
14313      * // => 'foo bar'
14314      *
14315      * _.lowerCase('fooBar');
14316      * // => 'foo bar'
14317      *
14318      * _.lowerCase('__FOO_BAR__');
14319      * // => 'foo bar'
14320      */
14321     var lowerCase = createCompounder(function(result, word, index) {
14322       return result + (index ? ' ' : '') + word.toLowerCase();
14323     });
14324
14325     /**
14326      * Converts the first character of `string` to lower case.
14327      *
14328      * @static
14329      * @memberOf _
14330      * @since 4.0.0
14331      * @category String
14332      * @param {string} [string=''] The string to convert.
14333      * @returns {string} Returns the converted string.
14334      * @example
14335      *
14336      * _.lowerFirst('Fred');
14337      * // => 'fred'
14338      *
14339      * _.lowerFirst('FRED');
14340      * // => 'fRED'
14341      */
14342     var lowerFirst = createCaseFirst('toLowerCase');
14343
14344     /**
14345      * Pads `string` on the left and right sides if it's shorter than `length`.
14346      * Padding characters are truncated if they can't be evenly divided by `length`.
14347      *
14348      * @static
14349      * @memberOf _
14350      * @since 3.0.0
14351      * @category String
14352      * @param {string} [string=''] The string to pad.
14353      * @param {number} [length=0] The padding length.
14354      * @param {string} [chars=' '] The string used as padding.
14355      * @returns {string} Returns the padded string.
14356      * @example
14357      *
14358      * _.pad('abc', 8);
14359      * // => '  abc   '
14360      *
14361      * _.pad('abc', 8, '_-');
14362      * // => '_-abc_-_'
14363      *
14364      * _.pad('abc', 3);
14365      * // => 'abc'
14366      */
14367     function pad(string, length, chars) {
14368       string = toString(string);
14369       length = toInteger(length);
14370
14371       var strLength = length ? stringSize(string) : 0;
14372       if (!length || strLength >= length) {
14373         return string;
14374       }
14375       var mid = (length - strLength) / 2;
14376       return (
14377         createPadding(nativeFloor(mid), chars) +
14378         string +
14379         createPadding(nativeCeil(mid), chars)
14380       );
14381     }
14382
14383     /**
14384      * Pads `string` on the right side if it's shorter than `length`. Padding
14385      * characters are truncated if they exceed `length`.
14386      *
14387      * @static
14388      * @memberOf _
14389      * @since 4.0.0
14390      * @category String
14391      * @param {string} [string=''] The string to pad.
14392      * @param {number} [length=0] The padding length.
14393      * @param {string} [chars=' '] The string used as padding.
14394      * @returns {string} Returns the padded string.
14395      * @example
14396      *
14397      * _.padEnd('abc', 6);
14398      * // => 'abc   '
14399      *
14400      * _.padEnd('abc', 6, '_-');
14401      * // => 'abc_-_'
14402      *
14403      * _.padEnd('abc', 3);
14404      * // => 'abc'
14405      */
14406     function padEnd(string, length, chars) {
14407       string = toString(string);
14408       length = toInteger(length);
14409
14410       var strLength = length ? stringSize(string) : 0;
14411       return (length && strLength < length)
14412         ? (string + createPadding(length - strLength, chars))
14413         : string;
14414     }
14415
14416     /**
14417      * Pads `string` on the left side if it's shorter than `length`. Padding
14418      * characters are truncated if they exceed `length`.
14419      *
14420      * @static
14421      * @memberOf _
14422      * @since 4.0.0
14423      * @category String
14424      * @param {string} [string=''] The string to pad.
14425      * @param {number} [length=0] The padding length.
14426      * @param {string} [chars=' '] The string used as padding.
14427      * @returns {string} Returns the padded string.
14428      * @example
14429      *
14430      * _.padStart('abc', 6);
14431      * // => '   abc'
14432      *
14433      * _.padStart('abc', 6, '_-');
14434      * // => '_-_abc'
14435      *
14436      * _.padStart('abc', 3);
14437      * // => 'abc'
14438      */
14439     function padStart(string, length, chars) {
14440       string = toString(string);
14441       length = toInteger(length);
14442
14443       var strLength = length ? stringSize(string) : 0;
14444       return (length && strLength < length)
14445         ? (createPadding(length - strLength, chars) + string)
14446         : string;
14447     }
14448
14449     /**
14450      * Converts `string` to an integer of the specified radix. If `radix` is
14451      * `undefined` or `0`, a `radix` of `10` is used unless `value` is a
14452      * hexadecimal, in which case a `radix` of `16` is used.
14453      *
14454      * **Note:** This method aligns with the
14455      * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`.
14456      *
14457      * @static
14458      * @memberOf _
14459      * @since 1.1.0
14460      * @category String
14461      * @param {string} string The string to convert.
14462      * @param {number} [radix=10] The radix to interpret `value` by.
14463      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14464      * @returns {number} Returns the converted integer.
14465      * @example
14466      *
14467      * _.parseInt('08');
14468      * // => 8
14469      *
14470      * _.map(['6', '08', '10'], _.parseInt);
14471      * // => [6, 8, 10]
14472      */
14473     function parseInt(string, radix, guard) {
14474       if (guard || radix == null) {
14475         radix = 0;
14476       } else if (radix) {
14477         radix = +radix;
14478       }
14479       return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0);
14480     }
14481
14482     /**
14483      * Repeats the given string `n` times.
14484      *
14485      * @static
14486      * @memberOf _
14487      * @since 3.0.0
14488      * @category String
14489      * @param {string} [string=''] The string to repeat.
14490      * @param {number} [n=1] The number of times to repeat the string.
14491      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14492      * @returns {string} Returns the repeated string.
14493      * @example
14494      *
14495      * _.repeat('*', 3);
14496      * // => '***'
14497      *
14498      * _.repeat('abc', 2);
14499      * // => 'abcabc'
14500      *
14501      * _.repeat('abc', 0);
14502      * // => ''
14503      */
14504     function repeat(string, n, guard) {
14505       if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) {
14506         n = 1;
14507       } else {
14508         n = toInteger(n);
14509       }
14510       return baseRepeat(toString(string), n);
14511     }
14512
14513     /**
14514      * Replaces matches for `pattern` in `string` with `replacement`.
14515      *
14516      * **Note:** This method is based on
14517      * [`String#replace`](https://mdn.io/String/replace).
14518      *
14519      * @static
14520      * @memberOf _
14521      * @since 4.0.0
14522      * @category String
14523      * @param {string} [string=''] The string to modify.
14524      * @param {RegExp|string} pattern The pattern to replace.
14525      * @param {Function|string} replacement The match replacement.
14526      * @returns {string} Returns the modified string.
14527      * @example
14528      *
14529      * _.replace('Hi Fred', 'Fred', 'Barney');
14530      * // => 'Hi Barney'
14531      */
14532     function replace() {
14533       var args = arguments,
14534           string = toString(args[0]);
14535
14536       return args.length < 3 ? string : string.replace(args[1], args[2]);
14537     }
14538
14539     /**
14540      * Converts `string` to
14541      * [snake case](https://en.wikipedia.org/wiki/Snake_case).
14542      *
14543      * @static
14544      * @memberOf _
14545      * @since 3.0.0
14546      * @category String
14547      * @param {string} [string=''] The string to convert.
14548      * @returns {string} Returns the snake cased string.
14549      * @example
14550      *
14551      * _.snakeCase('Foo Bar');
14552      * // => 'foo_bar'
14553      *
14554      * _.snakeCase('fooBar');
14555      * // => 'foo_bar'
14556      *
14557      * _.snakeCase('--FOO-BAR--');
14558      * // => 'foo_bar'
14559      */
14560     var snakeCase = createCompounder(function(result, word, index) {
14561       return result + (index ? '_' : '') + word.toLowerCase();
14562     });
14563
14564     /**
14565      * Splits `string` by `separator`.
14566      *
14567      * **Note:** This method is based on
14568      * [`String#split`](https://mdn.io/String/split).
14569      *
14570      * @static
14571      * @memberOf _
14572      * @since 4.0.0
14573      * @category String
14574      * @param {string} [string=''] The string to split.
14575      * @param {RegExp|string} separator The separator pattern to split by.
14576      * @param {number} [limit] The length to truncate results to.
14577      * @returns {Array} Returns the string segments.
14578      * @example
14579      *
14580      * _.split('a-b-c', '-', 2);
14581      * // => ['a', 'b']
14582      */
14583     function split(string, separator, limit) {
14584       if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) {
14585         separator = limit = undefined;
14586       }
14587       limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0;
14588       if (!limit) {
14589         return [];
14590       }
14591       string = toString(string);
14592       if (string && (
14593             typeof separator == 'string' ||
14594             (separator != null && !isRegExp(separator))
14595           )) {
14596         separator = baseToString(separator);
14597         if (!separator && hasUnicode(string)) {
14598           return castSlice(stringToArray(string), 0, limit);
14599         }
14600       }
14601       return string.split(separator, limit);
14602     }
14603
14604     /**
14605      * Converts `string` to
14606      * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
14607      *
14608      * @static
14609      * @memberOf _
14610      * @since 3.1.0
14611      * @category String
14612      * @param {string} [string=''] The string to convert.
14613      * @returns {string} Returns the start cased string.
14614      * @example
14615      *
14616      * _.startCase('--foo-bar--');
14617      * // => 'Foo Bar'
14618      *
14619      * _.startCase('fooBar');
14620      * // => 'Foo Bar'
14621      *
14622      * _.startCase('__FOO_BAR__');
14623      * // => 'FOO BAR'
14624      */
14625     var startCase = createCompounder(function(result, word, index) {
14626       return result + (index ? ' ' : '') + upperFirst(word);
14627     });
14628
14629     /**
14630      * Checks if `string` starts with the given target string.
14631      *
14632      * @static
14633      * @memberOf _
14634      * @since 3.0.0
14635      * @category String
14636      * @param {string} [string=''] The string to inspect.
14637      * @param {string} [target] The string to search for.
14638      * @param {number} [position=0] The position to search from.
14639      * @returns {boolean} Returns `true` if `string` starts with `target`,
14640      *  else `false`.
14641      * @example
14642      *
14643      * _.startsWith('abc', 'a');
14644      * // => true
14645      *
14646      * _.startsWith('abc', 'b');
14647      * // => false
14648      *
14649      * _.startsWith('abc', 'b', 1);
14650      * // => true
14651      */
14652     function startsWith(string, target, position) {
14653       string = toString(string);
14654       position = position == null
14655         ? 0
14656         : baseClamp(toInteger(position), 0, string.length);
14657
14658       target = baseToString(target);
14659       return string.slice(position, position + target.length) == target;
14660     }
14661
14662     /**
14663      * Creates a compiled template function that can interpolate data properties
14664      * in "interpolate" delimiters, HTML-escape interpolated data properties in
14665      * "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
14666      * properties may be accessed as free variables in the template. If a setting
14667      * object is given, it takes precedence over `_.templateSettings` values.
14668      *
14669      * **Note:** In the development build `_.template` utilizes
14670      * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
14671      * for easier debugging.
14672      *
14673      * For more information on precompiling templates see
14674      * [lodash's custom builds documentation](https://lodash.com/custom-builds).
14675      *
14676      * For more information on Chrome extension sandboxes see
14677      * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
14678      *
14679      * @static
14680      * @since 0.1.0
14681      * @memberOf _
14682      * @category String
14683      * @param {string} [string=''] The template string.
14684      * @param {Object} [options={}] The options object.
14685      * @param {RegExp} [options.escape=_.templateSettings.escape]
14686      *  The HTML "escape" delimiter.
14687      * @param {RegExp} [options.evaluate=_.templateSettings.evaluate]
14688      *  The "evaluate" delimiter.
14689      * @param {Object} [options.imports=_.templateSettings.imports]
14690      *  An object to import into the template as free variables.
14691      * @param {RegExp} [options.interpolate=_.templateSettings.interpolate]
14692      *  The "interpolate" delimiter.
14693      * @param {string} [options.sourceURL='lodash.templateSources[n]']
14694      *  The sourceURL of the compiled template.
14695      * @param {string} [options.variable='obj']
14696      *  The data object variable name.
14697      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14698      * @returns {Function} Returns the compiled template function.
14699      * @example
14700      *
14701      * // Use the "interpolate" delimiter to create a compiled template.
14702      * var compiled = _.template('hello <%= user %>!');
14703      * compiled({ 'user': 'fred' });
14704      * // => 'hello fred!'
14705      *
14706      * // Use the HTML "escape" delimiter to escape data property values.
14707      * var compiled = _.template('<b><%- value %></b>');
14708      * compiled({ 'value': '<script>' });
14709      * // => '<b>&lt;script&gt;</b>'
14710      *
14711      * // Use the "evaluate" delimiter to execute JavaScript and generate HTML.
14712      * var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
14713      * compiled({ 'users': ['fred', 'barney'] });
14714      * // => '<li>fred</li><li>barney</li>'
14715      *
14716      * // Use the internal `print` function in "evaluate" delimiters.
14717      * var compiled = _.template('<% print("hello " + user); %>!');
14718      * compiled({ 'user': 'barney' });
14719      * // => 'hello barney!'
14720      *
14721      * // Use the ES template literal delimiter as an "interpolate" delimiter.
14722      * // Disable support by replacing the "interpolate" delimiter.
14723      * var compiled = _.template('hello ${ user }!');
14724      * compiled({ 'user': 'pebbles' });
14725      * // => 'hello pebbles!'
14726      *
14727      * // Use backslashes to treat delimiters as plain text.
14728      * var compiled = _.template('<%= "\\<%- value %\\>" %>');
14729      * compiled({ 'value': 'ignored' });
14730      * // => '<%- value %>'
14731      *
14732      * // Use the `imports` option to import `jQuery` as `jq`.
14733      * var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
14734      * var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
14735      * compiled({ 'users': ['fred', 'barney'] });
14736      * // => '<li>fred</li><li>barney</li>'
14737      *
14738      * // Use the `sourceURL` option to specify a custom sourceURL for the template.
14739      * var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
14740      * compiled(data);
14741      * // => Find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector.
14742      *
14743      * // Use the `variable` option to ensure a with-statement isn't used in the compiled template.
14744      * var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
14745      * compiled.source;
14746      * // => function(data) {
14747      * //   var __t, __p = '';
14748      * //   __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
14749      * //   return __p;
14750      * // }
14751      *
14752      * // Use custom template delimiters.
14753      * _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
14754      * var compiled = _.template('hello {{ user }}!');
14755      * compiled({ 'user': 'mustache' });
14756      * // => 'hello mustache!'
14757      *
14758      * // Use the `source` property to inline compiled templates for meaningful
14759      * // line numbers in error messages and stack traces.
14760      * fs.writeFileSync(path.join(process.cwd(), 'jst.js'), '\
14761      *   var JST = {\
14762      *     "main": ' + _.template(mainText).source + '\
14763      *   };\
14764      * ');
14765      */
14766     function template(string, options, guard) {
14767       // Based on John Resig's `tmpl` implementation
14768       // (http://ejohn.org/blog/javascript-micro-templating/)
14769       // and Laura Doktorova's doT.js (https://github.com/olado/doT).
14770       var settings = lodash.templateSettings;
14771
14772       if (guard && isIterateeCall(string, options, guard)) {
14773         options = undefined;
14774       }
14775       string = toString(string);
14776       options = assignInWith({}, options, settings, customDefaultsAssignIn);
14777
14778       var imports = assignInWith({}, options.imports, settings.imports, customDefaultsAssignIn),
14779           importsKeys = keys(imports),
14780           importsValues = baseValues(imports, importsKeys);
14781
14782       var isEscaping,
14783           isEvaluating,
14784           index = 0,
14785           interpolate = options.interpolate || reNoMatch,
14786           source = "__p += '";
14787
14788       // Compile the regexp to match each delimiter.
14789       var reDelimiters = RegExp(
14790         (options.escape || reNoMatch).source + '|' +
14791         interpolate.source + '|' +
14792         (interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
14793         (options.evaluate || reNoMatch).source + '|$'
14794       , 'g');
14795
14796       // Use a sourceURL for easier debugging.
14797       var sourceURL = '//# sourceURL=' +
14798         ('sourceURL' in options
14799           ? options.sourceURL
14800           : ('lodash.templateSources[' + (++templateCounter) + ']')
14801         ) + '\n';
14802
14803       string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
14804         interpolateValue || (interpolateValue = esTemplateValue);
14805
14806         // Escape characters that can't be included in string literals.
14807         source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
14808
14809         // Replace delimiters with snippets.
14810         if (escapeValue) {
14811           isEscaping = true;
14812           source += "' +\n__e(" + escapeValue + ") +\n'";
14813         }
14814         if (evaluateValue) {
14815           isEvaluating = true;
14816           source += "';\n" + evaluateValue + ";\n__p += '";
14817         }
14818         if (interpolateValue) {
14819           source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
14820         }
14821         index = offset + match.length;
14822
14823         // The JS engine embedded in Adobe products needs `match` returned in
14824         // order to produce the correct `offset` value.
14825         return match;
14826       });
14827
14828       source += "';\n";
14829
14830       // If `variable` is not specified wrap a with-statement around the generated
14831       // code to add the data object to the top of the scope chain.
14832       var variable = options.variable;
14833       if (!variable) {
14834         source = 'with (obj) {\n' + source + '\n}\n';
14835       }
14836       // Cleanup code by stripping empty strings.
14837       source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
14838         .replace(reEmptyStringMiddle, '$1')
14839         .replace(reEmptyStringTrailing, '$1;');
14840
14841       // Frame code as the function body.
14842       source = 'function(' + (variable || 'obj') + ') {\n' +
14843         (variable
14844           ? ''
14845           : 'obj || (obj = {});\n'
14846         ) +
14847         "var __t, __p = ''" +
14848         (isEscaping
14849            ? ', __e = _.escape'
14850            : ''
14851         ) +
14852         (isEvaluating
14853           ? ', __j = Array.prototype.join;\n' +
14854             "function print() { __p += __j.call(arguments, '') }\n"
14855           : ';\n'
14856         ) +
14857         source +
14858         'return __p\n}';
14859
14860       var result = attempt(function() {
14861         return Function(importsKeys, sourceURL + 'return ' + source)
14862           .apply(undefined, importsValues);
14863       });
14864
14865       // Provide the compiled function's source by its `toString` method or
14866       // the `source` property as a convenience for inlining compiled templates.
14867       result.source = source;
14868       if (isError(result)) {
14869         throw result;
14870       }
14871       return result;
14872     }
14873
14874     /**
14875      * Converts `string`, as a whole, to lower case just like
14876      * [String#toLowerCase](https://mdn.io/toLowerCase).
14877      *
14878      * @static
14879      * @memberOf _
14880      * @since 4.0.0
14881      * @category String
14882      * @param {string} [string=''] The string to convert.
14883      * @returns {string} Returns the lower cased string.
14884      * @example
14885      *
14886      * _.toLower('--Foo-Bar--');
14887      * // => '--foo-bar--'
14888      *
14889      * _.toLower('fooBar');
14890      * // => 'foobar'
14891      *
14892      * _.toLower('__FOO_BAR__');
14893      * // => '__foo_bar__'
14894      */
14895     function toLower(value) {
14896       return toString(value).toLowerCase();
14897     }
14898
14899     /**
14900      * Converts `string`, as a whole, to upper case just like
14901      * [String#toUpperCase](https://mdn.io/toUpperCase).
14902      *
14903      * @static
14904      * @memberOf _
14905      * @since 4.0.0
14906      * @category String
14907      * @param {string} [string=''] The string to convert.
14908      * @returns {string} Returns the upper cased string.
14909      * @example
14910      *
14911      * _.toUpper('--foo-bar--');
14912      * // => '--FOO-BAR--'
14913      *
14914      * _.toUpper('fooBar');
14915      * // => 'FOOBAR'
14916      *
14917      * _.toUpper('__foo_bar__');
14918      * // => '__FOO_BAR__'
14919      */
14920     function toUpper(value) {
14921       return toString(value).toUpperCase();
14922     }
14923
14924     /**
14925      * Removes leading and trailing whitespace or specified characters from `string`.
14926      *
14927      * @static
14928      * @memberOf _
14929      * @since 3.0.0
14930      * @category String
14931      * @param {string} [string=''] The string to trim.
14932      * @param {string} [chars=whitespace] The characters to trim.
14933      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14934      * @returns {string} Returns the trimmed string.
14935      * @example
14936      *
14937      * _.trim('  abc  ');
14938      * // => 'abc'
14939      *
14940      * _.trim('-_-abc-_-', '_-');
14941      * // => 'abc'
14942      *
14943      * _.map(['  foo  ', '  bar  '], _.trim);
14944      * // => ['foo', 'bar']
14945      */
14946     function trim(string, chars, guard) {
14947       string = toString(string);
14948       if (string && (guard || chars === undefined)) {
14949         return string.replace(reTrim, '');
14950       }
14951       if (!string || !(chars = baseToString(chars))) {
14952         return string;
14953       }
14954       var strSymbols = stringToArray(string),
14955           chrSymbols = stringToArray(chars),
14956           start = charsStartIndex(strSymbols, chrSymbols),
14957           end = charsEndIndex(strSymbols, chrSymbols) + 1;
14958
14959       return castSlice(strSymbols, start, end).join('');
14960     }
14961
14962     /**
14963      * Removes trailing whitespace or specified characters from `string`.
14964      *
14965      * @static
14966      * @memberOf _
14967      * @since 4.0.0
14968      * @category String
14969      * @param {string} [string=''] The string to trim.
14970      * @param {string} [chars=whitespace] The characters to trim.
14971      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
14972      * @returns {string} Returns the trimmed string.
14973      * @example
14974      *
14975      * _.trimEnd('  abc  ');
14976      * // => '  abc'
14977      *
14978      * _.trimEnd('-_-abc-_-', '_-');
14979      * // => '-_-abc'
14980      */
14981     function trimEnd(string, chars, guard) {
14982       string = toString(string);
14983       if (string && (guard || chars === undefined)) {
14984         return string.replace(reTrimEnd, '');
14985       }
14986       if (!string || !(chars = baseToString(chars))) {
14987         return string;
14988       }
14989       var strSymbols = stringToArray(string),
14990           end = charsEndIndex(strSymbols, stringToArray(chars)) + 1;
14991
14992       return castSlice(strSymbols, 0, end).join('');
14993     }
14994
14995     /**
14996      * Removes leading whitespace or specified characters from `string`.
14997      *
14998      * @static
14999      * @memberOf _
15000      * @since 4.0.0
15001      * @category String
15002      * @param {string} [string=''] The string to trim.
15003      * @param {string} [chars=whitespace] The characters to trim.
15004      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
15005      * @returns {string} Returns the trimmed string.
15006      * @example
15007      *
15008      * _.trimStart('  abc  ');
15009      * // => 'abc  '
15010      *
15011      * _.trimStart('-_-abc-_-', '_-');
15012      * // => 'abc-_-'
15013      */
15014     function trimStart(string, chars, guard) {
15015       string = toString(string);
15016       if (string && (guard || chars === undefined)) {
15017         return string.replace(reTrimStart, '');
15018       }
15019       if (!string || !(chars = baseToString(chars))) {
15020         return string;
15021       }
15022       var strSymbols = stringToArray(string),
15023           start = charsStartIndex(strSymbols, stringToArray(chars));
15024
15025       return castSlice(strSymbols, start).join('');
15026     }
15027
15028     /**
15029      * Truncates `string` if it's longer than the given maximum string length.
15030      * The last characters of the truncated string are replaced with the omission
15031      * string which defaults to "...".
15032      *
15033      * @static
15034      * @memberOf _
15035      * @since 4.0.0
15036      * @category String
15037      * @param {string} [string=''] The string to truncate.
15038      * @param {Object} [options={}] The options object.
15039      * @param {number} [options.length=30] The maximum string length.
15040      * @param {string} [options.omission='...'] The string to indicate text is omitted.
15041      * @param {RegExp|string} [options.separator] The separator pattern to truncate to.
15042      * @returns {string} Returns the truncated string.
15043      * @example
15044      *
15045      * _.truncate('hi-diddly-ho there, neighborino');
15046      * // => 'hi-diddly-ho there, neighbo...'
15047      *
15048      * _.truncate('hi-diddly-ho there, neighborino', {
15049      *   'length': 24,
15050      *   'separator': ' '
15051      * });
15052      * // => 'hi-diddly-ho there,...'
15053      *
15054      * _.truncate('hi-diddly-ho there, neighborino', {
15055      *   'length': 24,
15056      *   'separator': /,? +/
15057      * });
15058      * // => 'hi-diddly-ho there...'
15059      *
15060      * _.truncate('hi-diddly-ho there, neighborino', {
15061      *   'omission': ' [...]'
15062      * });
15063      * // => 'hi-diddly-ho there, neig [...]'
15064      */
15065     function truncate(string, options) {
15066       var length = DEFAULT_TRUNC_LENGTH,
15067           omission = DEFAULT_TRUNC_OMISSION;
15068
15069       if (isObject(options)) {
15070         var separator = 'separator' in options ? options.separator : separator;
15071         length = 'length' in options ? toInteger(options.length) : length;
15072         omission = 'omission' in options ? baseToString(options.omission) : omission;
15073       }
15074       string = toString(string);
15075
15076       var strLength = string.length;
15077       if (hasUnicode(string)) {
15078         var strSymbols = stringToArray(string);
15079         strLength = strSymbols.length;
15080       }
15081       if (length >= strLength) {
15082         return string;
15083       }
15084       var end = length - stringSize(omission);
15085       if (end < 1) {
15086         return omission;
15087       }
15088       var result = strSymbols
15089         ? castSlice(strSymbols, 0, end).join('')
15090         : string.slice(0, end);
15091
15092       if (separator === undefined) {
15093         return result + omission;
15094       }
15095       if (strSymbols) {
15096         end += (result.length - end);
15097       }
15098       if (isRegExp(separator)) {
15099         if (string.slice(end).search(separator)) {
15100           var match,
15101               substring = result;
15102
15103           if (!separator.global) {
15104             separator = RegExp(separator.source, toString(reFlags.exec(separator)) + 'g');
15105           }
15106           separator.lastIndex = 0;
15107           while ((match = separator.exec(substring))) {
15108             var newEnd = match.index;
15109           }
15110           result = result.slice(0, newEnd === undefined ? end : newEnd);
15111         }
15112       } else if (string.indexOf(baseToString(separator), end) != end) {
15113         var index = result.lastIndexOf(separator);
15114         if (index > -1) {
15115           result = result.slice(0, index);
15116         }
15117       }
15118       return result + omission;
15119     }
15120
15121     /**
15122      * The inverse of `_.escape`; this method converts the HTML entities
15123      * `&amp;`, `&lt;`, `&gt;`, `&quot;`, and `&#39;` in `string` to
15124      * their corresponding characters.
15125      *
15126      * **Note:** No other HTML entities are unescaped. To unescape additional
15127      * HTML entities use a third-party library like [_he_](https://mths.be/he).
15128      *
15129      * @static
15130      * @memberOf _
15131      * @since 0.6.0
15132      * @category String
15133      * @param {string} [string=''] The string to unescape.
15134      * @returns {string} Returns the unescaped string.
15135      * @example
15136      *
15137      * _.unescape('fred, barney, &amp; pebbles');
15138      * // => 'fred, barney, & pebbles'
15139      */
15140     function unescape(string) {
15141       string = toString(string);
15142       return (string && reHasEscapedHtml.test(string))
15143         ? string.replace(reEscapedHtml, unescapeHtmlChar)
15144         : string;
15145     }
15146
15147     /**
15148      * Converts `string`, as space separated words, to upper case.
15149      *
15150      * @static
15151      * @memberOf _
15152      * @since 4.0.0
15153      * @category String
15154      * @param {string} [string=''] The string to convert.
15155      * @returns {string} Returns the upper cased string.
15156      * @example
15157      *
15158      * _.upperCase('--foo-bar');
15159      * // => 'FOO BAR'
15160      *
15161      * _.upperCase('fooBar');
15162      * // => 'FOO BAR'
15163      *
15164      * _.upperCase('__foo_bar__');
15165      * // => 'FOO BAR'
15166      */
15167     var upperCase = createCompounder(function(result, word, index) {
15168       return result + (index ? ' ' : '') + word.toUpperCase();
15169     });
15170
15171     /**
15172      * Converts the first character of `string` to upper case.
15173      *
15174      * @static
15175      * @memberOf _
15176      * @since 4.0.0
15177      * @category String
15178      * @param {string} [string=''] The string to convert.
15179      * @returns {string} Returns the converted string.
15180      * @example
15181      *
15182      * _.upperFirst('fred');
15183      * // => 'Fred'
15184      *
15185      * _.upperFirst('FRED');
15186      * // => 'FRED'
15187      */
15188     var upperFirst = createCaseFirst('toUpperCase');
15189
15190     /**
15191      * Splits `string` into an array of its words.
15192      *
15193      * @static
15194      * @memberOf _
15195      * @since 3.0.0
15196      * @category String
15197      * @param {string} [string=''] The string to inspect.
15198      * @param {RegExp|string} [pattern] The pattern to match words.
15199      * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
15200      * @returns {Array} Returns the words of `string`.
15201      * @example
15202      *
15203      * _.words('fred, barney, & pebbles');
15204      * // => ['fred', 'barney', 'pebbles']
15205      *
15206      * _.words('fred, barney, & pebbles', /[^, ]+/g);
15207      * // => ['fred', 'barney', '&', 'pebbles']
15208      */
15209     function words(string, pattern, guard) {
15210       string = toString(string);
15211       pattern = guard ? undefined : pattern;
15212
15213       if (pattern === undefined) {
15214         return hasUnicodeWord(string) ? unicodeWords(string) : asciiWords(string);
15215       }
15216       return string.match(pattern) || [];
15217     }
15218
15219     /*------------------------------------------------------------------------*/
15220
15221     /**
15222      * Attempts to invoke `func`, returning either the result or the caught error
15223      * object. Any additional arguments are provided to `func` when it's invoked.
15224      *
15225      * @static
15226      * @memberOf _
15227      * @since 3.0.0
15228      * @category Util
15229      * @param {Function} func The function to attempt.
15230      * @param {...*} [args] The arguments to invoke `func` with.
15231      * @returns {*} Returns the `func` result or error object.
15232      * @example
15233      *
15234      * // Avoid throwing errors for invalid selectors.
15235      * var elements = _.attempt(function(selector) {
15236      *   return document.querySelectorAll(selector);
15237      * }, '>_>');
15238      *
15239      * if (_.isError(elements)) {
15240      *   elements = [];
15241      * }
15242      */
15243     var attempt = baseRest(function(func, args) {
15244       try {
15245         return apply(func, undefined, args);
15246       } catch (e) {
15247         return isError(e) ? e : new Error(e);
15248       }
15249     });
15250
15251     /**
15252      * Binds methods of an object to the object itself, overwriting the existing
15253      * method.
15254      *
15255      * **Note:** This method doesn't set the "length" property of bound functions.
15256      *
15257      * @static
15258      * @since 0.1.0
15259      * @memberOf _
15260      * @category Util
15261      * @param {Object} object The object to bind and assign the bound methods to.
15262      * @param {...(string|string[])} methodNames The object method names to bind.
15263      * @returns {Object} Returns `object`.
15264      * @example
15265      *
15266      * var view = {
15267      *   'label': 'docs',
15268      *   'click': function() {
15269      *     console.log('clicked ' + this.label);
15270      *   }
15271      * };
15272      *
15273      * _.bindAll(view, ['click']);
15274      * jQuery(element).on('click', view.click);
15275      * // => Logs 'clicked docs' when clicked.
15276      */
15277     var bindAll = flatRest(function(object, methodNames) {
15278       arrayEach(methodNames, function(key) {
15279         key = toKey(key);
15280         baseAssignValue(object, key, bind(object[key], object));
15281       });
15282       return object;
15283     });
15284
15285     /**
15286      * Creates a function that iterates over `pairs` and invokes the corresponding
15287      * function of the first predicate to return truthy. The predicate-function
15288      * pairs are invoked with the `this` binding and arguments of the created
15289      * function.
15290      *
15291      * @static
15292      * @memberOf _
15293      * @since 4.0.0
15294      * @category Util
15295      * @param {Array} pairs The predicate-function pairs.
15296      * @returns {Function} Returns the new composite function.
15297      * @example
15298      *
15299      * var func = _.cond([
15300      *   [_.matches({ 'a': 1 }),           _.constant('matches A')],
15301      *   [_.conforms({ 'b': _.isNumber }), _.constant('matches B')],
15302      *   [_.stubTrue,                      _.constant('no match')]
15303      * ]);
15304      *
15305      * func({ 'a': 1, 'b': 2 });
15306      * // => 'matches A'
15307      *
15308      * func({ 'a': 0, 'b': 1 });
15309      * // => 'matches B'
15310      *
15311      * func({ 'a': '1', 'b': '2' });
15312      * // => 'no match'
15313      */
15314     function cond(pairs) {
15315       var length = pairs == null ? 0 : pairs.length,
15316           toIteratee = getIteratee();
15317
15318       pairs = !length ? [] : arrayMap(pairs, function(pair) {
15319         if (typeof pair[1] != 'function') {
15320           throw new TypeError(FUNC_ERROR_TEXT);
15321         }
15322         return [toIteratee(pair[0]), pair[1]];
15323       });
15324
15325       return baseRest(function(args) {
15326         var index = -1;
15327         while (++index < length) {
15328           var pair = pairs[index];
15329           if (apply(pair[0], this, args)) {
15330             return apply(pair[1], this, args);
15331           }
15332         }
15333       });
15334     }
15335
15336     /**
15337      * Creates a function that invokes the predicate properties of `source` with
15338      * the corresponding property values of a given object, returning `true` if
15339      * all predicates return truthy, else `false`.
15340      *
15341      * **Note:** The created function is equivalent to `_.conformsTo` with
15342      * `source` partially applied.
15343      *
15344      * @static
15345      * @memberOf _
15346      * @since 4.0.0
15347      * @category Util
15348      * @param {Object} source The object of property predicates to conform to.
15349      * @returns {Function} Returns the new spec function.
15350      * @example
15351      *
15352      * var objects = [
15353      *   { 'a': 2, 'b': 1 },
15354      *   { 'a': 1, 'b': 2 }
15355      * ];
15356      *
15357      * _.filter(objects, _.conforms({ 'b': function(n) { return n > 1; } }));
15358      * // => [{ 'a': 1, 'b': 2 }]
15359      */
15360     function conforms(source) {
15361       return baseConforms(baseClone(source, CLONE_DEEP_FLAG));
15362     }
15363
15364     /**
15365      * Creates a function that returns `value`.
15366      *
15367      * @static
15368      * @memberOf _
15369      * @since 2.4.0
15370      * @category Util
15371      * @param {*} value The value to return from the new function.
15372      * @returns {Function} Returns the new constant function.
15373      * @example
15374      *
15375      * var objects = _.times(2, _.constant({ 'a': 1 }));
15376      *
15377      * console.log(objects);
15378      * // => [{ 'a': 1 }, { 'a': 1 }]
15379      *
15380      * console.log(objects[0] === objects[1]);
15381      * // => true
15382      */
15383     function constant(value) {
15384       return function() {
15385         return value;
15386       };
15387     }
15388
15389     /**
15390      * Checks `value` to determine whether a default value should be returned in
15391      * its place. The `defaultValue` is returned if `value` is `NaN`, `null`,
15392      * or `undefined`.
15393      *
15394      * @static
15395      * @memberOf _
15396      * @since 4.14.0
15397      * @category Util
15398      * @param {*} value The value to check.
15399      * @param {*} defaultValue The default value.
15400      * @returns {*} Returns the resolved value.
15401      * @example
15402      *
15403      * _.defaultTo(1, 10);
15404      * // => 1
15405      *
15406      * _.defaultTo(undefined, 10);
15407      * // => 10
15408      */
15409     function defaultTo(value, defaultValue) {
15410       return (value == null || value !== value) ? defaultValue : value;
15411     }
15412
15413     /**
15414      * Creates a function that returns the result of invoking the given functions
15415      * with the `this` binding of the created function, where each successive
15416      * invocation is supplied the return value of the previous.
15417      *
15418      * @static
15419      * @memberOf _
15420      * @since 3.0.0
15421      * @category Util
15422      * @param {...(Function|Function[])} [funcs] The functions to invoke.
15423      * @returns {Function} Returns the new composite function.
15424      * @see _.flowRight
15425      * @example
15426      *
15427      * function square(n) {
15428      *   return n * n;
15429      * }
15430      *
15431      * var addSquare = _.flow([_.add, square]);
15432      * addSquare(1, 2);
15433      * // => 9
15434      */
15435     var flow = createFlow();
15436
15437     /**
15438      * This method is like `_.flow` except that it creates a function that
15439      * invokes the given functions from right to left.
15440      *
15441      * @static
15442      * @since 3.0.0
15443      * @memberOf _
15444      * @category Util
15445      * @param {...(Function|Function[])} [funcs] The functions to invoke.
15446      * @returns {Function} Returns the new composite function.
15447      * @see _.flow
15448      * @example
15449      *
15450      * function square(n) {
15451      *   return n * n;
15452      * }
15453      *
15454      * var addSquare = _.flowRight([square, _.add]);
15455      * addSquare(1, 2);
15456      * // => 9
15457      */
15458     var flowRight = createFlow(true);
15459
15460     /**
15461      * This method returns the first argument it receives.
15462      *
15463      * @static
15464      * @since 0.1.0
15465      * @memberOf _
15466      * @category Util
15467      * @param {*} value Any value.
15468      * @returns {*} Returns `value`.
15469      * @example
15470      *
15471      * var object = { 'a': 1 };
15472      *
15473      * console.log(_.identity(object) === object);
15474      * // => true
15475      */
15476     function identity(value) {
15477       return value;
15478     }
15479
15480     /**
15481      * Creates a function that invokes `func` with the arguments of the created
15482      * function. If `func` is a property name, the created function returns the
15483      * property value for a given element. If `func` is an array or object, the
15484      * created function returns `true` for elements that contain the equivalent
15485      * source properties, otherwise it returns `false`.
15486      *
15487      * @static
15488      * @since 4.0.0
15489      * @memberOf _
15490      * @category Util
15491      * @param {*} [func=_.identity] The value to convert to a callback.
15492      * @returns {Function} Returns the callback.
15493      * @example
15494      *
15495      * var users = [
15496      *   { 'user': 'barney', 'age': 36, 'active': true },
15497      *   { 'user': 'fred',   'age': 40, 'active': false }
15498      * ];
15499      *
15500      * // The `_.matches` iteratee shorthand.
15501      * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true }));
15502      * // => [{ 'user': 'barney', 'age': 36, 'active': true }]
15503      *
15504      * // The `_.matchesProperty` iteratee shorthand.
15505      * _.filter(users, _.iteratee(['user', 'fred']));
15506      * // => [{ 'user': 'fred', 'age': 40 }]
15507      *
15508      * // The `_.property` iteratee shorthand.
15509      * _.map(users, _.iteratee('user'));
15510      * // => ['barney', 'fred']
15511      *
15512      * // Create custom iteratee shorthands.
15513      * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) {
15514      *   return !_.isRegExp(func) ? iteratee(func) : function(string) {
15515      *     return func.test(string);
15516      *   };
15517      * });
15518      *
15519      * _.filter(['abc', 'def'], /ef/);
15520      * // => ['def']
15521      */
15522     function iteratee(func) {
15523       return baseIteratee(typeof func == 'function' ? func : baseClone(func, CLONE_DEEP_FLAG));
15524     }
15525
15526     /**
15527      * Creates a function that performs a partial deep comparison between a given
15528      * object and `source`, returning `true` if the given object has equivalent
15529      * property values, else `false`.
15530      *
15531      * **Note:** The created function is equivalent to `_.isMatch` with `source`
15532      * partially applied.
15533      *
15534      * Partial comparisons will match empty array and empty object `source`
15535      * values against any array or object value, respectively. See `_.isEqual`
15536      * for a list of supported value comparisons.
15537      *
15538      * @static
15539      * @memberOf _
15540      * @since 3.0.0
15541      * @category Util
15542      * @param {Object} source The object of property values to match.
15543      * @returns {Function} Returns the new spec function.
15544      * @example
15545      *
15546      * var objects = [
15547      *   { 'a': 1, 'b': 2, 'c': 3 },
15548      *   { 'a': 4, 'b': 5, 'c': 6 }
15549      * ];
15550      *
15551      * _.filter(objects, _.matches({ 'a': 4, 'c': 6 }));
15552      * // => [{ 'a': 4, 'b': 5, 'c': 6 }]
15553      */
15554     function matches(source) {
15555       return baseMatches(baseClone(source, CLONE_DEEP_FLAG));
15556     }
15557
15558     /**
15559      * Creates a function that performs a partial deep comparison between the
15560      * value at `path` of a given object to `srcValue`, returning `true` if the
15561      * object value is equivalent, else `false`.
15562      *
15563      * **Note:** Partial comparisons will match empty array and empty object
15564      * `srcValue` values against any array or object value, respectively. See
15565      * `_.isEqual` for a list of supported value comparisons.
15566      *
15567      * @static
15568      * @memberOf _
15569      * @since 3.2.0
15570      * @category Util
15571      * @param {Array|string} path The path of the property to get.
15572      * @param {*} srcValue The value to match.
15573      * @returns {Function} Returns the new spec function.
15574      * @example
15575      *
15576      * var objects = [
15577      *   { 'a': 1, 'b': 2, 'c': 3 },
15578      *   { 'a': 4, 'b': 5, 'c': 6 }
15579      * ];
15580      *
15581      * _.find(objects, _.matchesProperty('a', 4));
15582      * // => { 'a': 4, 'b': 5, 'c': 6 }
15583      */
15584     function matchesProperty(path, srcValue) {
15585       return baseMatchesProperty(path, baseClone(srcValue, CLONE_DEEP_FLAG));
15586     }
15587
15588     /**
15589      * Creates a function that invokes the method at `path` of a given object.
15590      * Any additional arguments are provided to the invoked method.
15591      *
15592      * @static
15593      * @memberOf _
15594      * @since 3.7.0
15595      * @category Util
15596      * @param {Array|string} path The path of the method to invoke.
15597      * @param {...*} [args] The arguments to invoke the method with.
15598      * @returns {Function} Returns the new invoker function.
15599      * @example
15600      *
15601      * var objects = [
15602      *   { 'a': { 'b': _.constant(2) } },
15603      *   { 'a': { 'b': _.constant(1) } }
15604      * ];
15605      *
15606      * _.map(objects, _.method('a.b'));
15607      * // => [2, 1]
15608      *
15609      * _.map(objects, _.method(['a', 'b']));
15610      * // => [2, 1]
15611      */
15612     var method = baseRest(function(path, args) {
15613       return function(object) {
15614         return baseInvoke(object, path, args);
15615       };
15616     });
15617
15618     /**
15619      * The opposite of `_.method`; this method creates a function that invokes
15620      * the method at a given path of `object`. Any additional arguments are
15621      * provided to the invoked method.
15622      *
15623      * @static
15624      * @memberOf _
15625      * @since 3.7.0
15626      * @category Util
15627      * @param {Object} object The object to query.
15628      * @param {...*} [args] The arguments to invoke the method with.
15629      * @returns {Function} Returns the new invoker function.
15630      * @example
15631      *
15632      * var array = _.times(3, _.constant),
15633      *     object = { 'a': array, 'b': array, 'c': array };
15634      *
15635      * _.map(['a[2]', 'c[0]'], _.methodOf(object));
15636      * // => [2, 0]
15637      *
15638      * _.map([['a', '2'], ['c', '0']], _.methodOf(object));
15639      * // => [2, 0]
15640      */
15641     var methodOf = baseRest(function(object, args) {
15642       return function(path) {
15643         return baseInvoke(object, path, args);
15644       };
15645     });
15646
15647     /**
15648      * Adds all own enumerable string keyed function properties of a source
15649      * object to the destination object. If `object` is a function, then methods
15650      * are added to its prototype as well.
15651      *
15652      * **Note:** Use `_.runInContext` to create a pristine `lodash` function to
15653      * avoid conflicts caused by modifying the original.
15654      *
15655      * @static
15656      * @since 0.1.0
15657      * @memberOf _
15658      * @category Util
15659      * @param {Function|Object} [object=lodash] The destination object.
15660      * @param {Object} source The object of functions to add.
15661      * @param {Object} [options={}] The options object.
15662      * @param {boolean} [options.chain=true] Specify whether mixins are chainable.
15663      * @returns {Function|Object} Returns `object`.
15664      * @example
15665      *
15666      * function vowels(string) {
15667      *   return _.filter(string, function(v) {
15668      *     return /[aeiou]/i.test(v);
15669      *   });
15670      * }
15671      *
15672      * _.mixin({ 'vowels': vowels });
15673      * _.vowels('fred');
15674      * // => ['e']
15675      *
15676      * _('fred').vowels().value();
15677      * // => ['e']
15678      *
15679      * _.mixin({ 'vowels': vowels }, { 'chain': false });
15680      * _('fred').vowels();
15681      * // => ['e']
15682      */
15683     function mixin(object, source, options) {
15684       var props = keys(source),
15685           methodNames = baseFunctions(source, props);
15686
15687       if (options == null &&
15688           !(isObject(source) && (methodNames.length || !props.length))) {
15689         options = source;
15690         source = object;
15691         object = this;
15692         methodNames = baseFunctions(source, keys(source));
15693       }
15694       var chain = !(isObject(options) && 'chain' in options) || !!options.chain,
15695           isFunc = isFunction(object);
15696
15697       arrayEach(methodNames, function(methodName) {
15698         var func = source[methodName];
15699         object[methodName] = func;
15700         if (isFunc) {
15701           object.prototype[methodName] = function() {
15702             var chainAll = this.__chain__;
15703             if (chain || chainAll) {
15704               var result = object(this.__wrapped__),
15705                   actions = result.__actions__ = copyArray(this.__actions__);
15706
15707               actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
15708               result.__chain__ = chainAll;
15709               return result;
15710             }
15711             return func.apply(object, arrayPush([this.value()], arguments));
15712           };
15713         }
15714       });
15715
15716       return object;
15717     }
15718
15719     /**
15720      * Reverts the `_` variable to its previous value and returns a reference to
15721      * the `lodash` function.
15722      *
15723      * @static
15724      * @since 0.1.0
15725      * @memberOf _
15726      * @category Util
15727      * @returns {Function} Returns the `lodash` function.
15728      * @example
15729      *
15730      * var lodash = _.noConflict();
15731      */
15732     function noConflict() {
15733       if (root._ === this) {
15734         root._ = oldDash;
15735       }
15736       return this;
15737     }
15738
15739     /**
15740      * This method returns `undefined`.
15741      *
15742      * @static
15743      * @memberOf _
15744      * @since 2.3.0
15745      * @category Util
15746      * @example
15747      *
15748      * _.times(2, _.noop);
15749      * // => [undefined, undefined]
15750      */
15751     function noop() {
15752       // No operation performed.
15753     }
15754
15755     /**
15756      * Creates a function that gets the argument at index `n`. If `n` is negative,
15757      * the nth argument from the end is returned.
15758      *
15759      * @static
15760      * @memberOf _
15761      * @since 4.0.0
15762      * @category Util
15763      * @param {number} [n=0] The index of the argument to return.
15764      * @returns {Function} Returns the new pass-thru function.
15765      * @example
15766      *
15767      * var func = _.nthArg(1);
15768      * func('a', 'b', 'c', 'd');
15769      * // => 'b'
15770      *
15771      * var func = _.nthArg(-2);
15772      * func('a', 'b', 'c', 'd');
15773      * // => 'c'
15774      */
15775     function nthArg(n) {
15776       n = toInteger(n);
15777       return baseRest(function(args) {
15778         return baseNth(args, n);
15779       });
15780     }
15781
15782     /**
15783      * Creates a function that invokes `iteratees` with the arguments it receives
15784      * and returns their results.
15785      *
15786      * @static
15787      * @memberOf _
15788      * @since 4.0.0
15789      * @category Util
15790      * @param {...(Function|Function[])} [iteratees=[_.identity]]
15791      *  The iteratees to invoke.
15792      * @returns {Function} Returns the new function.
15793      * @example
15794      *
15795      * var func = _.over([Math.max, Math.min]);
15796      *
15797      * func(1, 2, 3, 4);
15798      * // => [4, 1]
15799      */
15800     var over = createOver(arrayMap);
15801
15802     /**
15803      * Creates a function that checks if **all** of the `predicates` return
15804      * truthy when invoked with the arguments it receives.
15805      *
15806      * @static
15807      * @memberOf _
15808      * @since 4.0.0
15809      * @category Util
15810      * @param {...(Function|Function[])} [predicates=[_.identity]]
15811      *  The predicates to check.
15812      * @returns {Function} Returns the new function.
15813      * @example
15814      *
15815      * var func = _.overEvery([Boolean, isFinite]);
15816      *
15817      * func('1');
15818      * // => true
15819      *
15820      * func(null);
15821      * // => false
15822      *
15823      * func(NaN);
15824      * // => false
15825      */
15826     var overEvery = createOver(arrayEvery);
15827
15828     /**
15829      * Creates a function that checks if **any** of the `predicates` return
15830      * truthy when invoked with the arguments it receives.
15831      *
15832      * @static
15833      * @memberOf _
15834      * @since 4.0.0
15835      * @category Util
15836      * @param {...(Function|Function[])} [predicates=[_.identity]]
15837      *  The predicates to check.
15838      * @returns {Function} Returns the new function.
15839      * @example
15840      *
15841      * var func = _.overSome([Boolean, isFinite]);
15842      *
15843      * func('1');
15844      * // => true
15845      *
15846      * func(null);
15847      * // => true
15848      *
15849      * func(NaN);
15850      * // => false
15851      */
15852     var overSome = createOver(arraySome);
15853
15854     /**
15855      * Creates a function that returns the value at `path` of a given object.
15856      *
15857      * @static
15858      * @memberOf _
15859      * @since 2.4.0
15860      * @category Util
15861      * @param {Array|string} path The path of the property to get.
15862      * @returns {Function} Returns the new accessor function.
15863      * @example
15864      *
15865      * var objects = [
15866      *   { 'a': { 'b': 2 } },
15867      *   { 'a': { 'b': 1 } }
15868      * ];
15869      *
15870      * _.map(objects, _.property('a.b'));
15871      * // => [2, 1]
15872      *
15873      * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
15874      * // => [1, 2]
15875      */
15876     function property(path) {
15877       return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path);
15878     }
15879
15880     /**
15881      * The opposite of `_.property`; this method creates a function that returns
15882      * the value at a given path of `object`.
15883      *
15884      * @static
15885      * @memberOf _
15886      * @since 3.0.0
15887      * @category Util
15888      * @param {Object} object The object to query.
15889      * @returns {Function} Returns the new accessor function.
15890      * @example
15891      *
15892      * var array = [0, 1, 2],
15893      *     object = { 'a': array, 'b': array, 'c': array };
15894      *
15895      * _.map(['a[2]', 'c[0]'], _.propertyOf(object));
15896      * // => [2, 0]
15897      *
15898      * _.map([['a', '2'], ['c', '0']], _.propertyOf(object));
15899      * // => [2, 0]
15900      */
15901     function propertyOf(object) {
15902       return function(path) {
15903         return object == null ? undefined : baseGet(object, path);
15904       };
15905     }
15906
15907     /**
15908      * Creates an array of numbers (positive and/or negative) progressing from
15909      * `start` up to, but not including, `end`. A step of `-1` is used if a negative
15910      * `start` is specified without an `end` or `step`. If `end` is not specified,
15911      * it's set to `start` with `start` then set to `0`.
15912      *
15913      * **Note:** JavaScript follows the IEEE-754 standard for resolving
15914      * floating-point values which can produce unexpected results.
15915      *
15916      * @static
15917      * @since 0.1.0
15918      * @memberOf _
15919      * @category Util
15920      * @param {number} [start=0] The start of the range.
15921      * @param {number} end The end of the range.
15922      * @param {number} [step=1] The value to increment or decrement by.
15923      * @returns {Array} Returns the range of numbers.
15924      * @see _.inRange, _.rangeRight
15925      * @example
15926      *
15927      * _.range(4);
15928      * // => [0, 1, 2, 3]
15929      *
15930      * _.range(-4);
15931      * // => [0, -1, -2, -3]
15932      *
15933      * _.range(1, 5);
15934      * // => [1, 2, 3, 4]
15935      *
15936      * _.range(0, 20, 5);
15937      * // => [0, 5, 10, 15]
15938      *
15939      * _.range(0, -4, -1);
15940      * // => [0, -1, -2, -3]
15941      *
15942      * _.range(1, 4, 0);
15943      * // => [1, 1, 1]
15944      *
15945      * _.range(0);
15946      * // => []
15947      */
15948     var range = createRange();
15949
15950     /**
15951      * This method is like `_.range` except that it populates values in
15952      * descending order.
15953      *
15954      * @static
15955      * @memberOf _
15956      * @since 4.0.0
15957      * @category Util
15958      * @param {number} [start=0] The start of the range.
15959      * @param {number} end The end of the range.
15960      * @param {number} [step=1] The value to increment or decrement by.
15961      * @returns {Array} Returns the range of numbers.
15962      * @see _.inRange, _.range
15963      * @example
15964      *
15965      * _.rangeRight(4);
15966      * // => [3, 2, 1, 0]
15967      *
15968      * _.rangeRight(-4);
15969      * // => [-3, -2, -1, 0]
15970      *
15971      * _.rangeRight(1, 5);
15972      * // => [4, 3, 2, 1]
15973      *
15974      * _.rangeRight(0, 20, 5);
15975      * // => [15, 10, 5, 0]
15976      *
15977      * _.rangeRight(0, -4, -1);
15978      * // => [-3, -2, -1, 0]
15979      *
15980      * _.rangeRight(1, 4, 0);
15981      * // => [1, 1, 1]
15982      *
15983      * _.rangeRight(0);
15984      * // => []
15985      */
15986     var rangeRight = createRange(true);
15987
15988     /**
15989      * This method returns a new empty array.
15990      *
15991      * @static
15992      * @memberOf _
15993      * @since 4.13.0
15994      * @category Util
15995      * @returns {Array} Returns the new empty array.
15996      * @example
15997      *
15998      * var arrays = _.times(2, _.stubArray);
15999      *
16000      * console.log(arrays);
16001      * // => [[], []]
16002      *
16003      * console.log(arrays[0] === arrays[1]);
16004      * // => false
16005      */
16006     function stubArray() {
16007       return [];
16008     }
16009
16010     /**
16011      * This method returns `false`.
16012      *
16013      * @static
16014      * @memberOf _
16015      * @since 4.13.0
16016      * @category Util
16017      * @returns {boolean} Returns `false`.
16018      * @example
16019      *
16020      * _.times(2, _.stubFalse);
16021      * // => [false, false]
16022      */
16023     function stubFalse() {
16024       return false;
16025     }
16026
16027     /**
16028      * This method returns a new empty object.
16029      *
16030      * @static
16031      * @memberOf _
16032      * @since 4.13.0
16033      * @category Util
16034      * @returns {Object} Returns the new empty object.
16035      * @example
16036      *
16037      * var objects = _.times(2, _.stubObject);
16038      *
16039      * console.log(objects);
16040      * // => [{}, {}]
16041      *
16042      * console.log(objects[0] === objects[1]);
16043      * // => false
16044      */
16045     function stubObject() {
16046       return {};
16047     }
16048
16049     /**
16050      * This method returns an empty string.
16051      *
16052      * @static
16053      * @memberOf _
16054      * @since 4.13.0
16055      * @category Util
16056      * @returns {string} Returns the empty string.
16057      * @example
16058      *
16059      * _.times(2, _.stubString);
16060      * // => ['', '']
16061      */
16062     function stubString() {
16063       return '';
16064     }
16065
16066     /**
16067      * This method returns `true`.
16068      *
16069      * @static
16070      * @memberOf _
16071      * @since 4.13.0
16072      * @category Util
16073      * @returns {boolean} Returns `true`.
16074      * @example
16075      *
16076      * _.times(2, _.stubTrue);
16077      * // => [true, true]
16078      */
16079     function stubTrue() {
16080       return true;
16081     }
16082
16083     /**
16084      * Invokes the iteratee `n` times, returning an array of the results of
16085      * each invocation. The iteratee is invoked with one argument; (index).
16086      *
16087      * @static
16088      * @since 0.1.0
16089      * @memberOf _
16090      * @category Util
16091      * @param {number} n The number of times to invoke `iteratee`.
16092      * @param {Function} [iteratee=_.identity] The function invoked per iteration.
16093      * @returns {Array} Returns the array of results.
16094      * @example
16095      *
16096      * _.times(3, String);
16097      * // => ['0', '1', '2']
16098      *
16099      *  _.times(4, _.constant(0));
16100      * // => [0, 0, 0, 0]
16101      */
16102     function times(n, iteratee) {
16103       n = toInteger(n);
16104       if (n < 1 || n > MAX_SAFE_INTEGER) {
16105         return [];
16106       }
16107       var index = MAX_ARRAY_LENGTH,
16108           length = nativeMin(n, MAX_ARRAY_LENGTH);
16109
16110       iteratee = getIteratee(iteratee);
16111       n -= MAX_ARRAY_LENGTH;
16112
16113       var result = baseTimes(length, iteratee);
16114       while (++index < n) {
16115         iteratee(index);
16116       }
16117       return result;
16118     }
16119
16120     /**
16121      * Converts `value` to a property path array.
16122      *
16123      * @static
16124      * @memberOf _
16125      * @since 4.0.0
16126      * @category Util
16127      * @param {*} value The value to convert.
16128      * @returns {Array} Returns the new property path array.
16129      * @example
16130      *
16131      * _.toPath('a.b.c');
16132      * // => ['a', 'b', 'c']
16133      *
16134      * _.toPath('a[0].b.c');
16135      * // => ['a', '0', 'b', 'c']
16136      */
16137     function toPath(value) {
16138       if (isArray(value)) {
16139         return arrayMap(value, toKey);
16140       }
16141       return isSymbol(value) ? [value] : copyArray(stringToPath(toString(value)));
16142     }
16143
16144     /**
16145      * Generates a unique ID. If `prefix` is given, the ID is appended to it.
16146      *
16147      * @static
16148      * @since 0.1.0
16149      * @memberOf _
16150      * @category Util
16151      * @param {string} [prefix=''] The value to prefix the ID with.
16152      * @returns {string} Returns the unique ID.
16153      * @example
16154      *
16155      * _.uniqueId('contact_');
16156      * // => 'contact_104'
16157      *
16158      * _.uniqueId();
16159      * // => '105'
16160      */
16161     function uniqueId(prefix) {
16162       var id = ++idCounter;
16163       return toString(prefix) + id;
16164     }
16165
16166     /*------------------------------------------------------------------------*/
16167
16168     /**
16169      * Adds two numbers.
16170      *
16171      * @static
16172      * @memberOf _
16173      * @since 3.4.0
16174      * @category Math
16175      * @param {number} augend The first number in an addition.
16176      * @param {number} addend The second number in an addition.
16177      * @returns {number} Returns the total.
16178      * @example
16179      *
16180      * _.add(6, 4);
16181      * // => 10
16182      */
16183     var add = createMathOperation(function(augend, addend) {
16184       return augend + addend;
16185     }, 0);
16186
16187     /**
16188      * Computes `number` rounded up to `precision`.
16189      *
16190      * @static
16191      * @memberOf _
16192      * @since 3.10.0
16193      * @category Math
16194      * @param {number} number The number to round up.
16195      * @param {number} [precision=0] The precision to round up to.
16196      * @returns {number} Returns the rounded up number.
16197      * @example
16198      *
16199      * _.ceil(4.006);
16200      * // => 5
16201      *
16202      * _.ceil(6.004, 2);
16203      * // => 6.01
16204      *
16205      * _.ceil(6040, -2);
16206      * // => 6100
16207      */
16208     var ceil = createRound('ceil');
16209
16210     /**
16211      * Divide two numbers.
16212      *
16213      * @static
16214      * @memberOf _
16215      * @since 4.7.0
16216      * @category Math
16217      * @param {number} dividend The first number in a division.
16218      * @param {number} divisor The second number in a division.
16219      * @returns {number} Returns the quotient.
16220      * @example
16221      *
16222      * _.divide(6, 4);
16223      * // => 1.5
16224      */
16225     var divide = createMathOperation(function(dividend, divisor) {
16226       return dividend / divisor;
16227     }, 1);
16228
16229     /**
16230      * Computes `number` rounded down to `precision`.
16231      *
16232      * @static
16233      * @memberOf _
16234      * @since 3.10.0
16235      * @category Math
16236      * @param {number} number The number to round down.
16237      * @param {number} [precision=0] The precision to round down to.
16238      * @returns {number} Returns the rounded down number.
16239      * @example
16240      *
16241      * _.floor(4.006);
16242      * // => 4
16243      *
16244      * _.floor(0.046, 2);
16245      * // => 0.04
16246      *
16247      * _.floor(4060, -2);
16248      * // => 4000
16249      */
16250     var floor = createRound('floor');
16251
16252     /**
16253      * Computes the maximum value of `array`. If `array` is empty or falsey,
16254      * `undefined` is returned.
16255      *
16256      * @static
16257      * @since 0.1.0
16258      * @memberOf _
16259      * @category Math
16260      * @param {Array} array The array to iterate over.
16261      * @returns {*} Returns the maximum value.
16262      * @example
16263      *
16264      * _.max([4, 2, 8, 6]);
16265      * // => 8
16266      *
16267      * _.max([]);
16268      * // => undefined
16269      */
16270     function max(array) {
16271       return (array && array.length)
16272         ? baseExtremum(array, identity, baseGt)
16273         : undefined;
16274     }
16275
16276     /**
16277      * This method is like `_.max` except that it accepts `iteratee` which is
16278      * invoked for each element in `array` to generate the criterion by which
16279      * the value is ranked. The iteratee is invoked with one argument: (value).
16280      *
16281      * @static
16282      * @memberOf _
16283      * @since 4.0.0
16284      * @category Math
16285      * @param {Array} array The array to iterate over.
16286      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16287      * @returns {*} Returns the maximum value.
16288      * @example
16289      *
16290      * var objects = [{ 'n': 1 }, { 'n': 2 }];
16291      *
16292      * _.maxBy(objects, function(o) { return o.n; });
16293      * // => { 'n': 2 }
16294      *
16295      * // The `_.property` iteratee shorthand.
16296      * _.maxBy(objects, 'n');
16297      * // => { 'n': 2 }
16298      */
16299     function maxBy(array, iteratee) {
16300       return (array && array.length)
16301         ? baseExtremum(array, getIteratee(iteratee, 2), baseGt)
16302         : undefined;
16303     }
16304
16305     /**
16306      * Computes the mean of the values in `array`.
16307      *
16308      * @static
16309      * @memberOf _
16310      * @since 4.0.0
16311      * @category Math
16312      * @param {Array} array The array to iterate over.
16313      * @returns {number} Returns the mean.
16314      * @example
16315      *
16316      * _.mean([4, 2, 8, 6]);
16317      * // => 5
16318      */
16319     function mean(array) {
16320       return baseMean(array, identity);
16321     }
16322
16323     /**
16324      * This method is like `_.mean` except that it accepts `iteratee` which is
16325      * invoked for each element in `array` to generate the value to be averaged.
16326      * The iteratee is invoked with one argument: (value).
16327      *
16328      * @static
16329      * @memberOf _
16330      * @since 4.7.0
16331      * @category Math
16332      * @param {Array} array The array to iterate over.
16333      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16334      * @returns {number} Returns the mean.
16335      * @example
16336      *
16337      * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
16338      *
16339      * _.meanBy(objects, function(o) { return o.n; });
16340      * // => 5
16341      *
16342      * // The `_.property` iteratee shorthand.
16343      * _.meanBy(objects, 'n');
16344      * // => 5
16345      */
16346     function meanBy(array, iteratee) {
16347       return baseMean(array, getIteratee(iteratee, 2));
16348     }
16349
16350     /**
16351      * Computes the minimum value of `array`. If `array` is empty or falsey,
16352      * `undefined` is returned.
16353      *
16354      * @static
16355      * @since 0.1.0
16356      * @memberOf _
16357      * @category Math
16358      * @param {Array} array The array to iterate over.
16359      * @returns {*} Returns the minimum value.
16360      * @example
16361      *
16362      * _.min([4, 2, 8, 6]);
16363      * // => 2
16364      *
16365      * _.min([]);
16366      * // => undefined
16367      */
16368     function min(array) {
16369       return (array && array.length)
16370         ? baseExtremum(array, identity, baseLt)
16371         : undefined;
16372     }
16373
16374     /**
16375      * This method is like `_.min` except that it accepts `iteratee` which is
16376      * invoked for each element in `array` to generate the criterion by which
16377      * the value is ranked. The iteratee is invoked with one argument: (value).
16378      *
16379      * @static
16380      * @memberOf _
16381      * @since 4.0.0
16382      * @category Math
16383      * @param {Array} array The array to iterate over.
16384      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16385      * @returns {*} Returns the minimum value.
16386      * @example
16387      *
16388      * var objects = [{ 'n': 1 }, { 'n': 2 }];
16389      *
16390      * _.minBy(objects, function(o) { return o.n; });
16391      * // => { 'n': 1 }
16392      *
16393      * // The `_.property` iteratee shorthand.
16394      * _.minBy(objects, 'n');
16395      * // => { 'n': 1 }
16396      */
16397     function minBy(array, iteratee) {
16398       return (array && array.length)
16399         ? baseExtremum(array, getIteratee(iteratee, 2), baseLt)
16400         : undefined;
16401     }
16402
16403     /**
16404      * Multiply two numbers.
16405      *
16406      * @static
16407      * @memberOf _
16408      * @since 4.7.0
16409      * @category Math
16410      * @param {number} multiplier The first number in a multiplication.
16411      * @param {number} multiplicand The second number in a multiplication.
16412      * @returns {number} Returns the product.
16413      * @example
16414      *
16415      * _.multiply(6, 4);
16416      * // => 24
16417      */
16418     var multiply = createMathOperation(function(multiplier, multiplicand) {
16419       return multiplier * multiplicand;
16420     }, 1);
16421
16422     /**
16423      * Computes `number` rounded to `precision`.
16424      *
16425      * @static
16426      * @memberOf _
16427      * @since 3.10.0
16428      * @category Math
16429      * @param {number} number The number to round.
16430      * @param {number} [precision=0] The precision to round to.
16431      * @returns {number} Returns the rounded number.
16432      * @example
16433      *
16434      * _.round(4.006);
16435      * // => 4
16436      *
16437      * _.round(4.006, 2);
16438      * // => 4.01
16439      *
16440      * _.round(4060, -2);
16441      * // => 4100
16442      */
16443     var round = createRound('round');
16444
16445     /**
16446      * Subtract two numbers.
16447      *
16448      * @static
16449      * @memberOf _
16450      * @since 4.0.0
16451      * @category Math
16452      * @param {number} minuend The first number in a subtraction.
16453      * @param {number} subtrahend The second number in a subtraction.
16454      * @returns {number} Returns the difference.
16455      * @example
16456      *
16457      * _.subtract(6, 4);
16458      * // => 2
16459      */
16460     var subtract = createMathOperation(function(minuend, subtrahend) {
16461       return minuend - subtrahend;
16462     }, 0);
16463
16464     /**
16465      * Computes the sum of the values in `array`.
16466      *
16467      * @static
16468      * @memberOf _
16469      * @since 3.4.0
16470      * @category Math
16471      * @param {Array} array The array to iterate over.
16472      * @returns {number} Returns the sum.
16473      * @example
16474      *
16475      * _.sum([4, 2, 8, 6]);
16476      * // => 20
16477      */
16478     function sum(array) {
16479       return (array && array.length)
16480         ? baseSum(array, identity)
16481         : 0;
16482     }
16483
16484     /**
16485      * This method is like `_.sum` except that it accepts `iteratee` which is
16486      * invoked for each element in `array` to generate the value to be summed.
16487      * The iteratee is invoked with one argument: (value).
16488      *
16489      * @static
16490      * @memberOf _
16491      * @since 4.0.0
16492      * @category Math
16493      * @param {Array} array The array to iterate over.
16494      * @param {Function} [iteratee=_.identity] The iteratee invoked per element.
16495      * @returns {number} Returns the sum.
16496      * @example
16497      *
16498      * var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
16499      *
16500      * _.sumBy(objects, function(o) { return o.n; });
16501      * // => 20
16502      *
16503      * // The `_.property` iteratee shorthand.
16504      * _.sumBy(objects, 'n');
16505      * // => 20
16506      */
16507     function sumBy(array, iteratee) {
16508       return (array && array.length)
16509         ? baseSum(array, getIteratee(iteratee, 2))
16510         : 0;
16511     }
16512
16513     /*------------------------------------------------------------------------*/
16514
16515     // Add methods that return wrapped values in chain sequences.
16516     lodash.after = after;
16517     lodash.ary = ary;
16518     lodash.assign = assign;
16519     lodash.assignIn = assignIn;
16520     lodash.assignInWith = assignInWith;
16521     lodash.assignWith = assignWith;
16522     lodash.at = at;
16523     lodash.before = before;
16524     lodash.bind = bind;
16525     lodash.bindAll = bindAll;
16526     lodash.bindKey = bindKey;
16527     lodash.castArray = castArray;
16528     lodash.chain = chain;
16529     lodash.chunk = chunk;
16530     lodash.compact = compact;
16531     lodash.concat = concat;
16532     lodash.cond = cond;
16533     lodash.conforms = conforms;
16534     lodash.constant = constant;
16535     lodash.countBy = countBy;
16536     lodash.create = create;
16537     lodash.curry = curry;
16538     lodash.curryRight = curryRight;
16539     lodash.debounce = debounce;
16540     lodash.defaults = defaults;
16541     lodash.defaultsDeep = defaultsDeep;
16542     lodash.defer = defer;
16543     lodash.delay = delay;
16544     lodash.difference = difference;
16545     lodash.differenceBy = differenceBy;
16546     lodash.differenceWith = differenceWith;
16547     lodash.drop = drop;
16548     lodash.dropRight = dropRight;
16549     lodash.dropRightWhile = dropRightWhile;
16550     lodash.dropWhile = dropWhile;
16551     lodash.fill = fill;
16552     lodash.filter = filter;
16553     lodash.flatMap = flatMap;
16554     lodash.flatMapDeep = flatMapDeep;
16555     lodash.flatMapDepth = flatMapDepth;
16556     lodash.flatten = flatten;
16557     lodash.flattenDeep = flattenDeep;
16558     lodash.flattenDepth = flattenDepth;
16559     lodash.flip = flip;
16560     lodash.flow = flow;
16561     lodash.flowRight = flowRight;
16562     lodash.fromPairs = fromPairs;
16563     lodash.functions = functions;
16564     lodash.functionsIn = functionsIn;
16565     lodash.groupBy = groupBy;
16566     lodash.initial = initial;
16567     lodash.intersection = intersection;
16568     lodash.intersectionBy = intersectionBy;
16569     lodash.intersectionWith = intersectionWith;
16570     lodash.invert = invert;
16571     lodash.invertBy = invertBy;
16572     lodash.invokeMap = invokeMap;
16573     lodash.iteratee = iteratee;
16574     lodash.keyBy = keyBy;
16575     lodash.keys = keys;
16576     lodash.keysIn = keysIn;
16577     lodash.map = map;
16578     lodash.mapKeys = mapKeys;
16579     lodash.mapValues = mapValues;
16580     lodash.matches = matches;
16581     lodash.matchesProperty = matchesProperty;
16582     lodash.memoize = memoize;
16583     lodash.merge = merge;
16584     lodash.mergeWith = mergeWith;
16585     lodash.method = method;
16586     lodash.methodOf = methodOf;
16587     lodash.mixin = mixin;
16588     lodash.negate = negate;
16589     lodash.nthArg = nthArg;
16590     lodash.omit = omit;
16591     lodash.omitBy = omitBy;
16592     lodash.once = once;
16593     lodash.orderBy = orderBy;
16594     lodash.over = over;
16595     lodash.overArgs = overArgs;
16596     lodash.overEvery = overEvery;
16597     lodash.overSome = overSome;
16598     lodash.partial = partial;
16599     lodash.partialRight = partialRight;
16600     lodash.partition = partition;
16601     lodash.pick = pick;
16602     lodash.pickBy = pickBy;
16603     lodash.property = property;
16604     lodash.propertyOf = propertyOf;
16605     lodash.pull = pull;
16606     lodash.pullAll = pullAll;
16607     lodash.pullAllBy = pullAllBy;
16608     lodash.pullAllWith = pullAllWith;
16609     lodash.pullAt = pullAt;
16610     lodash.range = range;
16611     lodash.rangeRight = rangeRight;
16612     lodash.rearg = rearg;
16613     lodash.reject = reject;
16614     lodash.remove = remove;
16615     lodash.rest = rest;
16616     lodash.reverse = reverse;
16617     lodash.sampleSize = sampleSize;
16618     lodash.set = set;
16619     lodash.setWith = setWith;
16620     lodash.shuffle = shuffle;
16621     lodash.slice = slice;
16622     lodash.sortBy = sortBy;
16623     lodash.sortedUniq = sortedUniq;
16624     lodash.sortedUniqBy = sortedUniqBy;
16625     lodash.split = split;
16626     lodash.spread = spread;
16627     lodash.tail = tail;
16628     lodash.take = take;
16629     lodash.takeRight = takeRight;
16630     lodash.takeRightWhile = takeRightWhile;
16631     lodash.takeWhile = takeWhile;
16632     lodash.tap = tap;
16633     lodash.throttle = throttle;
16634     lodash.thru = thru;
16635     lodash.toArray = toArray;
16636     lodash.toPairs = toPairs;
16637     lodash.toPairsIn = toPairsIn;
16638     lodash.toPath = toPath;
16639     lodash.toPlainObject = toPlainObject;
16640     lodash.transform = transform;
16641     lodash.unary = unary;
16642     lodash.union = union;
16643     lodash.unionBy = unionBy;
16644     lodash.unionWith = unionWith;
16645     lodash.uniq = uniq;
16646     lodash.uniqBy = uniqBy;
16647     lodash.uniqWith = uniqWith;
16648     lodash.unset = unset;
16649     lodash.unzip = unzip;
16650     lodash.unzipWith = unzipWith;
16651     lodash.update = update;
16652     lodash.updateWith = updateWith;
16653     lodash.values = values;
16654     lodash.valuesIn = valuesIn;
16655     lodash.without = without;
16656     lodash.words = words;
16657     lodash.wrap = wrap;
16658     lodash.xor = xor;
16659     lodash.xorBy = xorBy;
16660     lodash.xorWith = xorWith;
16661     lodash.zip = zip;
16662     lodash.zipObject = zipObject;
16663     lodash.zipObjectDeep = zipObjectDeep;
16664     lodash.zipWith = zipWith;
16665
16666     // Add aliases.
16667     lodash.entries = toPairs;
16668     lodash.entriesIn = toPairsIn;
16669     lodash.extend = assignIn;
16670     lodash.extendWith = assignInWith;
16671
16672     // Add methods to `lodash.prototype`.
16673     mixin(lodash, lodash);
16674
16675     /*------------------------------------------------------------------------*/
16676
16677     // Add methods that return unwrapped values in chain sequences.
16678     lodash.add = add;
16679     lodash.attempt = attempt;
16680     lodash.camelCase = camelCase;
16681     lodash.capitalize = capitalize;
16682     lodash.ceil = ceil;
16683     lodash.clamp = clamp;
16684     lodash.clone = clone;
16685     lodash.cloneDeep = cloneDeep;
16686     lodash.cloneDeepWith = cloneDeepWith;
16687     lodash.cloneWith = cloneWith;
16688     lodash.conformsTo = conformsTo;
16689     lodash.deburr = deburr;
16690     lodash.defaultTo = defaultTo;
16691     lodash.divide = divide;
16692     lodash.endsWith = endsWith;
16693     lodash.eq = eq;
16694     lodash.escape = escape;
16695     lodash.escapeRegExp = escapeRegExp;
16696     lodash.every = every;
16697     lodash.find = find;
16698     lodash.findIndex = findIndex;
16699     lodash.findKey = findKey;
16700     lodash.findLast = findLast;
16701     lodash.findLastIndex = findLastIndex;
16702     lodash.findLastKey = findLastKey;
16703     lodash.floor = floor;
16704     lodash.forEach = forEach;
16705     lodash.forEachRight = forEachRight;
16706     lodash.forIn = forIn;
16707     lodash.forInRight = forInRight;
16708     lodash.forOwn = forOwn;
16709     lodash.forOwnRight = forOwnRight;
16710     lodash.get = get;
16711     lodash.gt = gt;
16712     lodash.gte = gte;
16713     lodash.has = has;
16714     lodash.hasIn = hasIn;
16715     lodash.head = head;
16716     lodash.identity = identity;
16717     lodash.includes = includes;
16718     lodash.indexOf = indexOf;
16719     lodash.inRange = inRange;
16720     lodash.invoke = invoke;
16721     lodash.isArguments = isArguments;
16722     lodash.isArray = isArray;
16723     lodash.isArrayBuffer = isArrayBuffer;
16724     lodash.isArrayLike = isArrayLike;
16725     lodash.isArrayLikeObject = isArrayLikeObject;
16726     lodash.isBoolean = isBoolean;
16727     lodash.isBuffer = isBuffer;
16728     lodash.isDate = isDate;
16729     lodash.isElement = isElement;
16730     lodash.isEmpty = isEmpty;
16731     lodash.isEqual = isEqual;
16732     lodash.isEqualWith = isEqualWith;
16733     lodash.isError = isError;
16734     lodash.isFinite = isFinite;
16735     lodash.isFunction = isFunction;
16736     lodash.isInteger = isInteger;
16737     lodash.isLength = isLength;
16738     lodash.isMap = isMap;
16739     lodash.isMatch = isMatch;
16740     lodash.isMatchWith = isMatchWith;
16741     lodash.isNaN = isNaN;
16742     lodash.isNative = isNative;
16743     lodash.isNil = isNil;
16744     lodash.isNull = isNull;
16745     lodash.isNumber = isNumber;
16746     lodash.isObject = isObject;
16747     lodash.isObjectLike = isObjectLike;
16748     lodash.isPlainObject = isPlainObject;
16749     lodash.isRegExp = isRegExp;
16750     lodash.isSafeInteger = isSafeInteger;
16751     lodash.isSet = isSet;
16752     lodash.isString = isString;
16753     lodash.isSymbol = isSymbol;
16754     lodash.isTypedArray = isTypedArray;
16755     lodash.isUndefined = isUndefined;
16756     lodash.isWeakMap = isWeakMap;
16757     lodash.isWeakSet = isWeakSet;
16758     lodash.join = join;
16759     lodash.kebabCase = kebabCase;
16760     lodash.last = last;
16761     lodash.lastIndexOf = lastIndexOf;
16762     lodash.lowerCase = lowerCase;
16763     lodash.lowerFirst = lowerFirst;
16764     lodash.lt = lt;
16765     lodash.lte = lte;
16766     lodash.max = max;
16767     lodash.maxBy = maxBy;
16768     lodash.mean = mean;
16769     lodash.meanBy = meanBy;
16770     lodash.min = min;
16771     lodash.minBy = minBy;
16772     lodash.stubArray = stubArray;
16773     lodash.stubFalse = stubFalse;
16774     lodash.stubObject = stubObject;
16775     lodash.stubString = stubString;
16776     lodash.stubTrue = stubTrue;
16777     lodash.multiply = multiply;
16778     lodash.nth = nth;
16779     lodash.noConflict = noConflict;
16780     lodash.noop = noop;
16781     lodash.now = now;
16782     lodash.pad = pad;
16783     lodash.padEnd = padEnd;
16784     lodash.padStart = padStart;
16785     lodash.parseInt = parseInt;
16786     lodash.random = random;
16787     lodash.reduce = reduce;
16788     lodash.reduceRight = reduceRight;
16789     lodash.repeat = repeat;
16790     lodash.replace = replace;
16791     lodash.result = result;
16792     lodash.round = round;
16793     lodash.runInContext = runInContext;
16794     lodash.sample = sample;
16795     lodash.size = size;
16796     lodash.snakeCase = snakeCase;
16797     lodash.some = some;
16798     lodash.sortedIndex = sortedIndex;
16799     lodash.sortedIndexBy = sortedIndexBy;
16800     lodash.sortedIndexOf = sortedIndexOf;
16801     lodash.sortedLastIndex = sortedLastIndex;
16802     lodash.sortedLastIndexBy = sortedLastIndexBy;
16803     lodash.sortedLastIndexOf = sortedLastIndexOf;
16804     lodash.startCase = startCase;
16805     lodash.startsWith = startsWith;
16806     lodash.subtract = subtract;
16807     lodash.sum = sum;
16808     lodash.sumBy = sumBy;
16809     lodash.template = template;
16810     lodash.times = times;
16811     lodash.toFinite = toFinite;
16812     lodash.toInteger = toInteger;
16813     lodash.toLength = toLength;
16814     lodash.toLower = toLower;
16815     lodash.toNumber = toNumber;
16816     lodash.toSafeInteger = toSafeInteger;
16817     lodash.toString = toString;
16818     lodash.toUpper = toUpper;
16819     lodash.trim = trim;
16820     lodash.trimEnd = trimEnd;
16821     lodash.trimStart = trimStart;
16822     lodash.truncate = truncate;
16823     lodash.unescape = unescape;
16824     lodash.uniqueId = uniqueId;
16825     lodash.upperCase = upperCase;
16826     lodash.upperFirst = upperFirst;
16827
16828     // Add aliases.
16829     lodash.each = forEach;
16830     lodash.eachRight = forEachRight;
16831     lodash.first = head;
16832
16833     mixin(lodash, (function() {
16834       var source = {};
16835       baseForOwn(lodash, function(func, methodName) {
16836         if (!hasOwnProperty.call(lodash.prototype, methodName)) {
16837           source[methodName] = func;
16838         }
16839       });
16840       return source;
16841     }()), { 'chain': false });
16842
16843     /*------------------------------------------------------------------------*/
16844
16845     /**
16846      * The semantic version number.
16847      *
16848      * @static
16849      * @memberOf _
16850      * @type {string}
16851      */
16852     lodash.VERSION = VERSION;
16853
16854     // Assign default placeholders.
16855     arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
16856       lodash[methodName].placeholder = lodash;
16857     });
16858
16859     // Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
16860     arrayEach(['drop', 'take'], function(methodName, index) {
16861       LazyWrapper.prototype[methodName] = function(n) {
16862         n = n === undefined ? 1 : nativeMax(toInteger(n), 0);
16863
16864         var result = (this.__filtered__ && !index)
16865           ? new LazyWrapper(this)
16866           : this.clone();
16867
16868         if (result.__filtered__) {
16869           result.__takeCount__ = nativeMin(n, result.__takeCount__);
16870         } else {
16871           result.__views__.push({
16872             'size': nativeMin(n, MAX_ARRAY_LENGTH),
16873             'type': methodName + (result.__dir__ < 0 ? 'Right' : '')
16874           });
16875         }
16876         return result;
16877       };
16878
16879       LazyWrapper.prototype[methodName + 'Right'] = function(n) {
16880         return this.reverse()[methodName](n).reverse();
16881       };
16882     });
16883
16884     // Add `LazyWrapper` methods that accept an `iteratee` value.
16885     arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
16886       var type = index + 1,
16887           isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG;
16888
16889       LazyWrapper.prototype[methodName] = function(iteratee) {
16890         var result = this.clone();
16891         result.__iteratees__.push({
16892           'iteratee': getIteratee(iteratee, 3),
16893           'type': type
16894         });
16895         result.__filtered__ = result.__filtered__ || isFilter;
16896         return result;
16897       };
16898     });
16899
16900     // Add `LazyWrapper` methods for `_.head` and `_.last`.
16901     arrayEach(['head', 'last'], function(methodName, index) {
16902       var takeName = 'take' + (index ? 'Right' : '');
16903
16904       LazyWrapper.prototype[methodName] = function() {
16905         return this[takeName](1).value()[0];
16906       };
16907     });
16908
16909     // Add `LazyWrapper` methods for `_.initial` and `_.tail`.
16910     arrayEach(['initial', 'tail'], function(methodName, index) {
16911       var dropName = 'drop' + (index ? '' : 'Right');
16912
16913       LazyWrapper.prototype[methodName] = function() {
16914         return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1);
16915       };
16916     });
16917
16918     LazyWrapper.prototype.compact = function() {
16919       return this.filter(identity);
16920     };
16921
16922     LazyWrapper.prototype.find = function(predicate) {
16923       return this.filter(predicate).head();
16924     };
16925
16926     LazyWrapper.prototype.findLast = function(predicate) {
16927       return this.reverse().find(predicate);
16928     };
16929
16930     LazyWrapper.prototype.invokeMap = baseRest(function(path, args) {
16931       if (typeof path == 'function') {
16932         return new LazyWrapper(this);
16933       }
16934       return this.map(function(value) {
16935         return baseInvoke(value, path, args);
16936       });
16937     });
16938
16939     LazyWrapper.prototype.reject = function(predicate) {
16940       return this.filter(negate(getIteratee(predicate)));
16941     };
16942
16943     LazyWrapper.prototype.slice = function(start, end) {
16944       start = toInteger(start);
16945
16946       var result = this;
16947       if (result.__filtered__ && (start > 0 || end < 0)) {
16948         return new LazyWrapper(result);
16949       }
16950       if (start < 0) {
16951         result = result.takeRight(-start);
16952       } else if (start) {
16953         result = result.drop(start);
16954       }
16955       if (end !== undefined) {
16956         end = toInteger(end);
16957         result = end < 0 ? result.dropRight(-end) : result.take(end - start);
16958       }
16959       return result;
16960     };
16961
16962     LazyWrapper.prototype.takeRightWhile = function(predicate) {
16963       return this.reverse().takeWhile(predicate).reverse();
16964     };
16965
16966     LazyWrapper.prototype.toArray = function() {
16967       return this.take(MAX_ARRAY_LENGTH);
16968     };
16969
16970     // Add `LazyWrapper` methods to `lodash.prototype`.
16971     baseForOwn(LazyWrapper.prototype, function(func, methodName) {
16972       var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName),
16973           isTaker = /^(?:head|last)$/.test(methodName),
16974           lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName],
16975           retUnwrapped = isTaker || /^find/.test(methodName);
16976
16977       if (!lodashFunc) {
16978         return;
16979       }
16980       lodash.prototype[methodName] = function() {
16981         var value = this.__wrapped__,
16982             args = isTaker ? [1] : arguments,
16983             isLazy = value instanceof LazyWrapper,
16984             iteratee = args[0],
16985             useLazy = isLazy || isArray(value);
16986
16987         var interceptor = function(value) {
16988           var result = lodashFunc.apply(lodash, arrayPush([value], args));
16989           return (isTaker && chainAll) ? result[0] : result;
16990         };
16991
16992         if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
16993           // Avoid lazy use if the iteratee has a "length" value other than `1`.
16994           isLazy = useLazy = false;
16995         }
16996         var chainAll = this.__chain__,
16997             isHybrid = !!this.__actions__.length,
16998             isUnwrapped = retUnwrapped && !chainAll,
16999             onlyLazy = isLazy && !isHybrid;
17000
17001         if (!retUnwrapped && useLazy) {
17002           value = onlyLazy ? value : new LazyWrapper(this);
17003           var result = func.apply(value, args);
17004           result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined });
17005           return new LodashWrapper(result, chainAll);
17006         }
17007         if (isUnwrapped && onlyLazy) {
17008           return func.apply(this, args);
17009         }
17010         result = this.thru(interceptor);
17011         return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result;
17012       };
17013     });
17014
17015     // Add `Array` methods to `lodash.prototype`.
17016     arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
17017       var func = arrayProto[methodName],
17018           chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
17019           retUnwrapped = /^(?:pop|shift)$/.test(methodName);
17020
17021       lodash.prototype[methodName] = function() {
17022         var args = arguments;
17023         if (retUnwrapped && !this.__chain__) {
17024           var value = this.value();
17025           return func.apply(isArray(value) ? value : [], args);
17026         }
17027         return this[chainName](function(value) {
17028           return func.apply(isArray(value) ? value : [], args);
17029         });
17030       };
17031     });
17032
17033     // Map minified method names to their real names.
17034     baseForOwn(LazyWrapper.prototype, function(func, methodName) {
17035       var lodashFunc = lodash[methodName];
17036       if (lodashFunc) {
17037         var key = (lodashFunc.name + ''),
17038             names = realNames[key] || (realNames[key] = []);
17039
17040         names.push({ 'name': methodName, 'func': lodashFunc });
17041       }
17042     });
17043
17044     realNames[createHybrid(undefined, WRAP_BIND_KEY_FLAG).name] = [{
17045       'name': 'wrapper',
17046       'func': undefined
17047     }];
17048
17049     // Add methods to `LazyWrapper`.
17050     LazyWrapper.prototype.clone = lazyClone;
17051     LazyWrapper.prototype.reverse = lazyReverse;
17052     LazyWrapper.prototype.value = lazyValue;
17053
17054     // Add chain sequence methods to the `lodash` wrapper.
17055     lodash.prototype.at = wrapperAt;
17056     lodash.prototype.chain = wrapperChain;
17057     lodash.prototype.commit = wrapperCommit;
17058     lodash.prototype.next = wrapperNext;
17059     lodash.prototype.plant = wrapperPlant;
17060     lodash.prototype.reverse = wrapperReverse;
17061     lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
17062
17063     // Add lazy aliases.
17064     lodash.prototype.first = lodash.prototype.head;
17065
17066     if (symIterator) {
17067       lodash.prototype[symIterator] = wrapperToIterator;
17068     }
17069     return lodash;
17070   });
17071
17072   /*--------------------------------------------------------------------------*/
17073
17074   // Export lodash.
17075   var _ = runInContext();
17076
17077   // Some AMD build optimizers, like r.js, check for condition patterns like:
17078   if (typeof undefined == 'function' && typeof undefined.amd == 'object' && undefined.amd) {
17079     // Expose Lodash on the global object to prevent errors when Lodash is
17080     // loaded by a script tag in the presence of an AMD loader.
17081     // See http://requirejs.org/docs/errors.html#mismatch for more details.
17082     // Use `_.noConflict` to remove Lodash from the global object.
17083     root._ = _;
17084
17085     // Define as an anonymous module so, through path mapping, it can be
17086     // referenced as the "underscore" module.
17087     undefined(function() {
17088       return _;
17089     });
17090   }
17091   // Check for `exports` after `define` in case a build optimizer adds it.
17092   else if (freeModule) {
17093     // Export for Node.js.
17094     (freeModule.exports = _)._ = _;
17095     // Export for CommonJS support.
17096     freeExports._ = _;
17097   }
17098   else {
17099     // Export to the global object.
17100     root._ = _;
17101   }
17102 }.call(commonjsGlobal));
17103 });
17104
17105
17106
17107 var lodash$1 = Object.freeze({
17108         default: lodash,
17109         __moduleExports: lodash
17110 });
17111
17112 function osmIsInterestingTag(key) {
17113     return key !== 'attribution' &&
17114         key !== 'created_by' &&
17115         key !== 'source' &&
17116         key !== 'odbl' &&
17117         key.indexOf('tiger:') !== 0;
17118
17119 }
17120
17121
17122 var osmOneWayTags = {
17123     'aerialway': {
17124         'chair_lift': true,
17125         'mixed_lift': true,
17126         't-bar': true,
17127         'j-bar': true,
17128         'platter': true,
17129         'rope_tow': true,
17130         'magic_carpet': true,
17131         'yes': true
17132     },
17133     'highway': {
17134         'motorway': true,
17135         'motorway_link': true
17136     },
17137     'junction': {
17138         'roundabout': true
17139     },
17140     'man_made': {
17141         'piste:halfpipe': true
17142     },
17143     'piste:type': {
17144         'downhill': true,
17145         'sled': true,
17146         'yes': true
17147     },
17148     'waterway': {
17149         'canal': true,
17150         'ditch': true,
17151         'drain': true,
17152         'river': true,
17153         'stream': true
17154     }
17155 };
17156
17157
17158 var osmPavedTags = {
17159     'surface': {
17160         'paved': true,
17161         'asphalt': true,
17162         'concrete': true
17163     },
17164     'tracktype': {
17165         'grade1': true
17166     }
17167 };
17168
17169 var dataWikipedia = [
17170     [
17171         "Abkhazian",
17172         "Аҧсшәа",
17173         "ab"
17174     ],
17175     [
17176         "Achinese",
17177         "Acèh",
17178         "ace"
17179     ],
17180     [
17181         "Adyghe",
17182         "адыгабзэ",
17183         "ady"
17184     ],
17185     [
17186         "Afrikaans",
17187         "Afrikaans",
17188         "af"
17189     ],
17190     [
17191         "Akan",
17192         "Akan",
17193         "ak"
17194     ],
17195     [
17196         "Alemannisch",
17197         "Alemannisch",
17198         "als"
17199     ],
17200     [
17201         "Amharic",
17202         "አማርኛ",
17203         "am"
17204     ],
17205     [
17206         "Aragonese",
17207         "aragonés",
17208         "an"
17209     ],
17210     [
17211         "Old English",
17212         "Ænglisc",
17213         "ang"
17214     ],
17215     [
17216         "Arabic",
17217         "العربية",
17218         "ar"
17219     ],
17220     [
17221         "Aramaic",
17222         "ܐܪܡܝܐ",
17223         "arc"
17224     ],
17225     [
17226         "Egyptian Arabic",
17227         "مصرى",
17228         "arz"
17229     ],
17230     [
17231         "Assamese",
17232         "অসমীয়া",
17233         "as"
17234     ],
17235     [
17236         "Asturian",
17237         "asturianu",
17238         "ast"
17239     ],
17240     [
17241         "Avaric",
17242         "авар",
17243         "av"
17244     ],
17245     [
17246         "Aymara",
17247         "Aymar aru",
17248         "ay"
17249     ],
17250     [
17251         "Azerbaijani",
17252         "azərbaycanca",
17253         "az"
17254     ],
17255     [
17256         "تۆرکجه",
17257         "تۆرکجه",
17258         "azb"
17259     ],
17260     [
17261         "Bashkir",
17262         "башҡортса",
17263         "ba"
17264     ],
17265     [
17266         "Bavarian",
17267         "Boarisch",
17268         "bar"
17269     ],
17270     [
17271         "Samogitian",
17272         "žemaitėška",
17273         "bat-smg"
17274     ],
17275     [
17276         "Bikol Central",
17277         "Bikol Central",
17278         "bcl"
17279     ],
17280     [
17281         "Belarusian",
17282         "беларуская",
17283         "be"
17284     ],
17285     [
17286         "беларуская (тарашкевіца)‎",
17287         "беларуская (тарашкевіца)‎",
17288         "be-x-old"
17289     ],
17290     [
17291         "Bulgarian",
17292         "български",
17293         "bg"
17294     ],
17295     [
17296         "भोजपुरी",
17297         "भोजपुरी",
17298         "bh"
17299     ],
17300     [
17301         "Bislama",
17302         "Bislama",
17303         "bi"
17304     ],
17305     [
17306         "Banjar",
17307         "Bahasa Banjar",
17308         "bjn"
17309     ],
17310     [
17311         "Bambara",
17312         "bamanankan",
17313         "bm"
17314     ],
17315     [
17316         "Bangla",
17317         "বাংলা",
17318         "bn"
17319     ],
17320     [
17321         "Tibetan",
17322         "བོད་ཡིག",
17323         "bo"
17324     ],
17325     [
17326         "Bishnupriya",
17327         "বিষ্ণুপ্রিয়া মণিপুরী",
17328         "bpy"
17329     ],
17330     [
17331         "Breton",
17332         "brezhoneg",
17333         "br"
17334     ],
17335     [
17336         "Bosnian",
17337         "bosanski",
17338         "bs"
17339     ],
17340     [
17341         "Buginese",
17342         "ᨅᨔ ᨕᨘᨁᨗ",
17343         "bug"
17344     ],
17345     [
17346         "буряад",
17347         "буряад",
17348         "bxr"
17349     ],
17350     [
17351         "Catalan",
17352         "català",
17353         "ca"
17354     ],
17355     [
17356         "Chavacano de Zamboanga",
17357         "Chavacano de Zamboanga",
17358         "cbk-zam"
17359     ],
17360     [
17361         "Min Dong Chinese",
17362         "Mìng-dĕ̤ng-ngṳ̄",
17363         "cdo"
17364     ],
17365     [
17366         "Chechen",
17367         "нохчийн",
17368         "ce"
17369     ],
17370     [
17371         "Cebuano",
17372         "Cebuano",
17373         "ceb"
17374     ],
17375     [
17376         "Chamorro",
17377         "Chamoru",
17378         "ch"
17379     ],
17380     [
17381         "Cherokee",
17382         "ᏣᎳᎩ",
17383         "chr"
17384     ],
17385     [
17386         "Cheyenne",
17387         "Tsetsêhestâhese",
17388         "chy"
17389     ],
17390     [
17391         "Central Kurdish",
17392         "کوردیی ناوەندی",
17393         "ckb"
17394     ],
17395     [
17396         "Corsican",
17397         "corsu",
17398         "co"
17399     ],
17400     [
17401         "Cree",
17402         "Nēhiyawēwin / ᓀᐦᐃᔭᐍᐏᐣ",
17403         "cr"
17404     ],
17405     [
17406         "Crimean Turkish",
17407         "qırımtatarca",
17408         "crh"
17409     ],
17410     [
17411         "Czech",
17412         "čeština",
17413         "cs"
17414     ],
17415     [
17416         "Kashubian",
17417         "kaszëbsczi",
17418         "csb"
17419     ],
17420     [
17421         "Church Slavic",
17422         "словѣньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ",
17423         "cu"
17424     ],
17425     [
17426         "Chuvash",
17427         "Чӑвашла",
17428         "cv"
17429     ],
17430     [
17431         "Welsh",
17432         "Cymraeg",
17433         "cy"
17434     ],
17435     [
17436         "Danish",
17437         "dansk",
17438         "da"
17439     ],
17440     [
17441         "German",
17442         "Deutsch",
17443         "de"
17444     ],
17445     [
17446         "Zazaki",
17447         "Zazaki",
17448         "diq"
17449     ],
17450     [
17451         "Lower Sorbian",
17452         "dolnoserbski",
17453         "dsb"
17454     ],
17455     [
17456         "Divehi",
17457         "ދިވެހިބަސް",
17458         "dv"
17459     ],
17460     [
17461         "Dzongkha",
17462         "ཇོང་ཁ",
17463         "dz"
17464     ],
17465     [
17466         "Ewe",
17467         "eʋegbe",
17468         "ee"
17469     ],
17470     [
17471         "Greek",
17472         "Ελληνικά",
17473         "el"
17474     ],
17475     [
17476         "Emiliano-Romagnolo",
17477         "emiliàn e rumagnòl",
17478         "eml"
17479     ],
17480     [
17481         "English",
17482         "English",
17483         "en"
17484     ],
17485     [
17486         "Esperanto",
17487         "Esperanto",
17488         "eo"
17489     ],
17490     [
17491         "Spanish",
17492         "español",
17493         "es"
17494     ],
17495     [
17496         "Estonian",
17497         "eesti",
17498         "et"
17499     ],
17500     [
17501         "Basque",
17502         "euskara",
17503         "eu"
17504     ],
17505     [
17506         "Extremaduran",
17507         "estremeñu",
17508         "ext"
17509     ],
17510     [
17511         "Persian",
17512         "فارسی",
17513         "fa"
17514     ],
17515     [
17516         "Fulah",
17517         "Fulfulde",
17518         "ff"
17519     ],
17520     [
17521         "Finnish",
17522         "suomi",
17523         "fi"
17524     ],
17525     [
17526         "Võro",
17527         "Võro",
17528         "fiu-vro"
17529     ],
17530     [
17531         "Fijian",
17532         "Na Vosa Vakaviti",
17533         "fj"
17534     ],
17535     [
17536         "Faroese",
17537         "føroyskt",
17538         "fo"
17539     ],
17540     [
17541         "French",
17542         "français",
17543         "fr"
17544     ],
17545     [
17546         "Arpitan",
17547         "arpetan",
17548         "frp"
17549     ],
17550     [
17551         "Northern Frisian",
17552         "Nordfriisk",
17553         "frr"
17554     ],
17555     [
17556         "Friulian",
17557         "furlan",
17558         "fur"
17559     ],
17560     [
17561         "Western Frisian",
17562         "Frysk",
17563         "fy"
17564     ],
17565     [
17566         "Irish",
17567         "Gaeilge",
17568         "ga"
17569     ],
17570     [
17571         "Gagauz",
17572         "Gagauz",
17573         "gag"
17574     ],
17575     [
17576         "Gan Chinese",
17577         "贛語",
17578         "gan"
17579     ],
17580     [
17581         "Scottish Gaelic",
17582         "Gàidhlig",
17583         "gd"
17584     ],
17585     [
17586         "Galician",
17587         "galego",
17588         "gl"
17589     ],
17590     [
17591         "Gilaki",
17592         "گیلکی",
17593         "glk"
17594     ],
17595     [
17596         "Guarani",
17597         "Avañe'ẽ",
17598         "gn"
17599     ],
17600     [
17601         "Goan Konkani",
17602         "गोंयची कोंकणी / Gõychi Konknni",
17603         "gom"
17604     ],
17605     [
17606         "Gothic",
17607         "𐌲𐌿𐍄𐌹𐍃𐌺",
17608         "got"
17609     ],
17610     [
17611         "Gujarati",
17612         "ગુજરાતી",
17613         "gu"
17614     ],
17615     [
17616         "Manx",
17617         "Gaelg",
17618         "gv"
17619     ],
17620     [
17621         "Hausa",
17622         "Hausa",
17623         "ha"
17624     ],
17625     [
17626         "Hakka Chinese",
17627         "客家語/Hak-kâ-ngî",
17628         "hak"
17629     ],
17630     [
17631         "Hawaiian",
17632         "Hawaiʻi",
17633         "haw"
17634     ],
17635     [
17636         "Hebrew",
17637         "עברית",
17638         "he"
17639     ],
17640     [
17641         "Hindi",
17642         "हिन्दी",
17643         "hi"
17644     ],
17645     [
17646         "Fiji Hindi",
17647         "Fiji Hindi",
17648         "hif"
17649     ],
17650     [
17651         "Croatian",
17652         "hrvatski",
17653         "hr"
17654     ],
17655     [
17656         "Upper Sorbian",
17657         "hornjoserbsce",
17658         "hsb"
17659     ],
17660     [
17661         "Haitian Creole",
17662         "Kreyòl ayisyen",
17663         "ht"
17664     ],
17665     [
17666         "Hungarian",
17667         "magyar",
17668         "hu"
17669     ],
17670     [
17671         "Armenian",
17672         "Հայերեն",
17673         "hy"
17674     ],
17675     [
17676         "Interlingua",
17677         "interlingua",
17678         "ia"
17679     ],
17680     [
17681         "Indonesian",
17682         "Bahasa Indonesia",
17683         "id"
17684     ],
17685     [
17686         "Interlingue",
17687         "Interlingue",
17688         "ie"
17689     ],
17690     [
17691         "Igbo",
17692         "Igbo",
17693         "ig"
17694     ],
17695     [
17696         "Inupiaq",
17697         "Iñupiak",
17698         "ik"
17699     ],
17700     [
17701         "Iloko",
17702         "Ilokano",
17703         "ilo"
17704     ],
17705     [
17706         "Ido",
17707         "Ido",
17708         "io"
17709     ],
17710     [
17711         "Icelandic",
17712         "íslenska",
17713         "is"
17714     ],
17715     [
17716         "Italian",
17717         "italiano",
17718         "it"
17719     ],
17720     [
17721         "Inuktitut",
17722         "ᐃᓄᒃᑎᑐᑦ/inuktitut",
17723         "iu"
17724     ],
17725     [
17726         "Japanese",
17727         "日本語",
17728         "ja"
17729     ],
17730     [
17731         "Jamaican Creole English",
17732         "Patois",
17733         "jam"
17734     ],
17735     [
17736         "Lojban",
17737         "la .lojban.",
17738         "jbo"
17739     ],
17740     [
17741         "Javanese",
17742         "Basa Jawa",
17743         "jv"
17744     ],
17745     [
17746         "Georgian",
17747         "ქართული",
17748         "ka"
17749     ],
17750     [
17751         "Kara-Kalpak",
17752         "Qaraqalpaqsha",
17753         "kaa"
17754     ],
17755     [
17756         "Kabyle",
17757         "Taqbaylit",
17758         "kab"
17759     ],
17760     [
17761         "Kabardian",
17762         "Адыгэбзэ",
17763         "kbd"
17764     ],
17765     [
17766         "Kongo",
17767         "Kongo",
17768         "kg"
17769     ],
17770     [
17771         "Kikuyu",
17772         "Gĩkũyũ",
17773         "ki"
17774     ],
17775     [
17776         "Kazakh",
17777         "қазақша",
17778         "kk"
17779     ],
17780     [
17781         "Kalaallisut",
17782         "kalaallisut",
17783         "kl"
17784     ],
17785     [
17786         "Khmer",
17787         "ភាសាខ្មែរ",
17788         "km"
17789     ],
17790     [
17791         "Kannada",
17792         "ಕನ್ನಡ",
17793         "kn"
17794     ],
17795     [
17796         "Korean",
17797         "한국어",
17798         "ko"
17799     ],
17800     [
17801         "Komi-Permyak",
17802         "Перем Коми",
17803         "koi"
17804     ],
17805     [
17806         "Karachay-Balkar",
17807         "къарачай-малкъар",
17808         "krc"
17809     ],
17810     [
17811         "Kashmiri",
17812         "कॉशुर / کٲشُر",
17813         "ks"
17814     ],
17815     [
17816         "Colognian",
17817         "Ripoarisch",
17818         "ksh"
17819     ],
17820     [
17821         "Kurdish",
17822         "Kurdî",
17823         "ku"
17824     ],
17825     [
17826         "Komi",
17827         "коми",
17828         "kv"
17829     ],
17830     [
17831         "Cornish",
17832         "kernowek",
17833         "kw"
17834     ],
17835     [
17836         "Kyrgyz",
17837         "Кыргызча",
17838         "ky"
17839     ],
17840     [
17841         "Latin",
17842         "Latina",
17843         "la"
17844     ],
17845     [
17846         "Ladino",
17847         "Ladino",
17848         "lad"
17849     ],
17850     [
17851         "Luxembourgish",
17852         "Lëtzebuergesch",
17853         "lb"
17854     ],
17855     [
17856         "лакку",
17857         "лакку",
17858         "lbe"
17859     ],
17860     [
17861         "Lezghian",
17862         "лезги",
17863         "lez"
17864     ],
17865     [
17866         "Ganda",
17867         "Luganda",
17868         "lg"
17869     ],
17870     [
17871         "Limburgish",
17872         "Limburgs",
17873         "li"
17874     ],
17875     [
17876         "Ligurian",
17877         "Ligure",
17878         "lij"
17879     ],
17880     [
17881         "Lombard",
17882         "lumbaart",
17883         "lmo"
17884     ],
17885     [
17886         "Lingala",
17887         "lingála",
17888         "ln"
17889     ],
17890     [
17891         "Lao",
17892         "ລາວ",
17893         "lo"
17894     ],
17895     [
17896         "Northern Luri",
17897         "لۊری شومالی",
17898         "lrc"
17899     ],
17900     [
17901         "Lithuanian",
17902         "lietuvių",
17903         "lt"
17904     ],
17905     [
17906         "Latgalian",
17907         "latgaļu",
17908         "ltg"
17909     ],
17910     [
17911         "Latvian",
17912         "latviešu",
17913         "lv"
17914     ],
17915     [
17916         "Maithili",
17917         "मैथिली",
17918         "mai"
17919     ],
17920     [
17921         "Basa Banyumasan",
17922         "Basa Banyumasan",
17923         "map-bms"
17924     ],
17925     [
17926         "Moksha",
17927         "мокшень",
17928         "mdf"
17929     ],
17930     [
17931         "Malagasy",
17932         "Malagasy",
17933         "mg"
17934     ],
17935     [
17936         "Eastern Mari",
17937         "олык марий",
17938         "mhr"
17939     ],
17940     [
17941         "Maori",
17942         "Māori",
17943         "mi"
17944     ],
17945     [
17946         "Minangkabau",
17947         "Baso Minangkabau",
17948         "min"
17949     ],
17950     [
17951         "Macedonian",
17952         "македонски",
17953         "mk"
17954     ],
17955     [
17956         "Malayalam",
17957         "മലയാളം",
17958         "ml"
17959     ],
17960     [
17961         "Mongolian",
17962         "монгол",
17963         "mn"
17964     ],
17965     [
17966         "Marathi",
17967         "मराठी",
17968         "mr"
17969     ],
17970     [
17971         "Western Mari",
17972         "кырык мары",
17973         "mrj"
17974     ],
17975     [
17976         "Malay",
17977         "Bahasa Melayu",
17978         "ms"
17979     ],
17980     [
17981         "Maltese",
17982         "Malti",
17983         "mt"
17984     ],
17985     [
17986         "Mirandese",
17987         "Mirandés",
17988         "mwl"
17989     ],
17990     [
17991         "Burmese",
17992         "မြန်မာဘာသာ",
17993         "my"
17994     ],
17995     [
17996         "Erzya",
17997         "эрзянь",
17998         "myv"
17999     ],
18000     [
18001         "Mazanderani",
18002         "مازِرونی",
18003         "mzn"
18004     ],
18005     [
18006         "Nauru",
18007         "Dorerin Naoero",
18008         "na"
18009     ],
18010     [
18011         "Nāhuatl",
18012         "Nāhuatl",
18013         "nah"
18014     ],
18015     [
18016         "Neapolitan",
18017         "Napulitano",
18018         "nap"
18019     ],
18020     [
18021         "Low German",
18022         "Plattdüütsch",
18023         "nds"
18024     ],
18025     [
18026         "Low Saxon",
18027         "Nedersaksies",
18028         "nds-nl"
18029     ],
18030     [
18031         "Nepali",
18032         "नेपाली",
18033         "ne"
18034     ],
18035     [
18036         "Newari",
18037         "नेपाल भाषा",
18038         "new"
18039     ],
18040     [
18041         "Dutch",
18042         "Nederlands",
18043         "nl"
18044     ],
18045     [
18046         "Norwegian Nynorsk",
18047         "norsk nynorsk",
18048         "nn"
18049     ],
18050     [
18051         "Norwegian",
18052         "norsk bokmål",
18053         "no"
18054     ],
18055     [
18056         "Novial",
18057         "Novial",
18058         "nov"
18059     ],
18060     [
18061         "Nouormand",
18062         "Nouormand",
18063         "nrm"
18064     ],
18065     [
18066         "Northern Sotho",
18067         "Sesotho sa Leboa",
18068         "nso"
18069     ],
18070     [
18071         "Navajo",
18072         "Diné bizaad",
18073         "nv"
18074     ],
18075     [
18076         "Nyanja",
18077         "Chi-Chewa",
18078         "ny"
18079     ],
18080     [
18081         "Occitan",
18082         "occitan",
18083         "oc"
18084     ],
18085     [
18086         "Livvi-Karelian",
18087         "Livvinkarjala",
18088         "olo"
18089     ],
18090     [
18091         "Oromo",
18092         "Oromoo",
18093         "om"
18094     ],
18095     [
18096         "Odia",
18097         "ଓଡ଼ିଆ",
18098         "or"
18099     ],
18100     [
18101         "Ossetic",
18102         "Ирон",
18103         "os"
18104     ],
18105     [
18106         "Punjabi",
18107         "ਪੰਜਾਬੀ",
18108         "pa"
18109     ],
18110     [
18111         "Pangasinan",
18112         "Pangasinan",
18113         "pag"
18114     ],
18115     [
18116         "Pampanga",
18117         "Kapampangan",
18118         "pam"
18119     ],
18120     [
18121         "Papiamento",
18122         "Papiamentu",
18123         "pap"
18124     ],
18125     [
18126         "Picard",
18127         "Picard",
18128         "pcd"
18129     ],
18130     [
18131         "Pennsylvania German",
18132         "Deitsch",
18133         "pdc"
18134     ],
18135     [
18136         "Palatine German",
18137         "Pälzisch",
18138         "pfl"
18139     ],
18140     [
18141         "Pali",
18142         "पालि",
18143         "pi"
18144     ],
18145     [
18146         "Norfuk / Pitkern",
18147         "Norfuk / Pitkern",
18148         "pih"
18149     ],
18150     [
18151         "Polish",
18152         "polski",
18153         "pl"
18154     ],
18155     [
18156         "Piedmontese",
18157         "Piemontèis",
18158         "pms"
18159     ],
18160     [
18161         "Western Punjabi",
18162         "پنجابی",
18163         "pnb"
18164     ],
18165     [
18166         "Pontic",
18167         "Ποντιακά",
18168         "pnt"
18169     ],
18170     [
18171         "Pashto",
18172         "پښتو",
18173         "ps"
18174     ],
18175     [
18176         "Portuguese",
18177         "português",
18178         "pt"
18179     ],
18180     [
18181         "Quechua",
18182         "Runa Simi",
18183         "qu"
18184     ],
18185     [
18186         "Romansh",
18187         "rumantsch",
18188         "rm"
18189     ],
18190     [
18191         "Romani",
18192         "Romani",
18193         "rmy"
18194     ],
18195     [
18196         "Rundi",
18197         "Kirundi",
18198         "rn"
18199     ],
18200     [
18201         "Romanian",
18202         "română",
18203         "ro"
18204     ],
18205     [
18206         "Aromanian",
18207         "armãneashti",
18208         "roa-rup"
18209     ],
18210     [
18211         "tarandíne",
18212         "tarandíne",
18213         "roa-tara"
18214     ],
18215     [
18216         "Russian",
18217         "русский",
18218         "ru"
18219     ],
18220     [
18221         "Rusyn",
18222         "русиньскый",
18223         "rue"
18224     ],
18225     [
18226         "Kinyarwanda",
18227         "Kinyarwanda",
18228         "rw"
18229     ],
18230     [
18231         "Sanskrit",
18232         "संस्कृतम्",
18233         "sa"
18234     ],
18235     [
18236         "Sakha",
18237         "саха тыла",
18238         "sah"
18239     ],
18240     [
18241         "Sardinian",
18242         "sardu",
18243         "sc"
18244     ],
18245     [
18246         "Sicilian",
18247         "sicilianu",
18248         "scn"
18249     ],
18250     [
18251         "Scots",
18252         "Scots",
18253         "sco"
18254     ],
18255     [
18256         "Sindhi",
18257         "سنڌي",
18258         "sd"
18259     ],
18260     [
18261         "Northern Sami",
18262         "sámegiella",
18263         "se"
18264     ],
18265     [
18266         "Sango",
18267         "Sängö",
18268         "sg"
18269     ],
18270     [
18271         "Serbo-Croatian",
18272         "srpskohrvatski / српскохрватски",
18273         "sh"
18274     ],
18275     [
18276         "Sinhala",
18277         "සිංහල",
18278         "si"
18279     ],
18280     [
18281         "Simple English",
18282         "Simple English",
18283         "simple"
18284     ],
18285     [
18286         "Slovak",
18287         "slovenčina",
18288         "sk"
18289     ],
18290     [
18291         "Slovenian",
18292         "slovenščina",
18293         "sl"
18294     ],
18295     [
18296         "Samoan",
18297         "Gagana Samoa",
18298         "sm"
18299     ],
18300     [
18301         "Shona",
18302         "chiShona",
18303         "sn"
18304     ],
18305     [
18306         "Somali",
18307         "Soomaaliga",
18308         "so"
18309     ],
18310     [
18311         "Albanian",
18312         "shqip",
18313         "sq"
18314     ],
18315     [
18316         "Serbian",
18317         "српски / srpski",
18318         "sr"
18319     ],
18320     [
18321         "Sranan Tongo",
18322         "Sranantongo",
18323         "srn"
18324     ],
18325     [
18326         "Swati",
18327         "SiSwati",
18328         "ss"
18329     ],
18330     [
18331         "Southern Sotho",
18332         "Sesotho",
18333         "st"
18334     ],
18335     [
18336         "Saterland Frisian",
18337         "Seeltersk",
18338         "stq"
18339     ],
18340     [
18341         "Sundanese",
18342         "Basa Sunda",
18343         "su"
18344     ],
18345     [
18346         "Swedish",
18347         "svenska",
18348         "sv"
18349     ],
18350     [
18351         "Swahili",
18352         "Kiswahili",
18353         "sw"
18354     ],
18355     [
18356         "Silesian",
18357         "ślůnski",
18358         "szl"
18359     ],
18360     [
18361         "Tamil",
18362         "தமிழ்",
18363         "ta"
18364     ],
18365     [
18366         "Tulu",
18367         "ತುಳು",
18368         "tcy"
18369     ],
18370     [
18371         "Telugu",
18372         "తెలుగు",
18373         "te"
18374     ],
18375     [
18376         "Tetum",
18377         "tetun",
18378         "tet"
18379     ],
18380     [
18381         "Tajik",
18382         "тоҷикӣ",
18383         "tg"
18384     ],
18385     [
18386         "Thai",
18387         "ไทย",
18388         "th"
18389     ],
18390     [
18391         "Tigrinya",
18392         "ትግርኛ",
18393         "ti"
18394     ],
18395     [
18396         "Turkmen",
18397         "Türkmençe",
18398         "tk"
18399     ],
18400     [
18401         "Tagalog",
18402         "Tagalog",
18403         "tl"
18404     ],
18405     [
18406         "Tswana",
18407         "Setswana",
18408         "tn"
18409     ],
18410     [
18411         "Tongan",
18412         "lea faka-Tonga",
18413         "to"
18414     ],
18415     [
18416         "Tok Pisin",
18417         "Tok Pisin",
18418         "tpi"
18419     ],
18420     [
18421         "Turkish",
18422         "Türkçe",
18423         "tr"
18424     ],
18425     [
18426         "Tsonga",
18427         "Xitsonga",
18428         "ts"
18429     ],
18430     [
18431         "Tatar",
18432         "татарча/tatarça",
18433         "tt"
18434     ],
18435     [
18436         "Tumbuka",
18437         "chiTumbuka",
18438         "tum"
18439     ],
18440     [
18441         "Twi",
18442         "Twi",
18443         "tw"
18444     ],
18445     [
18446         "Tahitian",
18447         "reo tahiti",
18448         "ty"
18449     ],
18450     [
18451         "Tuvinian",
18452         "тыва дыл",
18453         "tyv"
18454     ],
18455     [
18456         "Udmurt",
18457         "удмурт",
18458         "udm"
18459     ],
18460     [
18461         "Uyghur",
18462         "ئۇيغۇرچە / Uyghurche",
18463         "ug"
18464     ],
18465     [
18466         "Ukrainian",
18467         "українська",
18468         "uk"
18469     ],
18470     [
18471         "Urdu",
18472         "اردو",
18473         "ur"
18474     ],
18475     [
18476         "Uzbek",
18477         "oʻzbekcha/ўзбекча",
18478         "uz"
18479     ],
18480     [
18481         "Venda",
18482         "Tshivenda",
18483         "ve"
18484     ],
18485     [
18486         "Venetian",
18487         "vèneto",
18488         "vec"
18489     ],
18490     [
18491         "Veps",
18492         "vepsän kel’",
18493         "vep"
18494     ],
18495     [
18496         "Vietnamese",
18497         "Tiếng Việt",
18498         "vi"
18499     ],
18500     [
18501         "West Flemish",
18502         "West-Vlams",
18503         "vls"
18504     ],
18505     [
18506         "Volapük",
18507         "Volapük",
18508         "vo"
18509     ],
18510     [
18511         "Walloon",
18512         "walon",
18513         "wa"
18514     ],
18515     [
18516         "Waray",
18517         "Winaray",
18518         "war"
18519     ],
18520     [
18521         "Wolof",
18522         "Wolof",
18523         "wo"
18524     ],
18525     [
18526         "Wu Chinese",
18527         "吴语",
18528         "wuu"
18529     ],
18530     [
18531         "Kalmyk",
18532         "хальмг",
18533         "xal"
18534     ],
18535     [
18536         "Xhosa",
18537         "isiXhosa",
18538         "xh"
18539     ],
18540     [
18541         "Mingrelian",
18542         "მარგალური",
18543         "xmf"
18544     ],
18545     [
18546         "Yiddish",
18547         "ייִדיש",
18548         "yi"
18549     ],
18550     [
18551         "Yoruba",
18552         "Yorùbá",
18553         "yo"
18554     ],
18555     [
18556         "Zhuang",
18557         "Vahcuengh",
18558         "za"
18559     ],
18560     [
18561         "Zeelandic",
18562         "Zeêuws",
18563         "zea"
18564     ],
18565     [
18566         "Chinese",
18567         "中文",
18568         "zh"
18569     ],
18570     [
18571         "Classical Chinese",
18572         "文言",
18573         "zh-classical"
18574     ],
18575     [
18576         "Chinese (Min Nan)",
18577         "Bân-lâm-gú",
18578         "zh-min-nan"
18579     ],
18580     [
18581         "Cantonese",
18582         "粵語",
18583         "zh-yue"
18584     ],
18585     [
18586         "Zulu",
18587         "isiZulu",
18588         "zu"
18589     ]
18590 ];
18591
18592 var amenity = {"fuel":{"76":{"count":314},"Neste":{"count":189},"BP":{"count":2511},"Shell":{"count":8380},"Agip":{"count":2651},"Migrol":{"count":65},"Avia":{"count":897},"Texaco":{"count":680},"Total":{"count":2607},"Statoil":{"count":596},"Esso":{"count":3652},"Jet":{"count":441},"Avanti":{"count":90},"Sainsbury's":{"count":58},"OMV":{"count":701},"Aral":{"count":1339},"Tesco":{"count":197},"JET":{"count":180},"Morrisons":{"count":111},"United":{"count":91},"Canadian Tire":{"count":66},"Mobil":{"count":613},"Caltex":{"count":1001},"Sunoco":{"count":355},"Q8":{"count":1161},"ABC":{"count":79},"ARAL":{"count":375},"CEPSA":{"count":1018},"BFT":{"count":89},"Petron":{"count":878},"Intermarché":{"count":434},"Total Access":{"count":51},"Super U":{"count":124},"Auchan":{"count":53},"Elf":{"count":129},"Carrefour":{"count":205},"Station Service E. Leclerc":{"count":530},"Shell Express":{"count":131},"Hess":{"count":127},"Flying V":{"count":129},"bft":{"count":168},"Gulf":{"count":199},"PTT":{"count":191},"St1":{"count":100},"Teboil":{"count":115},"HEM":{"count":212},"GALP":{"count":626},"OK":{"count":163},"ÖMV":{"count":101},"Tinq":{"count":215},"OKQ8":{"count":186},"Repsol":{"count":424},"Westfalen":{"count":96},"Esso Express":{"count":98},"Raiffeisenbank":{"count":117},"Tamoil":{"count":866},"Engen":{"count":241},"Sasol":{"count":59},"Topaz":{"count":78},"LPG":{"count":174},"Coop":{"count":62},"Orlen":{"count":598},"Oilibya":{"count":68},"Tango":{"count":122},"Star":{"count":319},"Петрол":{"count":84},"Cepsa":{"count":96},"OIL!":{"count":63},"Ultramar":{"count":125},"Irving":{"count":87},"Lukoil":{"count":701},"Petro-Canada":{"count":489},"7-Eleven":{"count":488},"Agrola":{"count":69},"Husky":{"count":126},"Slovnaft":{"count":219},"Sheetz":{"count":134},"Mol":{"count":61},"Petronas":{"count":159},"Газпромнефть":{"count":748},"Лукойл":{"count":1477},"Elan":{"count":112},"Роснефть":{"count":638},"Turmöl":{"count":57},"Neste A24":{"count":55},"Marathon":{"count":189},"Valero":{"count":366},"Eni":{"count":236},"Chevron":{"count":954},"ТНК":{"count":520},"REPSOL":{"count":1603},"MOL":{"count":228},"Bliska":{"count":150},"Api":{"count":302},"Arco":{"count":179},"Pemex":{"count":423},"Exxon":{"count":506},"Coles Express":{"count":115},"Petrom":{"count":259},"PETRONOR":{"count":207},"Rompetrol":{"count":174},"Lotos":{"count":178},"ОМВ":{"count":60},"BR":{"count":129},"Copec":{"count":505},"Petrobras":{"count":270},"Liberty":{"count":55},"IP":{"count":871},"Erg":{"count":596},"Eneos":{"count":97},"Citgo":{"count":279},"Metano":{"count":208},"Сургутнефтегаз":{"count":61},"EKO":{"count":59},"Eko":{"count":58},"Indipend.":{"count":172},"IES":{"count":63},"TotalErg":{"count":89},"Cenex":{"count":115},"ПТК":{"count":82},"HP":{"count":79},"Phillips 66":{"count":216},"CARREFOUR":{"count":74},"ERG":{"count":76},"Speedway":{"count":148},"Benzina":{"count":96},"Татнефть":{"count":264},"Terpel":{"count":259},"WOG":{"count":189},"Seaoil":{"count":54},"АЗС":{"count":1077},"Kwik Trip":{"count":108},"Wawa":{"count":89},"Pertamina":{"count":186},"COSMO":{"count":64},"Z":{"count":76},"Indian Oil":{"count":183},"АГЗС":{"count":494},"INA":{"count":121},"JOMO":{"count":62},"Holiday":{"count":97},"YPF":{"count":70},"IDEMITSU":{"count":87},"ENEOS":{"count":736},"Bharat Petroleum":{"count":64},"CAMPSA":{"count":615},"Casey's General Store":{"count":190},"Башнефть":{"count":60},"Kangaroo":{"count":60},"コスモ石油 (COSMO)":{"count":136},"MEROIL":{"count":77},"1-2-3":{"count":71},"出光":{"count":228,"tags":{"name:en":"IDEMITSU"}},"НК Альянс":{"count":88},"Sinclair":{"count":100},"Conoco":{"count":189},"SPBU":{"count":54},"Макпетрол":{"count":109},"Circle K":{"count":166},"Posto Ipiranga":{"count":70},"Posto Shell":{"count":54},"Phoenix":{"count":144},"Ipiranga":{"count":119},"OKKO":{"count":85},"ОККО":{"count":119},"บางจาก":{"count":60},"QuikTrip":{"count":105},"Stewart's":{"count":63},"Posto BR":{"count":68},"ป ต ท":{"count":152},"ปตท":{"count":88},"ANP":{"count":80},"Kum & Go":{"count":80},"Petrolimex":{"count":55},"Sokimex":{"count":66},"Tela":{"count":154},"Posto":{"count":71},"H-E-B":{"count":182},"Укрнафта":{"count":58},"Татнефтепродукт":{"count":54},"Afriquia":{"count":88},"Murphy USA":{"count":67},"昭和シェル (Showa-shell)":{"count":94},"エネオス":{"count":53},"CNG":{"count":94}},"pub":{"Kings Arms":{"count":67},"The Ship":{"count":89},"The White Horse":{"count":204},"The White Hart":{"count":226},"Royal Oak":{"count":150},"The Red Lion":{"count":233},"The Kings Arms":{"count":58},"The Star":{"count":73},"The Anchor":{"count":64},"The Cross Keys":{"count":55},"The Wheatsheaf":{"count":117},"The Crown Inn":{"count":67},"The Kings Head":{"count":53},"The Castle":{"count":62},"The Railway":{"count":102},"The White Lion":{"count":118},"The Bell":{"count":121},"The Bull":{"count":68},"The Plough":{"count":179},"The George":{"count":110},"The Royal Oak":{"count":209},"The Fox":{"count":74},"Prince of Wales":{"count":77},"The Rising Sun":{"count":71},"The Prince of Wales":{"count":51},"The Crown":{"count":244},"The Chequers":{"count":66},"The Swan":{"count":152},"Rose and Crown":{"count":79},"The Victoria":{"count":67},"New Inn":{"count":90},"Royal Hotel":{"count":57},"Red Lion":{"count":207},"Cross Keys":{"count":61},"The Greyhound":{"count":96},"The Black Horse":{"count":94},"The New Inn":{"count":105},"Kings Head":{"count":59},"The Albion":{"count":51},"The Angel":{"count":52},"The Queens Head":{"count":52},"The Ship Inn":{"count":83},"Rose & Crown":{"count":51},"Queens Head":{"count":52},"Irish Pub":{"count":76}},"fast_food":{"Quick":{"count":484},"McDonald's":{"count":12376,"tags":{"cuisine":"burger"}},"Subway":{"count":5576,"tags":{"cuisine":"sandwich"}},"Burger King":{"count":3734,"tags":{"cuisine":"burger"}},"Ali Baba":{"count":61},"Hungry Jacks":{"count":173,"tags":{"cuisine":"burger"}},"Red Rooster":{"count":148},"KFC":{"count":3198,"tags":{"cuisine":"chicken"}},"Domino's Pizza":{"count":985,"tags":{"cuisine":"pizza"}},"Chowking":{"count":142},"Jollibee":{"count":396},"Hesburger":{"count":102},"肯德基":{"count":86},"Wendy's":{"count":1621,"tags":{"cuisine":"burger"}},"Tim Hortons":{"count":323},"Steers":{"count":151},"Hardee's":{"count":268,"tags":{"cuisine":"burger"}},"Arby's":{"count":782},"A&W":{"count":283},"Dairy Queen":{"count":791},"Hallo Pizza":{"count":76},"Fish & Chips":{"count":93},"Harvey's":{"count":90},"麥當勞":{"count":65},"Pizza Pizza":{"count":215},"Kotipizza":{"count":74},"Jack in the Box":{"count":546,"tags":{"cuisine":"burger"}},"Istanbul":{"count":56},"Kochlöffel":{"count":68},"Döner":{"count":228},"Telepizza":{"count":201},"Sibylla":{"count":61},"Carl's Jr.":{"count":298,"tags":{"cuisine":"burger"}},"Quiznos":{"count":266,"tags":{"cuisine":"sandwich"}},"Wimpy":{"count":141},"Sonic":{"count":566,"tags":{"cuisine":"burger"}},"Taco Bell":{"count":1423,"tags":{"cuisine":"mexican"}},"Pizza Nova":{"count":63},"Papa John's":{"count":304,"tags":{"cuisine":"pizza"}},"Nordsee":{"count":159},"Mr. Sub":{"count":103},"Макдоналдс":{"count":324,"tags":{"name:en":"McDonald's"}},"Asia Imbiss":{"count":111},"Chipotle":{"count":290,"tags":{"cuisine":"mexican"}},"マクドナルド":{"count":692,"tags":{"name:en":"McDonald's","cuisine":"burger"}},"In-N-Out Burger":{"count":65},"Jimmy John's":{"count":141},"Jamba Juice":{"count":68},"Робин Сдобин":{"count":82},"Baskin Robbins":{"count":74},"ケンタッキーフライドチキン":{"count":164,"tags":{"name:en":"KFC","cuisine":"chicken"}},"吉野家":{"count":191},"Taco Time":{"count":88},"松屋":{"count":281,"tags":{"name:en":"Matsuya"}},"Little Caesars":{"count":81},"El Pollo Loco":{"count":63},"Del Taco":{"count":141},"White Castle":{"count":80},"Boston Market":{"count":66},"Chick-fil-A":{"count":257,"tags":{"cuisine":"chicken"}},"Panda Express":{"count":238,"tags":{"cuisine":"chinese"}},"Whataburger":{"count":364},"Taco John's":{"count":78},"Теремок":{"count":68},"Culver's":{"count":425},"Five Guys":{"count":141},"Church's Chicken":{"count":95},"Popeye's":{"count":167,"tags":{"cuisine":"chicken"}},"Long John Silver's":{"count":93},"Pollo Campero":{"count":62},"Zaxby's":{"count":51},"すき家":{"count":276,"tags":{"name:en":"SUKIYA"}},"モスバーガー":{"count":257,"tags":{"name:en":"MOS BURGER"}},"Русский Аппетит":{"count":69},"なか卯":{"count":63}},"restaurant":{"Pizza Hut":{"count":1180,"tags":{"cuisine":"pizza"}},"Little Chef":{"count":64},"Adler":{"count":158},"Zur Krone":{"count":90},"Deutsches Haus":{"count":90},"Krone":{"count":171},"Akropolis":{"count":152},"Schützenhaus":{"count":124},"Kreuz":{"count":74},"Waldschänke":{"count":55},"La Piazza":{"count":69},"Lamm":{"count":66},"Zur Sonne":{"count":73},"Zur Linde":{"count":204},"Poseidon":{"count":110},"Shanghai":{"count":82},"Red Lobster":{"count":235},"Zum Löwen":{"count":84},"Swiss Chalet":{"count":107},"Olympia":{"count":74},"Wagamama":{"count":64},"Frankie & Benny's":{"count":66},"Hooters":{"count":103},"Sternen":{"count":78},"Hirschen":{"count":79},"Denny's":{"count":450},"Athen":{"count":68},"Sonne":{"count":126},"Hirsch":{"count":79},"Ratskeller":{"count":150},"La Cantina":{"count":56},"Gasthaus Krone":{"count":56},"El Greco":{"count":86},"Gasthof zur Post":{"count":79},"Nando's":{"count":246},"Löwen":{"count":112},"La Pataterie":{"count":51},"Bella Napoli":{"count":53},"Pizza Express":{"count":262},"Mandarin":{"count":65},"Hong Kong":{"count":83},"Zizzi":{"count":68},"Cracker Barrel":{"count":183},"Rhodos":{"count":81},"Lindenhof":{"count":79},"Milano":{"count":54},"Dolce Vita":{"count":77},"Kirchenwirt":{"count":81},"Kantine":{"count":52},"Ochsen":{"count":95},"Spur":{"count":62},"Mykonos":{"count":59},"Lotus":{"count":66},"Applebee's":{"count":531},"Flunch":{"count":72},"Zur Post":{"count":116},"China Town":{"count":76},"La Dolce Vita":{"count":73},"Waffle House":{"count":207},"Delphi":{"count":88},"Linde":{"count":103},"Outback Steakhouse":{"count":218},"Dionysos":{"count":69},"Kelsey's":{"count":57},"Boston Pizza":{"count":165},"Bella Italia":{"count":132},"Sizzler":{"count":53},"Grüner Baum":{"count":116},"Taj Mahal":{"count":104},"Rössli":{"count":68},"Wimpy":{"count":51},"Traube":{"count":65},"Adria":{"count":52},"Red Robin":{"count":185},"Roma":{"count":61},"San Marco":{"count":67},"Hellas":{"count":55},"La Perla":{"count":67},"Vips":{"count":53},"Panera Bread":{"count":218},"Da Vinci":{"count":54},"Hippopotamus":{"count":96},"Prezzo":{"count":75},"Courtepaille":{"count":106},"Hard Rock Cafe":{"count":70},"Panorama":{"count":61},"デニーズ":{"count":82},"Sportheim":{"count":65},"餃子の王将":{"count":57},"Bären":{"count":60},"Alte Post":{"count":60},"Pizzeria Roma":{"count":51},"China Garden":{"count":66},"Vapiano":{"count":82},"Mamma Mia":{"count":64},"Schwarzer Adler":{"count":57},"IHOP":{"count":317},"Chili's":{"count":328},"Asia":{"count":51},"Olive Garden":{"count":279},"TGI Friday's":{"count":159},"Friendly's":{"count":78},"Buffalo Grill":{"count":202},"Texas Roadhouse":{"count":110},"ガスト":{"count":230,"tags":{"name:en":"Gusto"}},"Sakura":{"count":75},"Mensa":{"count":99},"The Keg":{"count":53},"サイゼリヤ":{"count":93},"La Strada":{"count":52},"Village Inn":{"count":92},"Buffalo Wild Wings":{"count":176},"Peking":{"count":59},"Boston Market":{"count":61},"Round Table Pizza":{"count":53},"Jimmy John's":{"count":69},"California Pizza Kitchen":{"count":61},"Якитория":{"count":77},"Golden Corral":{"count":101},"Perkins":{"count":105},"Ruby Tuesday":{"count":162},"Shari's":{"count":65},"Bob Evans":{"count":129},"바다횟집 (Bada Fish Restaurant)":{"count":55},"Mang Inasal":{"count":84},"Евразия":{"count":102},"ジョナサン":{"count":59},"Longhorn Steakhouse":{"count":66}},"bank":{"Chase":{"count":721},"Commonwealth Bank":{"count":232},"Citibank":{"count":277},"HSBC":{"count":1102},"Barclays":{"count":965},"Westpac":{"count":208},"NAB":{"count":131},"ANZ":{"count":218},"Lloyds Bank":{"count":547},"Landbank":{"count":81},"Sparkasse":{"count":4555},"UCPB":{"count":92},"PNB":{"count":244},"Metrobank":{"count":269},"BDO":{"count":290},"Volksbank":{"count":2591},"BPI":{"count":415},"Postbank":{"count":443},"NatWest":{"count":628},"Raiffeisenbank":{"count":2119},"Yorkshire Bank":{"count":63},"ABSA":{"count":95},"Standard Bank":{"count":109},"FNB":{"count":97},"Deutsche Bank":{"count":855},"SEB":{"count":133},"Commerzbank":{"count":806},"Targobank":{"count":166},"ABN AMRO":{"count":130},"Handelsbanken":{"count":184},"Swedbank":{"count":223},"Kreissparkasse":{"count":600},"UniCredit Bank":{"count":408},"Monte dei Paschi di Siena":{"count":132},"Caja Rural":{"count":99},"Dresdner Bank":{"count":66},"Sparda-Bank":{"count":320},"VÚB":{"count":107},"Slovenská sporiteľňa":{"count":134},"Bank of Montreal":{"count":118},"KBC":{"count":203},"Royal Bank of Scotland":{"count":111},"TSB":{"count":80},"US Bank":{"count":256},"HypoVereinsbank":{"count":561},"Bank Austria":{"count":176},"ING":{"count":496},"Erste Bank":{"count":180},"CIBC":{"count":326},"Scotiabank":{"count":413},"Caisse d'Épargne":{"count":882},"Santander":{"count":1323},"Bank of Scotland":{"count":89},"TD Canada Trust":{"count":450},"BMO":{"count":169},"Danske Bank":{"count":131},"OTP":{"count":192},"Crédit Agricole":{"count":1239},"LCL":{"count":553},"VR-Bank":{"count":430},"ČSOB":{"count":160},"Česká spořitelna":{"count":212},"BNP":{"count":112},"Royal Bank":{"count":65},"Nationwide":{"count":209},"Halifax":{"count":225},"BAWAG PSK":{"count":102},"National Bank":{"count":84},"Nedbank":{"count":80},"First National Bank":{"count":85},"Nordea":{"count":319},"Rabobank":{"count":609},"Sparkasse KölnBonn":{"count":69},"Tatra banka":{"count":67},"Berliner Sparkasse":{"count":62},"Berliner Volksbank":{"count":77},"Wells Fargo":{"count":874},"Credit Suisse":{"count":71},"Société Générale":{"count":634},"Osuuspankki":{"count":75},"Sparkasse Aachen":{"count":56},"Hamburger Sparkasse":{"count":156},"Cassa di Risparmio del Veneto":{"count":68},"BNP Paribas":{"count":617},"Banque Populaire":{"count":433},"BNP Paribas Fortis":{"count":209},"Banco Popular":{"count":291},"Bancaja":{"count":55},"Banesto":{"count":208},"La Caixa":{"count":583},"Santander Consumer Bank":{"count":88},"BRD":{"count":191},"BCR":{"count":143},"Banca Transilvania":{"count":141},"BW-Bank":{"count":97},"Komerční banka":{"count":132},"Banco Pastor":{"count":64},"Stadtsparkasse":{"count":86},"Ulster Bank":{"count":86},"Sberbank":{"count":58},"CIC":{"count":427},"Bancpost":{"count":56},"Caja Madrid":{"count":115},"Maybank":{"count":94},"中国银行":{"count":85},"Unicredit Banca":{"count":243},"Crédit Mutuel":{"count":690},"BBVA":{"count":647},"Intesa San Paolo":{"count":69},"TD Bank":{"count":206},"Belfius":{"count":231},"Bank of America":{"count":924},"RBC":{"count":230},"Alpha Bank":{"count":123},"Сбербанк":{"count":4794},"Россельхозбанк":{"count":201},"Crédit du Nord":{"count":96},"BancoEstado":{"count":80},"Millennium Bank":{"count":414},"State Bank of India":{"count":151},"Беларусбанк":{"count":242},"ING Bank Śląski":{"count":67},"Caixa Geral de Depósitos":{"count":129},"Kreissparkasse Köln":{"count":65},"Banco BCI":{"count":51},"Banco de Chile":{"count":98},"ВТБ24":{"count":326},"UBS":{"count":134},"PKO BP":{"count":265},"Chinabank":{"count":55},"PSBank":{"count":59},"Union Bank":{"count":124},"China Bank":{"count":66},"RCBC":{"count":122},"Unicaja":{"count":83},"BBK":{"count":79},"Ibercaja":{"count":69},"RBS":{"count":143},"Commercial Bank of Ceylon PLC":{"count":79},"Bank of Ireland":{"count":109},"BNL":{"count":87},"Banco Santander":{"count":138},"Banco Itaú":{"count":111},"AIB":{"count":72},"BZ WBK":{"count":77},"Banco do Brasil":{"count":557},"Caixa Econômica Federal":{"count":184},"Fifth Third Bank":{"count":84},"Banca Popolare di Vicenza":{"count":81},"Wachovia":{"count":58},"OLB":{"count":53},"みずほ銀行":{"count":78},"BES":{"count":72},"ICICI Bank":{"count":91},"HDFC Bank":{"count":91},"La Banque Postale":{"count":67},"Pekao SA":{"count":56},"Oberbank":{"count":90},"Bradesco":{"count":295},"Oldenburgische Landesbank":{"count":56},"Bendigo Bank":{"count":93},"Argenta":{"count":86},"AXA":{"count":68},"Axis Bank":{"count":61},"Banco Nación":{"count":67},"GE Money Bank":{"count":72},"Альфа-Банк":{"count":185},"Белагропромбанк":{"count":70},"Caja Círculo":{"count":65},"Banco Galicia":{"count":51},"Eurobank":{"count":97},"Banca Intesa":{"count":62},"Canara Bank":{"count":92},"Cajamar":{"count":77},"Banamex":{"count":149},"Crédit Mutuel de Bretagne":{"count":335},"Davivienda":{"count":83},"Bank Spółdzielczy":{"count":159},"Credit Agricole":{"count":157},"Bankinter":{"count":59},"Banque Nationale":{"count":63},"Bank of the West":{"count":96},"Key Bank":{"count":155},"Western Union":{"count":88},"Citizens Bank":{"count":115},"ПриватБанк":{"count":513},"Security Bank":{"count":78},"Millenium":{"count":60},"Bankia":{"count":149},"三菱東京UFJ銀行":{"count":159},"Caixa":{"count":117},"Banco de Costa Rica":{"count":63},"SunTrust Bank":{"count":73},"Itaú":{"count":338},"PBZ":{"count":52},"中国工商银行":{"count":51},"Bancolombia":{"count":89},"Райффайзен Банк Аваль":{"count":64},"Bancomer":{"count":115},"Banorte":{"count":80},"Alior Bank":{"count":81},"BOC":{"count":51},"Банк Москвы":{"count":118},"ВТБ":{"count":59},"Getin Bank":{"count":55},"Caja Duero":{"count":57},"Regions Bank":{"count":62},"Росбанк":{"count":177},"Banco Estado":{"count":72},"BCI":{"count":68},"SunTrust":{"count":68},"PNC Bank":{"count":254},"신한은행":{"count":217,"tags":{"name:en":"Sinhan Bank"}},"우리은행":{"count":291,"tags":{"name:en":"Uri Bank"}},"국민은행":{"count":165,"tags":{"name:en":"Gungmin Bank"}},"중소기업은행":{"count":52,"tags":{"name:en":"Industrial Bank of Korea"}},"광주은행":{"count":51,"tags":{"name:en":"Gwangju Bank"}},"Газпромбанк":{"count":100},"M&T Bank":{"count":92},"Caja de Burgos":{"count":51},"Santander Totta":{"count":69},"УкрСиббанк":{"count":192},"Ощадбанк":{"count":364},"Уралсиб":{"count":85},"りそな銀行":{"count":225,"tags":{"name:en":"Mizuho Bank"}},"Ecobank":{"count":66},"Cajero Automatico Bancared":{"count":145},"Промсвязьбанк":{"count":93},"三井住友銀行":{"count":129},"Banco Provincia":{"count":67},"BB&T":{"count":147},"Возрождение":{"count":59},"Capital One":{"count":59},"横浜銀行":{"count":51},"Bank Mandiri":{"count":62},"Banco de la Nación":{"count":92},"Banco G&T Continental":{"count":62},"Peoples Bank":{"count":60},"工商银行":{"count":51},"Совкомбанк":{"count":55},"Provincial":{"count":56},"Banco de Desarrollo Banrural":{"count":73},"Banco Bradesco":{"count":65},"Bicentenario":{"count":182},"ლიბერთი ბანკი":{"count":54,"tags":{"name:en":"Liberty Bank"}},"Banesco":{"count":108},"Mercantil":{"count":75},"Bank BRI":{"count":53},"Del Tesoro":{"count":91},"하나은행":{"count":77},"CityCommerce Bank":{"count":71},"De Venezuela":{"count":117}},"car_rental":{"Europcar":{"count":291},"Budget":{"count":92},"Sixt":{"count":161},"Avis":{"count":282},"Hertz":{"count":293},"Enterprise":{"count":199},"stadtmobil CarSharing-Station":{"count":148}},"pharmacy":{"Rowlands Pharmacy":{"count":71},"Boots":{"count":840},"Marien-Apotheke":{"count":314},"Mercury Drug":{"count":426},"Löwen-Apotheke":{"count":356},"Superdrug":{"count":117},"Sonnen-Apotheke":{"count":311},"Rathaus-Apotheke":{"count":132},"Engel-Apotheke":{"count":123},"Hirsch-Apotheke":{"count":83},"Stern-Apotheke":{"count":67},"Lloyds Pharmacy":{"count":295},"Rosen-Apotheke":{"count":208},"Stadt-Apotheke":{"count":302},"Markt-Apotheke":{"count":164},"Аптека":{"count":1989},"Pharmasave":{"count":64},"Brunnen-Apotheke":{"count":53},"Shoppers Drug Mart":{"count":430},"Apotheke am Markt":{"count":60},"Alte Apotheke":{"count":88},"Neue Apotheke":{"count":109},"Gintarinė vaistinė":{"count":101},"Rats-Apotheke":{"count":84},"Adler Apotheke":{"count":313},"Pharmacie Centrale":{"count":64},"Walgreens":{"count":1619},"Rite Aid":{"count":745},"Apotheke":{"count":165},"Linden-Apotheke":{"count":211},"Bahnhof-Apotheke":{"count":66},"Burg-Apotheke":{"count":55},"Jean Coutu":{"count":62},"Pharmaprix":{"count":60},"Farmacias Ahumada":{"count":104},"Farmacia Comunale":{"count":113},"Farmacias Cruz Verde":{"count":86},"Cruz Verde":{"count":99},"Hubertus Apotheke":{"count":52},"CVS":{"count":1560},"Farmacias SalcoBrand":{"count":133},"Фармация":{"count":120},"Bären-Apotheke":{"count":74},"Clicks":{"count":113},"セイジョー":{"count":53},"マツモトキヨシ":{"count":115},"Dr. Max":{"count":51},"Вита":{"count":106},"Радуга":{"count":70},"サンドラッグ":{"count":61},"Apteka":{"count":366},"Первая помощь":{"count":74},"Ригла":{"count":113},"Имплозия":{"count":63},"Kinney Drugs":{"count":68},"Классика":{"count":67},"Ljekarna":{"count":53},"SalcoBrand":{"count":88},"Аптека 36,6":{"count":224},"Фармакор":{"count":75},"スギ薬局":{"count":84},"Аптечный пункт":{"count":148},"Невис":{"count":60},"トモズ (Tomod's)":{"count":83},"Eurovaistinė":{"count":65},"Farmacity":{"count":68},"аптека":{"count":96},"The Generics Pharmacy":{"count":95},"Farmatodo":{"count":123},"Duane Reade":{"count":61},"H-E-B":{"count":262},"Фармленд":{"count":82},"ドラッグてらしま (Drug Terashima)":{"count":96},"Арніка":{"count":125},"ავერსი (Aversi)":{"count":62},"Farmahorro":{"count":58}},"cafe":{"Starbucks":{"count":4238,"tags":{"cuisine":"coffee_shop"}},"Cafeteria":{"count":115},"Costa":{"count":618},"Caffè Nero":{"count":169},"Кафе":{"count":226},"Café Central":{"count":61},"Second Cup":{"count":193},"Dunkin Donuts":{"count":428,"tags":{"cuisine":"donut"}},"Espresso House":{"count":53},"Segafredo":{"count":69},"Coffee Time":{"count":94},"Cafe Coffee Day":{"count":120},"Eiscafe Venezia":{"count":180},"スターバックス":{"count":251,"tags":{"name:en":"Starbucks"}},"Шоколадница":{"count":145},"Pret A Manger":{"count":119},"Столовая":{"count":391},"Jamba Juice":{"count":53},"ドトール":{"count":164,"tags":{"name:en":"DOUTOR"}},"Tchibo":{"count":100},"Кофе Хауз":{"count":104},"Caribou Coffee":{"count":100},"Уют":{"count":51},"Шашлычная":{"count":58},"คาเฟ่ อเมซอน":{"count":62},"Traveler's Coffee":{"count":60},"カフェ・ド・クリエ":{"count":67,"tags":{"name:en":"Cafe de CRIE"}},"Cafe Amazon":{"count":65}}};
18593 var shop = {"supermarket":{"Budgens":{"count":88},"Morrisons":{"count":411},"Interspar":{"count":142},"Merkur":{"count":107},"Sainsbury's":{"count":547},"Lidl":{"count":7130},"Edeka":{"count":2293},"Coles":{"count":400},"Iceland":{"count":315},"Coop":{"count":2100},"Tesco":{"count":1297},"Woolworths":{"count":541},"Zielpunkt":{"count":239},"Nahkauf":{"count":170},"Billa":{"count":1432},"Kaufland":{"count":1004},"Plus":{"count":120},"ALDI":{"count":5172},"Checkers":{"count":128},"Tesco Metro":{"count":137},"NP":{"count":153},"Penny":{"count":1759},"Norma":{"count":1068},"Asda":{"count":225},"Netto":{"count":4379},"Rewe":{"count":2645},"Aldi Süd":{"count":594},"Real":{"count":246},"Tesco Express":{"count":406},"King Soopers":{"count":72},"Kiwi":{"count":167},"Pick n Pay":{"count":241},"ICA":{"count":192},"Tengelmann":{"count":188},"Carrefour":{"count":1640},"Waitrose":{"count":258},"Spar":{"count":2386},"Hofer":{"count":442},"M-Preis":{"count":76},"tegut":{"count":210},"Sainsbury's Local":{"count":118},"E-Center":{"count":66},"Aldi Nord":{"count":210},"nahkauf":{"count":84},"Meijer":{"count":76},"Safeway":{"count":410},"Costco":{"count":152},"Albert":{"count":185},"Jumbo":{"count":194},"Shoprite":{"count":244},"MPreis":{"count":54},"Penny Market":{"count":429},"Tesco Extra":{"count":123},"Albert Heijn":{"count":476},"IGA":{"count":363},"Super U":{"count":488},"Metro":{"count":260},"Neukauf":{"count":77},"Migros":{"count":459},"Marktkauf":{"count":121},"Delikatesy Centrum":{"count":59},"C1000":{"count":307},"Hoogvliet":{"count":53},"Food Basics":{"count":75},"Casino":{"count":264},"Penny Markt":{"count":466},"Giant":{"count":191},"COOP Jednota":{"count":73},"Rema 1000":{"count":368},"Kaufpark":{"count":96},"ALDI SÜD":{"count":113},"Simply Market":{"count":330},"Konzum":{"count":230},"Carrefour Express":{"count":353},"Eurospar":{"count":270},"Mercator":{"count":125},"Famila":{"count":130},"Hemköp":{"count":82},"real,-":{"count":81},"Markant":{"count":88},"Volg":{"count":135},"Leader Price":{"count":267},"Treff 3000":{"count":94},"SuperBrugsen":{"count":67},"Kaiser's":{"count":256},"K+K":{"count":106},"Unimarkt":{"count":86},"Carrefour City":{"count":126},"Sobeys":{"count":122},"S-Market":{"count":109},"Combi":{"count":55},"Denner":{"count":276},"Konsum":{"count":133},"Franprix":{"count":312},"Monoprix":{"count":198},"Diska":{"count":69},"PENNY":{"count":79},"Dia":{"count":835},"Giant Eagle":{"count":85},"NORMA":{"count":115},"AD Delhaize":{"count":63},"Auchan":{"count":152},"Mercadona":{"count":769},"Consum":{"count":130},"Carrefour Market":{"count":80},"Whole Foods":{"count":210,"tags":{"shop":"supermarket"}},"Pam":{"count":56},"sky":{"count":105},"Despar":{"count":146},"Eroski":{"count":208},"Costcutter":{"count":63},"Maxi":{"count":108},"Colruyt":{"count":180},"The Co-operative":{"count":64},"Intermarché":{"count":1210},"Delhaize":{"count":207},"CBA":{"count":176},"Shopi":{"count":53},"Walmart":{"count":644},"Kroger":{"count":317},"Albertsons":{"count":242},"Trader Joe's":{"count":235},"Feneberg":{"count":58},"denn's Biomarkt":{"count":52},"dm":{"count":114},"Kvickly":{"count":55},"Makro":{"count":140},"Dico":{"count":53},"Nah & Frisch":{"count":73},"Champion":{"count":59},"ICA Supermarket":{"count":51},"Fakta":{"count":235},"Магнит":{"count":1760},"Caprabo":{"count":103},"Famiglia Cooperativa":{"count":64},"Народная 7Я семьЯ":{"count":154},"Esselunga":{"count":85},"Maxima":{"count":102},"Petit Casino":{"count":111},"Wasgau":{"count":60},"Pingo Doce":{"count":253},"Match":{"count":140},"Profi":{"count":60},"Lider":{"count":65},"Unimarc":{"count":177},"The Co-operative Food":{"count":190},"Santa Isabel":{"count":128},"Седьмой континент":{"count":79},"HIT":{"count":59},"Rimi":{"count":106},"Conad":{"count":304},"Фуршет":{"count":76},"Willys":{"count":56},"Farmfoods":{"count":64},"U Express":{"count":51},"Фора":{"count":52},"Dunnes Stores":{"count":73},"Сільпо":{"count":125},"マルエツ":{"count":59},"Piggly Wiggly":{"count":57},"Crai":{"count":54},"El Árbol":{"count":73},"Centre Commercial E. Leclerc":{"count":549},"Foodland":{"count":100},"Super Brugsen":{"count":67},"Дикси":{"count":683},"Пятёрочка":{"count":1344},"Publix":{"count":339},"Føtex":{"count":66},"coop":{"count":73},"Fressnapf":{"count":69},"Coop Konsum":{"count":79},"Carrefour Contact":{"count":83},"No Frills":{"count":105},"Plodine":{"count":52},"ADEG":{"count":68},"Minipreço":{"count":111},"Biedronka":{"count":1335},"Eurospin":{"count":155},"Семья":{"count":62},"Gadis":{"count":53},"Евроопт":{"count":68},"Centra":{"count":51},"Квартал":{"count":82},"New World":{"count":69},"Countdown":{"count":95},"Reliance Fresh":{"count":61},"Stokrotka":{"count":98},"Coop Jednota":{"count":74},"Fred Meyer":{"count":64},"Irma":{"count":58},"Continente":{"count":75},"Price Chopper":{"count":99},"Game":{"count":52},"Soriana":{"count":93},"Alimerka":{"count":64},"Piotr i Paweł":{"count":53},"Перекресток":{"count":312},"Maxima X":{"count":117},"Карусель":{"count":55},"ALDI Nord":{"count":51},"Condis":{"count":67},"Sam's Club":{"count":138},"Копейка":{"count":87},"Géant Casino":{"count":54},"ASDA":{"count":180},"Intermarche":{"count":115},"Stop & Shop":{"count":66},"Food Lion":{"count":216},"Harris Teeter":{"count":92},"Foodworks":{"count":62},"Polo Market":{"count":86},"Лента":{"count":51},"西友 (SEIYU)":{"count":58},"H-E-B":{"count":293},"Атак":{"count":53},"Полушка":{"count":139},"Extra":{"count":82},"Lewiatan":{"count":94},"Sigma":{"count":51},"АТБ":{"count":322},"Społem":{"count":55},"Bodega Aurrera":{"count":82},"Tesco Lotus":{"count":77},"Мария-Ра":{"count":108},"Магнолия":{"count":72},"Магазин":{"count":120},"Монетка":{"count":174},"Hy-Vee":{"count":75},"Walmart Supercenter":{"count":133},"Hannaford":{"count":57},"Wegmans":{"count":83},"業務スーパー":{"count":61},"Norfa XL":{"count":55},"ヨークマート (YorkMart)":{"count":64},"Leclerc Drive":{"count":76}},"electronics":{"Media Markt":{"count":285},"Maplin":{"count":65},"Best Buy":{"count":345},"Future Shop":{"count":73},"Saturn":{"count":134},"Currys":{"count":80},"Radio Shack":{"count":269},"Euronics":{"count":115},"Expert":{"count":123},"Эльдорадо":{"count":184},"Darty":{"count":74},"М.Видео":{"count":89},"ヤマダ電機":{"count":51}},"convenience":{"Shell":{"count":255},"Spar":{"count":1119},"McColl's":{"count":100},"Tesco Express":{"count":426},"Sainsbury's Local":{"count":104},"Aral":{"count":56},"One Stop":{"count":146},"The Co-operative Food":{"count":115},"Londis":{"count":352},"7-Eleven":{"count":4440},"CBA":{"count":135},"Coop":{"count":678},"Sale":{"count":80},"Statoil":{"count":69},"Sheetz":{"count":54},"Konzum":{"count":173},"Siwa":{"count":216},"Mercator":{"count":57},"Esso":{"count":67},"COOP Jednota":{"count":181},"Mac's":{"count":152},"Alepa":{"count":62},"Hasty Market":{"count":54},"K-Market":{"count":54},"Costcutter":{"count":292},"Valintatalo":{"count":62},"Casino":{"count":90},"Franprix":{"count":61},"Circle K":{"count":289},"セブンイレブン":{"count":3011,"tags":{"name:en":"7-Eleven"}},"ローソン":{"count":1596,"tags":{"name:en":"LAWSON"}},"BP":{"count":163},"Tesco":{"count":55},"Petit Casino":{"count":233},"Volg":{"count":116},"Mace":{"count":115},"Mini Market":{"count":272},"Nisa Local":{"count":77},"Dorfladen":{"count":75},"Продукты":{"count":4285},"Mini Stop":{"count":228},"LAWSON":{"count":419},"デイリーヤマザキ":{"count":141},"Biedronka":{"count":83},"Надежда":{"count":56},"Mobil":{"count":66},"Nisa":{"count":51},"Premier":{"count":129},"ABC":{"count":152},"ミニストップ":{"count":316,"tags":{"name:en":"MINISTOP"}},"サンクス":{"count":560,"tags":{"name:en":"sunkus"}},"スリーエフ":{"count":88},"8 à Huit":{"count":61},"Tchibo":{"count":56},"Żabka":{"count":546},"Almacen":{"count":229},"Vival":{"count":194},"FamilyMart":{"count":529},"ファミリーマート":{"count":1608,"tags":{"name:en":"FamilyMart"}},"Carrefour City":{"count":57},"Sunkus":{"count":62},"Casey's General Store":{"count":95},"セブンイレブン(Seven-Eleven)":{"count":65},"Jednota":{"count":58},"Магазин":{"count":915},"Гастроном":{"count":152},"Centra":{"count":111},"Магнит":{"count":701},"サークルK":{"count":538,"tags":{"name:en":"Circle K"}},"Wawa":{"count":135},"Proxi":{"count":123},"Универсам":{"count":78},"Перекресток":{"count":51},"Groszek":{"count":65},"Select":{"count":62},"Večerka":{"count":51},"Potraviny":{"count":249},"Смак":{"count":78},"Эконом":{"count":55},"Березка":{"count":77},"Społem":{"count":93},"Carrefour Express":{"count":84},"Cumberland Farms":{"count":63},"Chevron":{"count":59},"Coop Jednota":{"count":66},"Tesco Lotus Express":{"count":67},"Kiosk":{"count":55},"Sklep spożywczy":{"count":130},"24 часа":{"count":58},"Минимаркет":{"count":102},"Oxxo":{"count":669},"Пятёрочка":{"count":398},"abc":{"count":74},"7/11":{"count":51},"Stewart's":{"count":255},"Продукти":{"count":171},"ローソンストア100 (LAWSON STORE 100)":{"count":85},"Дикси":{"count":119},"Радуга":{"count":86},"ローソンストア100":{"count":76},"เซเว่นอีเลฟเว่น":{"count":185},"Delikatesy Centrum":{"count":53},"Citgo":{"count":62},"Фортуна":{"count":51},"Kum & Go":{"count":59},"Мария-Ра":{"count":76},"Picard":{"count":57},"Four Square":{"count":52},"Визит":{"count":57},"Авоська":{"count":55},"Dollar General":{"count":127},"Studenac":{"count":76},"Central Convenience Store":{"count":55},"Монетка":{"count":62},"продукты":{"count":114},"Теремок":{"count":56},"Kwik Trip":{"count":69},"Кулинария":{"count":55},"全家":{"count":90},"Мечта":{"count":54},"Epicerie":{"count":102},"Кировский":{"count":67},"Food Mart":{"count":117},"Delikatesy":{"count":81},"ポプラ":{"count":54},"Lewiatan":{"count":135},"Продуктовый магазин":{"count":149},"Продуктовый":{"count":84},"セイコーマート (Seicomart)":{"count":72},"Виктория":{"count":70},"Весна":{"count":57},"Mini Market Non-Stop":{"count":60},"QuikTrip":{"count":75},"Копеечка":{"count":51},"Royal Farms":{"count":51},"Alfamart":{"count":103},"Indomaret":{"count":141},"магазин":{"count":171},"全家便利商店":{"count":156},"Boutique":{"count":59},"მარკეტი (Market)":{"count":144},"Stores":{"count":61}},"chemist":{"dm":{"count":939},"Müller":{"count":212},"Schlecker":{"count":187},"Etos":{"count":467},"Bipa":{"count":289},"Rossmann":{"count":1669},"DM Drogeriemarkt":{"count":55},"Ihr Platz":{"count":73},"Douglas":{"count":62},"Kruidvat":{"count":123}},"car_repair":{"Peugeot":{"count":83},"Kwik Fit":{"count":128},"ATU":{"count":261},"Midas":{"count":202},"Feu Vert":{"count":113},"Norauto":{"count":152},"Speedy":{"count":115},"Автозапчасти":{"count":212},"Renault":{"count":171},"Pit Stop":{"count":58},"Jiffy Lube":{"count":198},"Шиномонтаж":{"count":1157},"СТО":{"count":395},"O'Reilly Auto Parts":{"count":81},"Carglass":{"count":112},"шиномонтаж":{"count":62},"Citroen":{"count":51},"Euromaster":{"count":87},"Firestone":{"count":88},"Автосервис":{"count":361},"Advance Auto Parts":{"count":52},"Roady":{"count":56}},"furniture":{"IKEA":{"count":169},"Jysk":{"count":109},"Roller":{"count":78},"Dänisches Bettenlager":{"count":309},"Conforama":{"count":99},"Matratzen Concord":{"count":52},"Мебель":{"count":210},"But":{"count":63}},"doityourself":{"Hornbach":{"count":123},"B&Q":{"count":225},"Hubo":{"count":77},"Mr Bricolage":{"count":88},"Gamma":{"count":111},"OBI":{"count":422},"Lowes":{"count":1152},"Wickes":{"count":123},"Hagebau":{"count":59},"Max Bahr":{"count":79},"Castorama":{"count":153},"Rona":{"count":61},"Home Depot":{"count":865},"Toom Baumarkt":{"count":71},"Homebase":{"count":225},"Baumax":{"count":95},"Lagerhaus":{"count":79},"Bauhaus":{"count":186},"Canadian Tire":{"count":97},"Leroy Merlin":{"count":209},"Hellweg":{"count":58},"Brico":{"count":98},"Bricomarché":{"count":235},"Toom":{"count":67},"Hagebaumarkt":{"count":107},"Praktiker":{"count":122},"Menards":{"count":70},"Weldom":{"count":73},"Bunnings Warehouse":{"count":91},"Ace Hardware":{"count":147},"Home Hardware":{"count":72},"Хозтовары":{"count":86},"Стройматериалы":{"count":197},"Bricorama":{"count":60},"Point P":{"count":59}},"stationery":{"Staples":{"count":299},"McPaper":{"count":83},"Office Depot":{"count":98},"Канцтовары":{"count":63}},"car":{"Skoda":{"count":97},"BMW":{"count":149},"Citroen":{"count":277},"Renault":{"count":382},"Mercedes-Benz":{"count":235},"Volvo":{"count":96},"Ford":{"count":239},"Volkswagen":{"count":217},"Mazda":{"count":105},"Mitsubishi":{"count":73},"Fiat":{"count":93},"Автозапчасти":{"count":277},"Opel":{"count":165},"Audi":{"count":121},"Toyota":{"count":271},"Nissan":{"count":189},"Suzuki":{"count":75},"Honda":{"count":157},"Peugeot":{"count":308},"Шиномонтаж":{"count":259},"Hyundai":{"count":166},"Subaru":{"count":58},"Chevrolet":{"count":86},"Автомагазин":{"count":72}},"clothes":{"Matalan":{"count":90},"KiK":{"count":1219},"H&M":{"count":658},"Urban Outfitters":{"count":63},"Vögele":{"count":132},"Zeeman":{"count":121},"Takko":{"count":515},"Adler":{"count":55},"C&A":{"count":506},"Zara":{"count":217},"Vero Moda":{"count":95},"NKD":{"count":486},"Ernsting's family":{"count":312},"Winners":{"count":65},"River Island":{"count":59},"Next":{"count":176},"Gap":{"count":81},"Adidas":{"count":92},"Woolworths":{"count":117},"Mr Price":{"count":88},"Jet":{"count":61},"Pep":{"count":134},"Edgars":{"count":110},"Ackermans":{"count":91},"Truworths":{"count":65},"Ross":{"count":93},"Burton":{"count":51},"Dorothy Perkins":{"count":53},"Deichmann":{"count":61},"Lindex":{"count":73},"s.Oliver":{"count":56},"Cecil":{"count":51},"Dress Barn":{"count":52},"Old Navy":{"count":174},"Jack & Jones":{"count":52},"Pimkie":{"count":73},"Esprit":{"count":231},"Primark":{"count":92},"Bonita":{"count":155},"Mexx":{"count":67},"Gerry Weber":{"count":71},"Tally Weijl":{"count":70},"Mango":{"count":133},"TK Maxx":{"count":84},"Benetton":{"count":101},"Ulla Popken":{"count":61},"AWG":{"count":66},"Tommy Hilfiger":{"count":75},"New Yorker":{"count":180},"Orsay":{"count":73},"Jeans Fritz":{"count":51},"Charles Vögele":{"count":69},"New Look":{"count":126},"Lacoste":{"count":78},"Etam":{"count":53},"Kiabi":{"count":148},"Jack Wolfskin":{"count":60},"American Apparel":{"count":57},"Men's Wearhouse":{"count":54},"Intimissimi":{"count":52},"United Colors of Benetton":{"count":96},"Jules":{"count":63},"Second Hand":{"count":53},"AOKI":{"count":57},"Calzedonia":{"count":68},"洋服の青山":{"count":100},"Levi's":{"count":63},"Celio":{"count":74},"TJ Maxx":{"count":57},"Promod":{"count":82},"Street One":{"count":72},"ユニクロ":{"count":59},"Banana Republic":{"count":57},"Одежда":{"count":75},"Marshalls":{"count":56},"La Halle":{"count":62},"Peacocks":{"count":89},"しまむら":{"count":60}},"books":{"Bruna":{"count":58},"Waterstones":{"count":90},"Libro":{"count":57},"Barnes & Noble":{"count":267},"Weltbild":{"count":74},"Thalia":{"count":121},"Книги":{"count":112}},"department_store":{"Debenhams":{"count":67},"Canadian Tire":{"count":75},"Karstadt":{"count":64},"Walmart":{"count":517},"Kmart":{"count":143},"Target":{"count":574},"Galeria Kaufhof":{"count":61},"Marks & Spencer":{"count":66},"Big W":{"count":57},"Woolworth":{"count":78},"Универмаг":{"count":72},"Sears":{"count":235},"Walmart Supercenter":{"count":101},"Kohl's":{"count":153},"Macy's":{"count":147},"Sam's Club":{"count":54},"JCPenney":{"count":66}},"alcohol":{"Alko":{"count":145},"The Beer Store":{"count":150},"Systembolaget":{"count":210},"LCBO":{"count":239},"Ароматный мир":{"count":62},"Bargain Booze":{"count":62},"Nicolas":{"count":119},"BWS":{"count":70},"Botilleria":{"count":77},"SAQ":{"count":72},"Gall & Gall":{"count":512},"Живое пиво":{"count":70}},"bakery":{"Kamps":{"count":252},"Banette":{"count":52},"Bäckerei Schmidt":{"count":57},"Anker":{"count":73},"Hofpfisterei":{"count":111},"Greggs":{"count":276},"Oebel":{"count":57},"Boulangerie":{"count":266},"Stadtbäckerei":{"count":57},"Steinecke":{"count":145},"Ihle":{"count":76},"Goldilocks":{"count":59},"Dat Backhus":{"count":67},"K&U":{"count":61},"Der Beck":{"count":96},"Thürmann":{"count":54},"Backwerk":{"count":95},"Schäfer's":{"count":51},"Panaderia":{"count":168},"Goeken backen":{"count":51},"Stadtbäckerei Junge":{"count":51},"Boulangerie Patisserie":{"count":119},"Paul":{"count":81},"Хлеб":{"count":89},"Пекарня":{"count":52},"Кулиничи":{"count":51}},"sports":{"Sports Direct":{"count":57},"Decathlon":{"count":309},"Intersport":{"count":283},"Sports Authority":{"count":75},"Спортмастер":{"count":87},"Sport 2000":{"count":90},"Dick's Sporting Goods":{"count":77}},"variety_store":{"Tedi":{"count":157},"Dollarama":{"count":103},"Family Dollar":{"count":61},"Dollar Tree":{"count":110},"Dollar General":{"count":80}},"pet":{"Fressnapf":{"count":318},"PetSmart":{"count":177},"Das Futterhaus":{"count":69},"Pets at Home":{"count":62},"Petco":{"count":101},"Зоомагазин":{"count":100}},"shoes":{"Deichmann":{"count":622},"Reno":{"count":183},"Ecco":{"count":55},"Clarks":{"count":109},"La Halle aux Chaussures":{"count":69},"Brantano":{"count":71},"Geox":{"count":51},"Salamander":{"count":51},"Обувь":{"count":100},"Payless Shoe Source":{"count":67},"Famous Footwear":{"count":59},"Quick Schuh":{"count":72},"Shoe Zone":{"count":55},"Foot Locker":{"count":82},"Bata":{"count":101},"ЦентрОбувь":{"count":51}},"toys":{"La Grande Récré":{"count":56},"Toys R Us":{"count":151,"tags":{"shop":"toys"}},"Intertoys":{"count":57},"Детский мир":{"count":86},"Игрушки":{"count":58}},"travel_agency":{"Flight Centre":{"count":92},"Thomas Cook":{"count":119}},"jewelry":{"Bijou Brigitte":{"count":57},"Christ":{"count":57},"Swarovski":{"count":74}},"optician":{"Fielmann":{"count":232},"Apollo Optik":{"count":150},"Vision Express":{"count":58},"Оптика":{"count":182},"Optic 2000":{"count":98},"Alain Afflelou":{"count":73},"Specsavers":{"count":124},"Krys":{"count":77},"Atol":{"count":55}},"video":{"Blockbuster":{"count":184},"World of Video":{"count":64}},"mobile_phone":{"Билайн":{"count":128},"ソフトバンクショップ (SoftBank shop)":{"count":255},"Vodafone":{"count":355},"O2":{"count":208},"Carphone Warehouse":{"count":127},"Orange":{"count":246},"Verizon Wireless":{"count":125},"Sprint":{"count":109},"T-Mobile":{"count":175},"МТС":{"count":352},"Евросеть":{"count":506},"Bell":{"count":190},"The Phone House":{"count":83},"SFR":{"count":71},"Связной":{"count":439},"Мегафон":{"count":251},"AT&T":{"count":124},"ドコモショップ (docomo shop)":{"count":114},"au":{"count":65},"Movistar":{"count":77},"Bitė":{"count":72}},"hifi":{},"computer":{"PC World":{"count":55},"DNS":{"count":128}},"hairdresser":{"Klier":{"count":119},"Supercuts":{"count":106},"Hairkiller":{"count":51},"Great Clips":{"count":182},"Парикмахерская":{"count":510},"Стиль":{"count":51},"Franck Provost":{"count":70},"Салон красоты":{"count":70}},"hardware":{"1000 мелочей":{"count":61},"Хозтовары":{"count":151},"Стройматериалы":{"count":54}},"motorcycle":{"Yamaha":{"count":67},"Honda":{"count":69}}};
18594 var dataSuggestions = {
18595         amenity: amenity,
18596         shop: shop
18597 };
18598
18599 var dataAddressFormats = [{"format":[["housenumber","street"],["city","postcode"]]},{"countryCodes":["gb"],"format":[["housename"],["housenumber","street"],["city","postcode"]]},{"countryCodes":["ie"],"format":[["housename"],["housenumber","street"],["city"],["postcode"]]},{"countryCodes":["ad","at","ba","be","ch","cz","de","dk","es","fi","gr","hr","is","it","li","nl","no","pl","pt","se","si","sk","sm","va"],"format":[["street","housenumber"],["postcode","city"]]},{"countryCodes":["fr","lu","mo"],"format":[["housenumber","street"],["postcode","city"]]},{"countryCodes":["br"],"format":[["street"],["housenumber","suburb"],["city","postcode"]]},{"countryCodes":["vn"],"format":[["housenumber","street"],["subdistrict"],["district"],["city"],["province","postcode"]]},{"countryCodes":["us"],"format":[["housenumber","street"],["city","state","postcode"]]},{"countryCodes":["ca"],"format":[["housenumber","street"],["city","province","postcode"]]},{"countryCodes":["tw"],"format":[["postcode","city","district"],["place","street"],["housenumber","floor"]]},{"countryCodes":["jp"],"format":[["postcode","province","county"],["city","suburb"],["quarter","neighbourhood"],["block_number","housenumber"]],"dropdowns":["postcode","province","county","city","suburb","quarter","neighbourhood","block_number"],"widths":{"postcode":0.3,"province":0.35,"county":0.35,"city":0.65,"suburb":0.35,"quarter":0.5,"neighbourhood":0.5,"block_number":0.5,"housenumber":0.5}},{"countryCodes":["tr"],"format":[["neighbourhood"],["street","housenumber"],["postcode","district","city"]]},{"countryCodes":["ua"],"format":[["housenumber","postcode"],["street"]]},{"countryCodes":["cn"],"format":[["postcode","province"],["city"],["district"],["street","housenumber"]]}];
18600
18601 var dataDeprecated = [{"old":{"amenity":"firepit"},"replace":{"leisure":"firepit"}},{"old":{"barrier":"wire_fence"},"replace":{"barrier":"fence","fence_type":"chain"}},{"old":{"barrier":"wood_fence"},"replace":{"barrier":"fence","fence_type":"wood"}},{"old":{"highway":"ford"},"replace":{"ford":"yes"}},{"old":{"highway":"stile"},"replace":{"barrier":"stile"}},{"old":{"highway":"incline"},"replace":{"highway":"road","incline":"up"}},{"old":{"highway":"incline_steep"},"replace":{"highway":"road","incline":"up"}},{"old":{"highway":"unsurfaced"},"replace":{"highway":"road","incline":"unpaved"}},{"old":{"landuse":"wood"},"replace":{"landuse":"forest","natural":"wood"}},{"old":{"natural":"marsh"},"replace":{"natural":"wetland","wetland":"marsh"}},{"old":{"power_source":"*"},"replace":{"generator:source":"$1"}},{"old":{"power_rating":"*"},"replace":{"generator:output":"$1"}},{"old":{"shop":"organic"},"replace":{"shop":"supermarket","organic":"only"}}];
18602
18603 var dataDiscarded = ["created_by","odbl","odbl:note","tiger:upload_uuid","tiger:tlid","tiger:source","tiger:separated","geobase:datasetName","geobase:uuid","sub_sea:type","KSJ2:ADS","KSJ2:ARE","KSJ2:AdminArea","KSJ2:COP_label","KSJ2:DFD","KSJ2:INT","KSJ2:INT_label","KSJ2:LOC","KSJ2:LPN","KSJ2:OPC","KSJ2:PubFacAdmin","KSJ2:RAC","KSJ2:RAC_label","KSJ2:RIC","KSJ2:RIN","KSJ2:WSC","KSJ2:coordinate","KSJ2:curve_id","KSJ2:curve_type","KSJ2:filename","KSJ2:lake_id","KSJ2:lat","KSJ2:long","KSJ2:river_id","yh:LINE_NAME","yh:LINE_NUM","yh:STRUCTURE","yh:TOTYUMONO","yh:TYPE","yh:WIDTH","yh:WIDTH_RANK","SK53_bulk:load"];
18604
18605 var dataLocales = {"af":{"rtl":false},"ar":{"rtl":true},"ar-AA":{"rtl":true},"ast":{"rtl":false},"bg":{"rtl":false},"bg-BG":{"rtl":false},"bn":{"rtl":false},"bs":{"rtl":false},"ca":{"rtl":false},"cs":{"rtl":false},"da":{"rtl":false},"de":{"rtl":false},"el":{"rtl":false},"en-GB":{"rtl":false},"eo":{"rtl":false},"es":{"rtl":false},"et":{"rtl":false},"fa":{"rtl":true},"fi":{"rtl":false},"fr":{"rtl":false},"gan":{"rtl":false},"gl":{"rtl":false},"gu":{"rtl":false},"he":{"rtl":true},"hi":{"rtl":false},"hr":{"rtl":false},"hu":{"rtl":false},"hy":{"rtl":false},"ia":{"rtl":false},"id":{"rtl":false},"is":{"rtl":false},"it":{"rtl":false},"ja":{"rtl":false},"jv":{"rtl":false},"km":{"rtl":false},"kn":{"rtl":false},"ko":{"rtl":false},"ku":{"rtl":true},"lij":{"rtl":false},"lt":{"rtl":false},"lv":{"rtl":false},"mg":{"rtl":false},"mk":{"rtl":false},"ml":{"rtl":false},"mn":{"rtl":false},"ms":{"rtl":false},"ne":{"rtl":false},"nl":{"rtl":false},"nn":{"rtl":false},"no":{"rtl":false},"nv":{"rtl":false},"pl":{"rtl":false},"pt":{"rtl":false},"pt-BR":{"rtl":false},"rm":{"rtl":false},"ro":{"rtl":false},"ru":{"rtl":false},"sc":{"rtl":false},"si":{"rtl":false},"sk":{"rtl":false},"sl":{"rtl":false},"sq":{"rtl":false},"sr":{"rtl":false},"sv":{"rtl":false},"ta":{"rtl":false},"te":{"rtl":false},"th":{"rtl":false},"tl":{"rtl":false},"tr":{"rtl":false},"uk":{"rtl":false},"ur":{"rtl":true},"vi":{"rtl":false},"yue":{"rtl":false},"zh":{"rtl":false},"zh-CN":{"rtl":false},"zh-HK":{"rtl":false},"zh-TW":{"rtl":false}};
18606
18607 var dataPhoneFormats = {"us":"+1-202-555-1234","ca":"+1-226-555-1234","bs":"+1-242-555-1234","bb":"+1-246-555-1234","ai":"+1-264-555-1234","ag":"+1-268-555-1234","vg":"+1-284-555-1234","vi":"+1-340-555-1234","ky":"+1-345-555-1234","bm":"+1-441-555-1234","gd":"+1-473-555-1234","tc":"+1-649-555-1234","ms":"+1-664-555-1234","mp":"+1-670-555-1234","gu":"+1-671-555-1234","as":"+1-684-555-1234","sx":"+1-721-555-1234","lc":"+1-758-555-1234","dm":"+1-767-555-1234","vc":"+1-784-555-1234","pr":"+1-787-555-1234","do":"+1-809-555-1234","tt":"+1-868-555-1234","kn":"+1-869-555-1234","jm":"+1-876-555-1234","za":"+27 11 907 1111","nl":"+31 42 123 4567","fr":"+33 1 23 45 67 89","es":"+34 989 12 34 56","pt":"+351 211 123456","ie":"+353 20 912 3456","fi":"+358 40 123 4567","hu":"+36 1 123 45 67","hr":"+385 01 123 4567","si":"+386 31 123 4567","it":"+39 01 123 456","va":"+39 01 123 456","gb":"+44 1632 961234","gg":"+44 1632 961234","im":"+44 1632 961234","je":"+44 1632 961234","se":"+46 31 123 4567","no":"+47 22 12 34 56","sj":"+47 22 12 34 56","pl":"+48 42 123 4567","de":"+49 89 1234567","br":"+55 11 0982 1098","ru":"+7 495 1234567","kz":"+7 495 1234567","vn":"+84 1 234 5678","hk":"+852 1234 5678","cn":"+86 10 12345678","tw":"+886 1 2345 6789","tr":"+90 312 123 4567","ua":"+380 44 123 4567"};
18608
18609 var type = "FeatureCollection";
18610 var features = [{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[1.97754,51.13111],[1.8457,63.45051],[-10.45898,57.01681],[-6.82251,55.26503],[-7.25583,55.06525],[-7.26546,55.0665],[-7.26992,55.06419],[-7.2725,55.06346],[-7.27818,55.05362],[-7.2893,55.04735],[-7.29939,55.0561],[-7.31835,55.04475],[-7.3447,55.05079],[-7.38831,55.02389],[-7.40547,55.00292],[-7.39157,54.99507],[-7.40075,54.98892],[-7.40706,54.98291],[-7.40363,54.97963],[-7.40633,54.97813],[-7.39835,54.97013],[-7.40745,54.96357],[-7.40178,54.95961],[-7.40727,54.95515],[-7.3944,54.94376],[-7.44444,54.93858],[-7.45216,54.89793],[-7.44204,54.87532],[-7.4713,54.83431],[-7.48092,54.83093],[-7.49216,54.82185],[-7.55121,54.79054],[-7.5443,54.78609],[-7.54958,54.75653],[-7.5349,54.74917],[-7.54881,54.74068],[-7.55941,54.74556],[-7.57894,54.74221],[-7.57507,54.7494],[-7.58606,54.75039],[-7.58872,54.74377],[-7.60031,54.74603],[-7.60632,54.74405],[-7.61662,54.74459],[-7.63593,54.75108],[-7.68854,54.72968],[-7.72064,54.72155],[-7.75094,54.70469],[-7.79094,54.71942],[-7.8051,54.71932],[-7.83497,54.73632],[-7.85419,54.72745],[-7.91496,54.67582],[-7.90174,54.66182],[-7.83832,54.63401],[-7.7433,54.6188],[-7.70863,54.63485],[-7.70682,54.6189],[-7.69386,54.6188],[-7.69631,54.61125],[-7.75845,54.59509],[-7.78708,54.58],[-7.79446,54.58141],[-7.79969,54.57704],[-7.79673,54.56915],[-7.8184,54.56315],[-7.83334,54.55227],[-7.82737,54.54299],[-7.85007,54.53363],[-7.90741,54.53722],[-7.93213,54.53388],[-8.00487,54.54568],[-8.03727,54.51162],[-8.04285,54.48759],[-8.08027,54.48829],[-8.09988,54.48395],[-8.09126,54.4765],[-8.111,54.47807],[-8.11512,54.46904],[-8.16542,54.46914],[-8.1776,54.46485],[-8.14293,54.45003],[-8.16284,54.4413],[-8.08731,54.4002],[-8.06062,54.37051],[-8.03289,54.35711],[-8.00054,54.34835],[-7.93333,54.30561],[-7.85849,54.29151],[-7.87067,54.28794],[-7.87265,54.26648],[-7.86123,54.25931],[-7.85917,54.21256],[-7.71043,54.20307],[-7.70193,54.20776],[-7.68828,54.202],[-7.67644,54.18906],[-7.66082,54.1871],[-7.62554,54.16545],[-7.62541,54.15319],[-7.61026,54.14353],[-7.57421,54.14142],[-7.57181,54.13287],[-7.56228,54.12704],[-7.51379,54.12998],[-7.47944,54.122],[-7.47169,54.12665],[-7.47075,54.13318],[-7.44684,54.15168],[-7.40792,54.156],[-7.42579,54.14092],[-7.41903,54.13629],[-7.3744,54.14172],[-7.37234,54.13881],[-7.39509,54.12624],[-7.39182,54.12017],[-7.36341,54.13157],[-7.34518,54.11577],[-7.32471,54.12123],[-7.32003,54.11379],[-7.3078,54.11718],[-7.30548,54.12347],[-7.31591,54.12697],[-7.31213,54.13162],[-7.3187,54.13411],[-7.31857,54.13745],[-7.32222,54.13836],[-7.32737,54.13544],[-7.3399,54.14585],[-7.30827,54.16716],[-7.30024,54.16625],[-7.29029,54.1715],[-7.28158,54.16839],[-7.2863,54.14919],[-7.29874,54.14904],[-7.30162,54.14411],[-7.28411,54.13971],[-7.29192,54.13071],[-7.29737,54.133],[-7.30883,54.13242],[-7.30333,54.12251],[-7.29218,54.11929],[-7.27844,54.12282],[-7.27707,54.12986],[-7.26613,54.13624],[-7.2566,54.16354],[-7.24015,54.17125],[-7.2575,54.17678],[-7.2581,54.19257],[-7.25179,54.19403],[-7.23608,54.1935],[-7.23338,54.19792],[-7.24317,54.20076],[-7.24892,54.1977],[-7.25183,54.20201],[-7.24119,54.20623],[-7.23094,54.20578],[-7.23269,54.20912],[-7.22188,54.21607],[-7.20643,54.2117],[-7.18506,54.22485],[-7.17055,54.21742],[-7.14721,54.22488],[-7.14633,54.23008],[-7.15051,54.23165],[-7.14613,54.23983],[-7.15802,54.24434],[-7.13985,54.25298],[-7.15255,54.26235],[-7.16064,54.27405],[-7.17991,54.27144],[-7.17201,54.28627],[-7.21252,54.2985],[-7.19888,54.31117],[-7.17918,54.30946],[-7.1812,54.3397],[-7.15339,54.33514],[-7.10253,54.35811],[-7.10811,54.36677],[-7.06927,54.3899],[-7.05593,54.41056],[-7.02898,54.42135],[-7.00198,54.40832],[-6.98683,54.40829],[-6.97562,54.40014],[-6.96774,54.40145],[-6.90682,54.36966],[-6.89772,54.35075],[-6.87527,54.33853],[-6.86512,54.32568],[-6.85163,54.29137],[-6.87452,54.28677],[-6.87791,54.27918],[-6.86673,54.27522],[-6.85177,54.26489],[-6.83693,54.26658],[-6.82165,54.24346],[-6.81633,54.22299],[-6.80045,54.22108],[-6.80122,54.21338],[-6.77599,54.19965],[-6.75573,54.1987],[-6.74316,54.18258],[-6.73406,54.18566],[-6.72445,54.18127],[-6.70295,54.20036],[-6.69166,54.20018],[-6.68673,54.19398],[-6.669,54.19584],[-6.65248,54.18102],[-6.6433,54.17801],[-6.63467,54.16449],[-6.63179,54.14766],[-6.64081,54.14238],[-6.63935,54.13599],[-6.66149,54.1205],[-6.6481,54.10153],[-6.66119,54.0934],[-6.66458,54.06629],[-6.64681,54.05873],[-6.62501,54.03737],[-6.59291,54.04755],[-6.58905,54.05808],[-6.5597,54.0481],[-6.52897,54.05888],[-6.50442,54.05566],[-6.47824,54.07004],[-6.47919,54.07762],[-6.43601,54.05959],[-6.36314,54.07057],[-6.36589,54.09338],[-6.36293,54.09758],[-6.37104,54.11497],[-6.3522,54.11084],[-6.34242,54.1114],[-6.33589,54.10833],[-6.33636,54.09469],[-6.31808,54.09096],[-6.30903,54.10463],[-6.29165,54.11235],[-6.28246,54.11145],[-6.26272,54.09786],[-5.35583,53.72597],[-7.0752,49.23912],[-1.83472,49.02346],[-2.12036,49.94415],[1.97754,51.13111]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-65.2,18.7],[-65,16.3],[-63.7,19.2],[-65.2,18.7]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-63,-50.5],[-55,-51],[-60,-54],[-63,-50.5]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-139.19952,60.08402],[-141,60.30621],[-141,76],[-169,68.63655],[-169,65.20147],[-180,61],[-180,-4],[-154,9],[-133.76404,54.54021],[-130.73868,54.71986],[-129.96277,55.29163],[-130.15228,55.7758],[-130.01787,55.90688],[-130.00362,56.00798],[-130.10284,56.12336],[-130.24498,56.09656],[-130.42625,56.14249],[-131.87439,56.79787],[-135.02884,59.56285],[-135.11759,59.62306],[-135.15827,59.6261],[-135.47928,59.79822],[-136.28677,59.57955],[-136.30531,59.46462],[-136.36836,59.44898],[-136.47697,59.46558],[-137.19727,59.01935],[-139.19952,60.08402]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-111.96064,48.99841],[-121.22623,49.00049],[-122.26513,49.00246],[-122.7565,49.00208],[-123.32218,49.00218],[-122.97821,48.76524],[-123.2666,48.69821],[-123.21991,48.21186],[-125.80444,48.60749],[-124.32129,31.54109],[-117.125,32.53429],[-116.82417,32.55996],[-115.88036,32.63735],[-115.49738,32.66486],[-114.71984,32.71877],[-114.7649,32.64602],[-114.80885,32.60959],[-114.81481,32.49451],[-112.81743,31.88004],[-111.07481,31.33224],[-109.56051,31.33402],[-108.20847,31.33384],[-108.20838,31.78363],[-106.52847,31.78391],[-106.52781,31.78086],[-106.52249,31.77501],[-106.51249,31.76933],[-106.50988,31.7612],[-106.50709,31.76123],[-106.48896,31.74806],[-106.48473,31.74769],[-106.4719,31.75101],[-106.46816,31.75897],[-106.45434,31.76466],[-106.45035,31.76426],[-106.43516,31.75492],[-106.41484,31.75101],[-106.37864,31.73021],[-106.37225,31.71174],[-106.34924,31.69633],[-106.33289,31.66178],[-106.3068,31.62459],[-106.28079,31.56179],[-106.24775,31.54226],[-106.2329,31.49982],[-106.2105,31.46857],[-106.08201,31.39863],[-106.00554,31.39233],[-105.76401,31.17051],[-105.58548,31.06117],[-105.56419,30.98526],[-104.99153,30.6639],[-104.97162,30.60896],[-104.90639,30.57822],[-104.83772,30.38117],[-104.70177,30.20567],[-104.68048,29.92399],[-104.57611,29.77838],[-104.51157,29.63674],[-104.39758,29.57047],[-104.39278,29.55293],[-104.05769,29.32173],[-103.79883,29.2581],[-103.78196,29.26555],[-103.76759,29.22799],[-103.14102,28.93666],[-102.86087,29.2217],[-102.65076,29.79418],[-101.41068,29.73457],[-101.26511,29.51372],[-101.05997,29.452],[-101.04083,29.38038],[-100.96303,29.34735],[-100.94406,29.34369],[-100.94071,29.33351],[-100.92775,29.32663],[-100.89814,29.30957],[-100.87818,29.28086],[-100.80076,29.2238],[-100.76437,29.15981],[-100.67047,29.08663],[-100.6412,28.91299],[-100.63236,28.90255],[-100.61296,28.89939],[-100.534,28.75622],[-100.51495,28.74531],[-100.50705,28.7143],[-100.51203,28.70666],[-100.51014,28.69127],[-100.50048,28.66186],[-100.45547,28.6381],[-100.44697,28.60743],[-100.35599,28.45239],[-100.34946,28.39653],[-100.29488,28.31315],[-100.29591,28.27324],[-100.17197,28.17493],[-99.93645,27.9568],[-99.87722,27.80173],[-99.79671,27.73338],[-99.772,27.72532],[-99.74556,27.69979],[-99.71947,27.65981],[-99.5957,27.59974],[-99.54094,27.60537],[-99.53055,27.57973],[-99.52034,27.55782],[-99.52802,27.49773],[-99.50141,27.49986],[-99.48755,27.49518],[-99.47897,27.48421],[-99.48661,27.46453],[-99.49534,27.44861],[-99.48927,27.40941],[-99.53957,27.31565],[-99.43588,27.19678],[-99.46404,27.01968],[-99.16698,26.56039],[-99.17474,26.53939],[-99.12698,26.51958],[-99.1135,26.42954],[-99.08355,26.39625],[-99.06007,26.39737],[-99.03634,26.41255],[-99.02042,26.40598],[-99.01291,26.39364],[-98.95686,26.38641],[-98.9566,26.37365],[-98.94523,26.36949],[-98.90013,26.36419],[-98.89905,26.35454],[-98.80305,26.36626],[-98.78254,26.30511],[-98.66667,26.23457],[-98.58496,26.24647],[-98.57951,26.23434],[-98.56519,26.23987],[-98.56294,26.22464],[-98.50599,26.20858],[-98.44806,26.21236],[-98.38617,26.15721],[-98.34176,26.15278],[-98.33579,26.1388],[-98.30626,26.10003],[-98.28841,26.10512],[-98.26524,26.0914],[-98.19898,26.06411],[-98.09577,26.05698],[-98.07568,26.06667],[-98.08302,26.03396],[-97.9771,26.04136],[-97.9532,26.06179],[-97.81643,26.04475],[-97.77017,26.02439],[-97.73884,26.02902],[-97.5289,25.90648],[-97.52151,25.88625],[-97.50615,25.89031],[-97.49851,25.89903],[-97.49637,25.89641],[-97.49748,25.88008],[-97.49422,25.87981],[-97.48847,25.88564],[-97.46409,25.88174],[-97.42607,25.842],[-97.36856,25.8396],[-97.26231,25.94724],[-80.81543,24.00633],[-66.87378,44.77794],[-67.16148,45.16715],[-67.2286,45.16739],[-67.26246,45.18797],[-67.28311,45.19175],[-67.28959,45.18784],[-67.29332,45.17568],[-67.29049,45.17317],[-67.3001,45.16776],[-67.3025,45.16122],[-67.29761,45.14766],[-67.33975,45.1255],[-67.40524,45.16122],[-67.40387,45.17139],[-67.4818,45.27682],[-67.42172,45.38543],[-67.45262,45.41008],[-67.50498,45.4889],[-67.41623,45.50105],[-67.42219,45.55661],[-67.42902,45.56833],[-67.42331,45.57154],[-67.42498,45.57836],[-67.45193,45.60323],[-67.77981,45.6738],[-67.79019,47.06776],[-67.88006,47.1067],[-67.91319,47.14793],[-67.92598,47.15418],[-67.95181,47.1875],[-68.02374,47.23915],[-68.13017,47.29309],[-68.17669,47.32893],[-68.24046,47.35354],[-68.32809,47.36005],[-68.36363,47.35476],[-68.38054,47.34167],[-68.38509,47.30321],[-68.37367,47.28796],[-68.4377,47.28232],[-68.47916,47.29623],[-68.51074,47.29885],[-68.54593,47.28441],[-68.58408,47.28482],[-68.59777,47.27134],[-68.59271,47.25762],[-68.61889,47.24148],[-68.68936,47.24125],[-68.71768,47.23676],[-68.80128,47.21423],[-68.89629,47.17676],[-69.05354,47.24847],[-69.04924,47.41798],[-69.22425,47.45961],[-69.99729,46.69558],[-70.0569,46.4149],[-70.25551,46.10871],[-70.29001,46.09431],[-70.39919,45.80667],[-70.83229,45.40062],[-70.80794,45.37878],[-70.82663,45.2367],[-70.87538,45.23453],[-70.92138,45.28099],[-70.90645,45.30918],[-71.0109,45.34798],[-71.08429,45.30556],[-71.1454,45.24226],[-71.20525,45.25278],[-71.28925,45.30097],[-71.41405,45.23513],[-71.43044,45.12381],[-71.49692,45.06991],[-71.50623,45.04878],[-71.49284,45.03629],[-71.50027,45.01372],[-71.79359,45.01075],[-72.08774,45.00581],[-72.14155,45.00568],[-72.15282,45.00609],[-72.17142,45.00584],[-72.25847,45.00436],[-72.38795,45.00626],[-72.4496,45.00863],[-72.5356,45.00936],[-72.66257,45.01523],[-72.82537,45.01642],[-73.08466,45.01561],[-73.45219,45.00875],[-74.14699,44.99145],[-74.33753,44.9923],[-74.50786,44.99798],[-74.66158,44.99949],[-74.71244,44.99734],[-74.75887,44.98708],[-74.76368,45.00632],[-74.78977,45.00365],[-74.82376,45.01773],[-74.94186,44.98229],[-75.30098,44.83883],[-75.30304,44.82836],[-75.59418,44.6457],[-75.97269,44.33502],[-75.97295,44.34595],[-76.00059,44.34797],[-76.17645,44.2865],[-76.18744,44.22158],[-76.88782,43.82759],[-79.16851,43.32168],[-79.05487,43.25371],[-79.05092,43.169],[-79.04603,43.16093],[-79.04208,43.13942],[-79.07002,43.12038],[-79.06015,43.114],[-79.0568,43.10474],[-79.0774,43.07861],[-78.9996,43.05484],[-79.02311,43.02071],[-79.02552,42.99473],[-78.96235,42.9573],[-78.91188,42.9426],[-78.90398,42.89181],[-82.42767,41.47978],[-83.14316,42.03807],[-83.12805,42.23843],[-83.09715,42.29052],[-83.07252,42.31515],[-82.94575,42.34332],[-82.59676,42.5479],[-82.51368,42.61785],[-82.5108,42.66464],[-82.4675,42.76415],[-82.48055,42.80573],[-82.45497,42.9284],[-82.41334,42.97099],[-82.42596,42.99536],[-82.15851,43.39507],[-83.53729,46.098],[-83.96301,46.05036],[-84.11021,46.23851],[-84.09794,46.25656],[-84.11613,46.26878],[-84.11905,46.31516],[-84.10721,46.3218],[-84.14394,46.41076],[-84.11682,46.51576],[-84.13536,46.53218],[-84.16162,46.5284],[-84.21621,46.53891],[-84.26994,46.49189],[-84.36092,46.50997],[-84.55284,46.4407],[-84.95178,46.77185],[-89.59179,48.00307],[-89.67547,48.00371],[-90.87204,48.25943],[-91.41312,48.06753],[-92.99377,48.62474],[-93.34877,48.62604],[-93.35529,48.61124],[-93.37074,48.60584],[-93.39812,48.60369],[-93.40542,48.61089],[-93.43846,48.59478],[-93.46859,48.59205],[-93.45735,48.56667],[-93.46533,48.54593],[-93.64763,48.51751],[-93.80625,48.51888],[-93.80642,48.58047],[-93.83328,48.62582],[-93.84865,48.63064],[-93.93388,48.6326],[-94.01327,48.64471],[-94.16176,48.64697],[-94.25025,48.65463],[-94.24931,48.67827],[-94.26046,48.69816],[-94.30578,48.71073],[-94.32758,48.70433],[-94.36123,48.70478],[-94.38406,48.71135],[-94.41629,48.71067],[-94.44294,48.69266],[-94.53615,48.7024],[-94.55031,48.71419],[-94.58894,48.71928],[-94.69425,48.77938],[-94.70129,48.83376],[-94.68996,48.83953],[-94.68395,48.99914],[-111.96064,48.99841]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[180,55],[170,53],[180,49],[180,55]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[143,22],[147,22],[147,12],[143,12],[143,22]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-171.5,-10],[-171,-15],[-167,-15],[-171.5,-10]]]}}];
18611 var dataImperial = {
18612         type: type,
18613         features: features
18614 };
18615
18616 var type$1 = "FeatureCollection";
18617 var features$1 = [{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[113.573,22.186],[114,22.5],[114.05534,22.503],[114.0595,22.51422],[114.07345,22.51934],[114.0786,22.53012],[114.08512,22.53228],[114.09034,22.53717],[114.09611,22.53486],[114.10602,22.53472],[114.1115,22.52929],[114.11522,22.5308],[114.11649,22.53418],[114.11979,22.53511],[114.1244,22.5393],[114.12729,22.53947],[114.13018,22.54132],[114.13807,22.5432],[114.14429,22.54176],[114.14441,22.54114],[114.14846,22.54179],[114.14855,22.54397],[114.15042,22.54593],[114.14964,22.54954],[114.15166,22.55168],[114.15192,22.55438],[114.15642,22.55495],[114.15841,22.55909],[114.16032,22.56153],[114.16162,22.56187],[114.1634,22.55931],[114.16553,22.5593],[114.16733,22.56119],[114.16934,22.56093],[114.17061,22.5597],[114.17702,22.56],[114.17798,22.55546],[114.18401,22.5552],[114.18673,22.55468],[114.1878,22.55545],[114.18979,22.55446],[114.1955,22.55564],[114.19674,22.55691],[114.20005,22.55717],[114.20376,22.55623],[114.20884,22.55672],[114.22438,22.55055],[114.2264,22.5476],[114.22545,22.54528],[114.22661,22.54339],[114.32,22.576],[114.45,22.43],[114.45,22.14],[113.9,22.14],[113.75,22.22],[113.553,22.095],[113.54678,22.1207],[113.5456,22.1207],[113.54076,22.12373],[113.54016,22.13618],[113.54701,22.13651],[113.5475,22.14583],[113.52456,22.17978],[113.53623,22.20191],[113.53299,22.21232],[113.53497,22.21351],[113.53735,22.21377],[113.54156,22.21315],[113.54385,22.21709],[113.55849,22.21565],[113.573,22.186]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-75,18],[-80,20.5],[-83,19],[-77,16],[-75,18]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-64.33594,32.86113],[-79.39819,27.21067],[-80.63965,23.71998],[-73.39966,20.40642],[-65.1709,19.20743],[-65.09399,16.23577],[-59.13391,16.80454],[-62.64404,15.16228],[-59.43054,14.85985],[-62.83081,13.64599],[-61.80359,10.73752],[-62.08649,10.04729],[-61.06201,9.85522],[-59.81369,8.31274],[-59.8027,8.27469],[-59.83498,8.22712],[-59.94141,8.21149],[-59.99771,8.15576],[-59.97986,8.13265],[-59.99771,8.12041],[-60.00183,8.07147],[-60.05127,8.02524],[-60.09933,8.03747],[-60.12268,8.02388],[-60.14053,7.98988],[-60.36163,7.83345],[-60.53467,7.81713],[-60.5896,7.6375],[-60.72144,7.54493],[-60.5896,7.31888],[-60.63904,7.24532],[-60.54703,7.12542],[-60.46875,7.20309],[-60.37262,7.18401],[-60.29984,7.1445],[-60.2916,7.06819],[-60.39871,6.95097],[-60.66513,6.83235],[-60.71869,6.75053],[-60.91232,6.81735],[-60.94254,6.72053],[-61.14441,6.72326],[-61.23093,6.5773],[-61.1554,6.45314],[-61.14441,6.20199],[-61.39709,5.95619],[-60.71045,5.20036],[-60.21606,5.23319],[-59.99634,5.06906],[-60.13916,4.51071],[-59.69971,4.40118],[-59.5459,3.93002],[-59.87549,3.56825],[-59.7876,3.37086],[-60.01831,2.83332],[-59.90845,2.38335],[-59.69971,2.2626],[-59.77661,1.87833],[-59.65302,1.85087],[-59.69147,1.75754],[-59.61456,1.71361],[-59.55139,1.73283],[-59.36188,1.49123],[-59.26575,1.39238],[-58.92242,1.30726],[-58.83728,1.17271],[-58.71918,1.23037],[-58.71094,1.29902],[-58.49121,1.26058],[-58.461,1.37591],[-58.50494,1.38689],[-58.51044,1.46102],[-58.38135,1.4775],[-58.32642,1.57359],[-58.00507,1.49946],[-57.99133,1.65321],[-57.79907,1.69165],[-57.70844,1.71087],[-57.54364,1.68341],[-57.41455,1.94421],[-57.10693,1.97715],[-56.8103,1.85636],[-56.48071,1.92225],[-55.90942,1.81244],[-55.90942,2.04302],[-56.14014,2.26534],[-55.94788,2.53701],[-55.70892,2.39981],[-55.37933,2.43274],[-55.19257,2.53976],[-54.98108,2.57268],[-54.88495,2.43548],[-54.71191,2.46293],[-54.69543,2.34767],[-54.58832,2.32846],[-54.43451,2.43548],[-54.20654,2.76748],[-54.17358,3.12955],[-53.96484,3.57921],[-54.33838,4.00674],[-54.44412,4.52577],[-54.46884,4.91036],[-54.36653,5.13061],[-54.27727,5.26191],[-54.19968,5.3084],[-54.01222,5.54457],[-54.0239,5.64605],[-53.86322,5.94936],[-64.33594,32.86113]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-14.5,-6],[11.79657,-17.27197],[12.03415,-17.14866],[12.38159,-17.22213],[12.58484,-17.22476],[13.01193,-16.97405],[13.24951,-17.00098],[13.38135,-16.98522],[13.93341,-17.38734],[18.42476,-17.38996],[18.47763,-17.46857],[18.62663,-17.64599],[18.79211,-17.76177],[18.92944,-17.82061],[19.33044,-17.84806],[19.66278,-17.8644],[19.74792,-17.90557],[19.85161,-17.87486],[20.10361,-17.90296],[20.18394,-17.88401],[20.34737,-17.88466],[20.44693,-17.91733],[20.51697,-17.96698],[20.83008,-18.03032],[20.95711,-17.97285],[21.16997,-17.93497],[21.42677,-18.0264],[23.45032,-17.63879],[22.00012,-16.38866],[21.99944,-13.00523],[24.03809,-12.99118],[24.03809,-10.91962],[24.43359,-11.09217],[24.45557,-11.48002],[25.37842,-11.19996],[25.42236,-11.60919],[26.96045,-11.97484],[27.18018,-11.60919],[28.125,-12.42048],[29.11377,-13.36824],[29.1687,-13.43771],[29.55872,-13.19716],[29.68506,-13.2239],[29.62463,-13.41099],[29.80591,-13.44305],[29.81415,-12.14809],[29.31152,-12.55456],[28.41064,-11.78133],[28.63037,-10.70379],[28.65234,-9.73071],[28.37219,-9.24309],[28.89748,-8.47916],[30.78644,-8.26857],[29.39941,-6.05316],[29.4873,-4.45595],[29.75922,-4.46759],[29.81415,-4.36421],[29.88007,-4.36832],[30.04074,-4.26699],[30.07919,-4.1629],[30.18356,-4.08311],[30.1918,-4.05126],[30.21566,-4.04595],[30.22923,-4.01136],[30.21326,-3.99612],[30.25978,-3.88755],[30.29274,-3.86288],[30.34424,-3.77245],[30.39848,-3.79095],[30.40878,-3.76765],[30.39548,-3.7304],[30.39054,-3.72821],[30.3896,-3.71918],[30.39093,-3.7101],[30.39514,-3.70444],[30.42028,-3.64963],[30.46886,-3.53501],[30.67108,-3.41335],[30.63297,-3.34892],[30.84206,-3.25535],[30.84549,-3.16108],[30.83485,-3.09698],[30.7933,-3.06235],[30.82111,-3.02258],[30.84515,-2.9739],[30.74764,-2.99618],[30.7037,-2.97013],[30.66422,-2.98967],[30.57632,-2.90738],[30.49393,-2.94441],[30.41016,-2.87172],[30.52002,-2.39432],[30.77545,-2.38883],[30.8606,-2.31199],[30.84961,-2.19398],[30.89081,-2.07322],[30.81116,-1.96068],[30.83862,-1.6587],[30.73425,-1.4418],[30.56259,-1.33884],[30.4541,-1.05737],[30.35797,-1.06287],[30.34149,-1.13152],[30.16571,-1.34296],[29.91852,-1.48024],[29.83887,-1.31824],[29.58344,-1.39238],[29.729,0.05493],[29.96796,0.5136],[29.9707,0.8569],[30.22339,0.92281],[30.24536,1.15349],[30.47745,1.20772],[31.30966,2.15693],[31.20255,2.22211],[31.20255,2.29278],[31.16409,2.27906],[31.13937,2.28318],[31.13113,2.26534],[31.07826,2.30033],[31.0714,2.34767],[31.00479,2.4005],[30.97183,2.40461],[30.94711,2.38746],[30.94849,2.36276],[30.9375,2.33532],[30.88531,2.34012],[30.83038,2.42176],[30.74112,2.43274],[30.76035,2.5864],[30.90179,2.88132],[30.76447,3.04178],[30.93613,3.40239],[30.94059,3.50588],[30.85236,3.48601],[30.90866,3.5936],[30.95055,3.63918],[30.94677,3.65391],[30.9866,3.70187],[31.00582,3.70701],[31.02058,3.69708],[31.16547,3.7954],[31.28838,3.79643],[31.52699,3.66282],[31.7038,3.72449],[31.82671,3.82794],[31.96198,3.65596],[31.95854,3.57099],[32.04987,3.59155],[32.07733,3.57099],[32.0842,3.53672],[32.20093,3.50657],[32.21672,3.56448],[32.19578,3.59977],[32.41516,3.74504],[32.72055,3.76782],[32.89307,3.81219],[33.02782,3.89371],[33.18146,3.7793],[33.51173,3.75258],[33.98758,4.23309],[34.05762,4.28342],[34.38721,4.61065],[35.94452,4.62023],[35.95688,4.53467],[36.04134,4.44568],[36.89621,4.4491],[38.14728,3.62992],[38.55927,3.62033],[38.92181,3.51068],[39.56039,3.43392],[39.87076,3.87522],[40.76752,4.28753],[41.16371,3.94372],[41.89774,3.97797],[41.31271,3.14463],[40.98896,2.82869],[40.99548,-0.84042],[41.7,-1.8],[41.7,-49],[-27,-60],[-65.7,-52.5],[-14.5,-6]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[31.33301,35.47856],[33.0249,33.75175],[35.44189,36.02245],[31.33301,35.47856]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[14,36.5],[15,36],[14,35],[14,36.5]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[0,62],[2.5,51.3],[-2,50],[-1.9,49],[-20,53],[0,62]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[180,-35],[161,-19],[167,-12],[180,-22],[180,4],[170,3.7],[127,5.7],[118,2.7],[119.5,5.4],[117.2,7.5],[102.6,8],[102.9158,11.74099],[102.76268,12.07357],[102.70226,12.17158],[102.74139,12.46474],[102.53128,12.68857],[102.49557,12.9256],[102.49763,13.0064],[102.4597,13.08199],[102.43412,13.09026],[102.39155,13.16407],[102.35481,13.29341],[102.35893,13.30945],[102.34503,13.34837],[102.35928,13.39797],[102.3567,13.48095],[102.36168,13.50582],[102.33559,13.53787],[102.33971,13.56023],[102.35498,13.5649],[102.36511,13.5785],[102.40047,13.5679],[102.42537,13.56891],[102.44614,13.56123],[102.48047,13.57091],[102.53849,13.56757],[102.5699,13.58526],[102.57806,13.60486],[102.62501,13.60845],[102.62132,13.61295],[102.60767,13.61562],[102.57231,13.63331],[102.56922,13.64082],[102.54879,13.658],[102.56252,13.68552],[102.5972,13.70803],[102.67084,13.74472],[102.68818,13.75172],[102.7014,13.7684],[102.73161,13.77082],[102.76543,13.85541],[102.78397,13.93207],[102.80388,13.94406],[102.81607,13.96639],[102.90705,14.02119],[102.89726,14.0535],[102.90095,14.0838],[102.92421,14.10744],[102.92378,14.12838],[102.94147,14.15035],[102.92953,14.17952],[103.17535,14.33774],[103.19939,14.32992],[103.68553,14.44],[103.94508,14.34157],[104.05756,14.34589],[104.06636,14.3419],[104.26025,14.37749],[104.50058,14.36984],[104.57817,14.36019],[104.6422,14.42387],[104.66632,14.40234],[104.68357,14.39877],[104.71138,14.43169],[104.72305,14.42188],[104.71687,14.40043],[104.75344,14.40459],[104.80408,14.43867],[104.83429,14.41573],[104.99239,14.3838],[105.05402,14.19783],[105.47905,14.49186],[105.60883,15.0005],[105.46703,15.13005],[105.48866,15.20237],[105.59269,15.2716],[105.58617,15.32823],[105.50308,15.31912],[105.46703,15.33948],[105.49175,15.37921],[105.59372,15.42869],[105.59372,15.50927],[105.60986,15.54871],[105.62616,15.56492],[105.62702,15.59129],[105.63518,15.62742],[105.63612,15.66056],[105.5975,15.72088],[105.49965,15.76681],[105.46291,15.74517],[105.43819,15.75459],[105.40489,15.79424],[105.34241,15.92039],[105.37811,15.98344],[105.39167,15.99136],[105.41931,15.98608],[105.42652,15.99764],[105.41468,16.01661],[105.21263,16.05076],[105.04955,16.10552],[105.01316,16.24401],[104.88235,16.37812],[104.8391,16.45782],[104.77936,16.49041],[104.73919,16.53287],[104.74228,16.62205],[104.76391,16.70953],[104.73953,16.80323],[104.76425,16.85088],[104.73782,16.90968],[104.744,17.0128],[104.81266,17.21853],[104.79841,17.39274],[104.70348,17.52833],[104.46384,17.65515],[104.34368,17.83564],[104.27776,17.8559],[104.22661,17.98069],[104.1116,18.10735],[104.06525,18.21174],[103.97392,18.33823],[103.9286,18.33237],[103.88809,18.29456],[103.85582,18.28673],[103.83659,18.32715],[103.79128,18.3467],[103.70201,18.34214],[103.60931,18.40405],[103.57292,18.40437],[103.51593,18.42978],[103.45963,18.42587],[103.41568,18.44802],[103.30479,18.43206],[103.24265,18.37082],[103.24333,18.34133],[103.29123,18.32357],[103.28899,18.29521],[103.23595,18.28299],[103.16608,18.25511],[103.02429,17.98135],[102.6535,17.83237],[102.40631,17.99963],[102.10968,18.22413],[101.548,17.81538],[101.30493,17.64991],[101.14563,17.46595],[100.95886,17.61654],[101.01757,17.88858],[101.18752,18.05121],[101.16863,18.10409],[101.18134,18.33595],[101.08727,18.38287],[101.05499,18.43988],[101.23215,18.73015],[101.35265,19.04524],[101.25927,19.12733],[101.2373,19.32637],[101.25824,19.58438],[101.11954,19.56836],[101.08898,19.58777],[101.08624,19.59715],[101.03165,19.6185],[100.89844,19.62125],[100.77827,19.49249],[100.63751,19.56432],[100.58258,19.49313],[100.47478,19.5944],[100.42929,19.67152],[100.43341,19.7024],[100.4147,19.7255],[100.40525,19.7646],[100.43907,19.80345],[100.45555,19.84843],[100.50636,19.87264],[100.51709,19.93027],[100.58653,20.1599],[100.56576,20.1757],[100.54945,20.17473],[100.52731,20.14379],[100.51065,20.14895],[100.48697,20.17956],[100.46774,20.196],[100.45246,20.20147],[100.45521,20.22129],[100.44783,20.23546],[100.41607,20.25286],[100.40594,20.28184],[100.38397,20.31082],[100.37556,20.35187],[100.36165,20.35638],[100.35736,20.37408],[100.33195,20.39902],[100.27805,20.40224],[100.25917,20.39677],[100.2475,20.37263],[100.22535,20.35509],[100.22346,20.31839],[100.16579,20.29988],[100.17162,20.24545],[100.10845,20.25221],[100.09266,20.2696],[100.09798,20.31485],[100.07961,20.3678],[99.9567,20.46417],[99.91636,20.44925],[99.90765,20.44977],[99.89121,20.44511],[99.87276,20.44406],[99.86212,20.44326],[99.80186,20.33948],[99.46472,20.3884],[99.56085,20.20035],[99.43691,20.08882],[99.27727,20.11623],[99.06921,20.1101],[98.97789,19.74538],[98.24387,19.68656],[97.85934,19.57014],[97.76733,18.57336],[97.39655,18.47179],[97.62451,18.30238],[97.73849,17.97743],[97.66502,17.87943],[97.90947,17.56745],[98.52951,16.82557],[98.51303,16.69276],[98.69293,16.26873],[98.87421,16.43609],[98.93394,16.3353],[98.84743,16.13356],[98.74512,16.12037],[98.58307,16.07287],[98.5762,15.79754],[98.54736,15.37557],[98.17383,15.15167],[98.3606,14.63674],[99.08295,13.89208],[99.16534,13.72204],[99.18182,13.00723],[99.39331,12.56797],[99.64153,11.78973],[99.32156,11.30266],[98.77859,10.67849],[98.80597,10.47642],[98.76657,10.40459],[98.74924,10.34194],[96.85547,6.40265],[92.42523,20.54794],[92.2728,20.96272],[92.187,21.16],[92.26,21.36],[92.27,21.4328],[92.62,21.43],[92.6,22],[93.22,22.25],[93.4,23.7],[93.34,23.95],[94.155,23.847],[94.17,23.92],[94.25171,24.07405],[94.28,24.23],[94.30175,24.2371],[94.3256,24.2731],[94.6,24.7],[94.78,25.47],[95.2,26],[95.1,26.6],[97.3,27.9],[96.14,29.38],[95.4,29.1],[94.8,29.2],[92.5,27.8],[91.64,27.76],[91.4,28],[89.58,28.18],[88.9,27.32],[88.74,27.47],[88.9,27.86],[88.7,28.1],[88.1,27.87],[85.93,27.942],[81.6,30.5],[81.2,30],[78.73,31.5],[78.77,31.99],[78.4,32.5],[79.3,32.5],[79,34.3],[78.3,34.6],[78,35.5],[76.1,35.8],[76,36.55],[75.15,37],[72.5,36.9],[71.1,36.1],[71.65,35.44],[71.45,35],[70.985,34.54],[71.18,34.36],[71.092,34.118],[70.88,33.97],[70.5,33.94],[69.908,34.04],[69.869,33.96],[70,33.75],[70.13,33.73],[70.34,33.34],[70.013,33.14],[69.57,33.09],[69.24,32.45],[69.3,31.9],[68.1,31.6],[66.393,30.934],[66.2,29.8],[62.5,29.4],[60.87,29.86],[61.53,29.0165],[61.66,28.77],[61.96,28.54],[62.43,28.42],[62.6,28.25],[62.795,28.28],[62.86,27.25],[63.24,27.25],[63.327,27.13],[63.25,27.1],[63.25,26.84],[63.18,26.83],[63.18,26.65],[62.3,26.5],[62.2,26.28],[61.85,26.22],[61.84,25.75],[61.68,25.67],[56.5,-21],[180,-65],[180,-35]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[138.7,46.7],[145.5,44.5],[145.2,43.7],[146,43.3],[142,18],[122,24.3],[138.7,46.7]]]}},{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-180,7],[-148,7],[-151,-12],[-171.5,-10.75],[-171,-16],[-152,-19],[-180,-55],[-180,7]]]}}];
18618 var dataDriveLeft = {
18619         type: type$1,
18620         features: features$1
18621 };
18622
18623 var en = {"modes":{"add_area":{"title":"Area","description":"Add parks, buildings, lakes or other areas to the map.","tail":"Click on the map to start drawing an area, like a park, lake, or building."},"add_line":{"title":"Line","description":"Add highways, streets, pedestrian paths, canals or other lines to the map.","tail":"Click on the map to start drawing a road, path, or route."},"add_point":{"title":"Point","description":"Add restaurants, monuments, postal boxes or other points to the map.","tail":"Click on the map to add a point."},"browse":{"title":"Browse","description":"Pan and zoom the map."},"draw_area":{"tail":"Click to add nodes to your area. Click the first node to finish the area."},"draw_line":{"tail":"Click to add more nodes to the line. Click on other lines to connect to them, and double-click to end the line."}},"operations":{"add":{"annotation":{"point":"Added a point.","vertex":"Added a node to a way.","relation":"Added a relation."}},"start":{"annotation":{"line":"Started a line.","area":"Started an area."}},"continue":{"key":"A","title":"Continue","description":"Continue this line.","not_eligible":"No line can be continued here.","multiple":"Several lines can be continued here. To choose a line, press the Shift key and click on it to select it.","annotation":{"line":"Continued a line.","area":"Continued an area."}},"cancel_draw":{"annotation":"Canceled drawing."},"change_role":{"annotation":"Changed the role of a relation member."},"change_tags":{"annotation":"Changed tags."},"circularize":{"title":"Circularize","description":{"line":"Make this line circular.","area":"Make this area circular."},"key":"O","annotation":{"line":"Made a line circular.","area":"Made an area circular."},"not_closed":"This can't be made circular because it's not a loop.","too_large":"This can't be made circular because not enough of it is currently visible.","connected_to_hidden":"This can't be made circular because it is connected to a hidden feature."},"orthogonalize":{"title":"Square","description":{"line":"Square the corners of this line.","area":"Square the corners of this area."},"key":"S","annotation":{"line":"Squared the corners of a line.","area":"Squared the corners of an area."},"not_squarish":"This can't be made square because it is not squarish.","too_large":"This can't be made square because not enough of it is currently visible.","connected_to_hidden":"This can't be made square because it is connected to a hidden feature."},"straighten":{"title":"Straighten","description":"Straighten this line.","key":"S","annotation":"Straightened a line.","too_bendy":"This can't be straightened because it bends too much.","connected_to_hidden":"This line can't be straightened because it is connected to a hidden feature."},"delete":{"title":"Delete","description":{"single":"Delete this feature permanently.","multiple":"Delete these features permanently."},"annotation":{"point":"Deleted a point.","vertex":"Deleted a node from a way.","line":"Deleted a line.","area":"Deleted an area.","relation":"Deleted a relation.","multiple":"Deleted {n} features."},"too_large":{"single":"This feature can't be deleted because not enough of it is currently visible.","multiple":"These features can't be deleted because not enough of them are currently visible."},"incomplete_relation":{"single":"This feature can't be deleted because it hasn't been fully downloaded.","multiple":"These features can't be deleted because they haven't been fully downloaded."},"part_of_relation":{"single":"This feature can't be deleted because it is part of a larger relation. You must remove it from the relation first.","multiple":"These features can't be deleted because they are part of larger relations. You must remove them from the relations first."},"connected_to_hidden":{"single":"This feature can't be deleted because it is connected to a hidden feature.","multiple":"These features can't be deleted because some are connected to hidden features."}},"add_member":{"annotation":"Added a member to a relation."},"delete_member":{"annotation":"Removed a member from a relation."},"connect":{"annotation":{"point":"Connected a way to a point.","vertex":"Connected a way to another.","line":"Connected a way to a line.","area":"Connected a way to an area."}},"disconnect":{"title":"Disconnect","description":"Disconnect these lines/areas from each other.","key":"D","annotation":"Disconnected lines/areas.","not_connected":"There aren't enough lines/areas here to disconnect.","connected_to_hidden":"This can't be disconnected because it is connected to a hidden feature.","relation":"This can't be disconnected because it connects members of a relation."},"merge":{"title":"Merge","description":"Merge these features.","key":"C","annotation":"Merged {n} features.","not_eligible":"These features can't be merged.","not_adjacent":"These features can't be merged because their endpoints aren't connected.","restriction":"These features can't be merged because at least one is a member of a \"{relation}\" relation.","incomplete_relation":"These features can't be merged because at least one hasn't been fully downloaded.","conflicting_tags":"These features can't be merged because some of their tags have conflicting values."},"move":{"title":"Move","description":{"single":"Move this feature to a different location.","multiple":"Move these features to a different location."},"key":"M","annotation":{"point":"Moved a point.","vertex":"Moved a node in a way.","line":"Moved a line.","area":"Moved an area.","multiple":"Moved multiple features."},"incomplete_relation":{"single":"This feature can't be moved because it hasn't been fully downloaded.","multiple":"These features can't be moved because they haven't been fully downloaded."},"too_large":{"single":"This feature can't be moved because not enough of it is currently visible.","multiple":"These features can't be moved because not enough of them are currently visible."},"connected_to_hidden":{"single":"This feature can't be moved because it is connected to a hidden feature.","multiple":"These features can't be moved because some are connected to hidden features."}},"reflect":{"title":{"long":"Reflect Long","short":"Reflect Short"},"description":{"long":{"single":"Reflect this feature across its long axis.","multiple":"Reflect these features across their long axis."},"short":{"single":"Reflect this feature across its short axis.","multiple":"Reflect these features across their short axis."}},"key":{"long":"T","short":"Y"},"annotation":{"long":{"single":"Reflected a feature across its long axis.","multiple":"Reflected multiple features across their long axis."},"short":{"single":"Reflected a feature across its short axis.","multiple":"Reflected multiple features across their short axis."}},"incomplete_relation":{"single":"This feature can't be reflected because it hasn't been fully downloaded.","multiple":"These features can't be reflected because they haven't been fully downloaded."},"too_large":{"single":"This feature can't be reflected because not enough of it is currently visible.","multiple":"These features can't be reflected because not enough of them are currently visible."},"connected_to_hidden":{"single":"This feature can't be reflected because it is connected to a hidden feature.","multiple":"These features can't be reflected because some are connected to hidden features."}},"rotate":{"title":"Rotate","description":{"single":"Rotate this feature around its center point.","multiple":"Rotate these features around their center point."},"key":"R","annotation":{"line":"Rotated a line.","area":"Rotated an area.","multiple":"Rotated multiple features."},"incomplete_relation":{"single":"This feature can't be rotated because it hasn't been fully downloaded.","multiple":"These features can't be rotated because they haven't been fully downloaded."},"too_large":{"single":"This feature can't be rotated because not enough of it is currently visible.","multiple":"These features can't be rotated because not enough of them are currently visible."},"connected_to_hidden":{"single":"This feature can't be rotated because it is connected to a hidden feature.","multiple":"These features can't be rotated because some are connected to hidden features."}},"reverse":{"title":"Reverse","description":"Make this line go in the opposite direction.","key":"V","annotation":"Reversed a line."},"split":{"title":"Split","description":{"line":"Split this line into two at this node.","area":"Split the boundary of this area into two.","multiple":"Split the lines/area boundaries at this node into two."},"key":"X","annotation":{"line":"Split a line.","area":"Split an area boundary.","multiple":"Split {n} lines/area boundaries."},"not_eligible":"Lines can't be split at their beginning or end.","multiple_ways":"There are too many lines here to split.","connected_to_hidden":"This can't be split because it is connected to a hidden feature."},"restriction":{"help":{"select":"Click to select a road segment.","toggle":"Click to toggle turn restrictions.","toggle_on":"Click to add a \"{restriction}\" restriction.","toggle_off":"Click to remove the \"{restriction}\" restriction."},"annotation":{"create":"Added a turn restriction","delete":"Deleted a turn restriction"}}},"undo":{"tooltip":"Undo: {action}","nothing":"Nothing to undo."},"redo":{"tooltip":"Redo: {action}","nothing":"Nothing to redo."},"tooltip_keyhint":"Shortcut:","browser_notice":"This editor is supported in Firefox, Chrome, Safari, Opera, and Internet Explorer 11 and above. Please upgrade your browser or use Potlatch 2 to edit the map.","translate":{"translate":"Translate","localized_translation_label":"Multilingual name","localized_translation_language":"Choose language","localized_translation_name":"Name"},"zoom_in_edit":"Zoom in to Edit","login":"login","logout":"logout","loading_auth":"Connecting to OpenStreetMap...","report_a_bug":"Report a bug","help_translate":"Help translate","feature_info":{"hidden_warning":"{count} hidden features","hidden_details":"These features are currently hidden: {details}"},"status":{"error":"Unable to connect to API.","offline":"The API is offline. Please try editing later.","readonly":"The API is read-only. You will need to wait to save your changes.","rateLimit":"The API is limiting anonymous connections.  You can fix this by logging in."},"commit":{"title":"Upload to OpenStreetMap","description_placeholder":"Brief description of your contributions (required)","message_label":"Changeset Comment","upload_explanation":"The changes you upload will be visible on all maps that use OpenStreetMap data.","upload_explanation_with_user":"The changes you upload as {user} will be visible on all maps that use OpenStreetMap data.","save":"Upload","cancel":"Cancel","changes":"{count} Changes","warnings":"Warnings","modified":"Modified","deleted":"Deleted","created":"Created","about_changeset_comments":"About changeset comments","about_changeset_comments_link":"//wiki.openstreetmap.org/wiki/Good_changeset_comments","google_warning":"You mentioned Google in this comment: remember that copying from Google Maps is strictly forbidden.","google_warning_link":"http://www.openstreetmap.org/copyright"},"contributors":{"list":"Edits by {users}","truncated_list":"Edits by {users} and {count} others"},"infobox":{"selected":"{n} selected","geometry":"Geometry","closed":"closed","center":"Center","perimeter":"Perimeter","length":"Length","area":"Area","centroid":"Centroid","location":"Location","metric":"Metric","imperial":"Imperial"},"geometry":{"point":"point","vertex":"vertex","line":"line","area":"area","relation":"relation"},"geocoder":{"search":"Search worldwide...","no_results_visible":"No results in visible map area","no_results_worldwide":"No results found"},"geolocate":{"title":"Show My Location","locating":"Locating, please wait..."},"inspector":{"no_documentation_combination":"There is no documentation available for this tag combination","no_documentation_key":"There is no documentation available for this key","documentation_redirect":"This documentation has been redirected to a new page","show_more":"Show More","view_on_osm":"View on openstreetmap.org","all_fields":"All fields","all_tags":"All tags","all_members":"All members","all_relations":"All relations","new_relation":"New relation...","role":"Role","choose":"Select feature type","results":"{n} results for {search}","reference":"View on OpenStreetMap Wiki","back_tooltip":"Change feature","remove":"Remove","search":"Search","multiselect":"Selected features","unknown":"Unknown","incomplete":"<not downloaded>","feature_list":"Search features","edit":"Edit feature","check":{"yes":"Yes","no":"No","reverser":"Change Direction"},"radio":{"structure":{"type":"Type","default":"Default","layer":"Layer"}},"add":"Add","none":"None","node":"Node","way":"Way","relation":"Relation","location":"Location","add_fields":"Add field:"},"background":{"title":"Background","description":"Background settings","percent_brightness":"{opacity}% brightness","none":"None","best_imagery":"Best known imagery source for this location","switch":"Switch back to this background","custom":"Custom","custom_button":"Edit custom background","custom_prompt":"Enter a tile URL template. Valid tokens are {zoom}, {x}, {y} for Z/X/Y scheme and {u} for quadtile scheme.","fix_misalignment":"Adjust imagery offset","imagery_source_faq":"Where does this imagery come from?","reset":"reset","offset":"Drag anywhere in the gray area below to adjust the imagery offset, or enter the offset values in meters.","minimap":{"description":"Minimap","tooltip":"Show a zoomed out map to help locate the area currently displayed."}},"map_data":{"title":"Map Data","description":"Map Data","data_layers":"Data Layers","fill_area":"Fill Areas","map_features":"Map Features","autohidden":"These features have been automatically hidden because too many would be shown on the screen.  You can zoom in to edit them."},"feature":{"points":{"description":"Points","tooltip":"Points of Interest"},"traffic_roads":{"description":"Traffic Roads","tooltip":"Highways, Streets, etc."},"service_roads":{"description":"Service Roads","tooltip":"Service Roads, Parking Aisles, Tracks, etc."},"paths":{"description":"Paths","tooltip":"Sidewalks, Foot Paths, Cycle Paths, etc."},"buildings":{"description":"Buildings","tooltip":"Buildings, Shelters, Garages, etc."},"landuse":{"description":"Landuse Features","tooltip":"Forests, Farmland, Parks, Residential, Commercial, etc."},"boundaries":{"description":"Boundaries","tooltip":"Administrative Boundaries"},"water":{"description":"Water Features","tooltip":"Rivers, Lakes, Ponds, Basins, etc."},"rail":{"description":"Rail Features","tooltip":"Railways"},"power":{"description":"Power Features","tooltip":"Power Lines, Power Plants, Substations, etc."},"past_future":{"description":"Past/Future","tooltip":"Proposed, Construction, Abandoned, Demolished, etc."},"others":{"description":"Others","tooltip":"Everything Else"}},"area_fill":{"wireframe":{"description":"No Fill (Wireframe)","tooltip":"Enabling wireframe mode makes it easy to see the background imagery."},"partial":{"description":"Partial Fill","tooltip":"Areas are drawn with fill only around their inner edges. (Recommended for beginner mappers)"},"full":{"description":"Full Fill","tooltip":"Areas are drawn fully filled."}},"restore":{"heading":"You have unsaved changes","description":"Do you wish to restore unsaved changes from a previous editing session?","restore":"Restore","reset":"Reset"},"save":{"title":"Save","help":"Review your changes and upload them to OpenStreetMap, making them visible to other users.","no_changes":"No changes to save.","error":"Errors occurred while trying to save","status_code":"Server returned status code {code}","unknown_error_details":"Please ensure you are connected to the internet.","uploading":"Uploading changes to OpenStreetMap...","unsaved_changes":"You have unsaved changes","conflict":{"header":"Resolve conflicting edits","count":"Conflict {num} of {total}","previous":"< Previous","next":"Next >","keep_local":"Keep mine","keep_remote":"Use theirs","restore":"Restore","delete":"Leave Deleted","download_changes":"Or download your changes.","done":"All conflicts resolved!","help":"Another user changed some of the same map features you changed.\nClick on each feature below for more details about the conflict, and choose whether to keep\nyour changes or the other user's changes.\n"}},"merge_remote_changes":{"conflict":{"deleted":"This feature has been deleted by {user}.","location":"This feature was moved by both you and {user}.","nodelist":"Nodes were changed by both you and {user}.","memberlist":"Relation members were changed by both you and {user}.","tags":"You changed the <b>{tag}</b> tag to \"{local}\" and {user} changed it to \"{remote}\"."}},"success":{"edited_osm":"Edited OSM!","just_edited":"You just edited OpenStreetMap!","view_on_osm":"View on OSM","facebook":"Share on Facebook","twitter":"Share on Twitter","google":"Share on Google+","help_html":"Your changes should appear in the \"Standard\" layer in a few minutes. Other layers, and certain features, may take longer.","help_link_text":"Details","help_link_url":"https://wiki.openstreetmap.org/wiki/FAQ#I_have_just_made_some_changes_to_the_map._How_do_I_get_to_see_my_changes.3F"},"confirm":{"okay":"OK","cancel":"Cancel"},"splash":{"welcome":"Welcome to the iD OpenStreetMap editor","text":"iD is a friendly but powerful tool for contributing to the world's best free world map. This is version {version}. For more information see {website} and report bugs at {github}.","walkthrough":"Start the Walkthrough","start":"Edit Now"},"source_switch":{"live":"live","lose_changes":"You have unsaved changes. Switching the map server will discard them. Are you sure you want to switch servers?","dev":"dev"},"version":{"whats_new":"What's new in iD {version}"},"tag_reference":{"description":"Description","on_wiki":"{tag} on wiki.osm.org","used_with":"used with {type}"},"validations":{"disconnected_highway":"Disconnected highway","disconnected_highway_tooltip":"Roads should be connected to other roads or building entrances.","old_multipolygon":"Multipolygon tags on outer way","old_multipolygon_tooltip":"This style of multipolygon is deprecated. Please assign the tags to the parent multipolygon instead of the outer way.","untagged_point":"Untagged point","untagged_point_tooltip":"Select a feature type that describes what this point is.","untagged_line":"Untagged line","untagged_line_tooltip":"Select a feature type that describes what this line is.","untagged_area":"Untagged area","untagged_area_tooltip":"Select a feature type that describes what this area is.","untagged_relation":"Untagged relation","untagged_relation_tooltip":"Select a feature type that describes what this relation is.","many_deletions":"You're deleting {n} features. Are you sure you want to do this? This will delete them from the map that everyone else sees on openstreetmap.org.","tag_suggests_area":"The tag {tag} suggests line should be area, but it is not an area","deprecated_tags":"Deprecated tags: {tags}"},"zoom":{"in":"Zoom In","out":"Zoom Out"},"cannot_zoom":"Cannot zoom out further in current mode.","full_screen":"Toggle Full Screen","gpx":{"local_layer":"Local file","drag_drop":"Drag and drop a .gpx, .geojson or .kml file on the page, or click the button to the right to browse","zoom":"Zoom to layer","browse":"Browse for a file"},"mapillary_images":{"tooltip":"Street-level photos from Mapillary","title":"Photo Overlay (Mapillary)"},"mapillary_signs":{"tooltip":"Traffic signs from Mapillary (must enable Photo Overlay)","title":"Traffic Sign Overlay (Mapillary)"},"mapillary":{"view_on_mapillary":"View this image on Mapillary"},"help":{"title":"Help","help":"# Help\n\nThis is an editor for [OpenStreetMap](http://www.openstreetmap.org/), the\nfree and editable map of the world. You can use it to add and update\ndata in your area, making an open-source and open-data map of the world\nbetter for everyone.\n\nEdits that you make on this map will be visible to everyone who uses\nOpenStreetMap. In order to make an edit, you'll need to\n[log in](https://www.openstreetmap.org/login).\n\nThe [iD editor](http://ideditor.com/) is a collaborative project with [source\ncode available on GitHub](https://github.com/openstreetmap/iD).\n","editing_saving":"# Editing & Saving\n\nThis editor is designed to work primarily online, and you're accessing\nit through a website right now.\n\n### Selecting Features\n\nTo select a map feature, like a road or point of interest, click\non it on the map. This will highlight the selected feature, open a panel with\ndetails about it, and show a menu of things you can do with the feature.\n\nTo select multiple features, hold down the 'Shift' key. Then either click\non the features you want to select, or drag on the map to draw a rectangle.\nThis will draw a box and select all the points within it.\n\n### Saving Edits\n\nWhen you make changes like editing roads, buildings, and places, these are\nstored locally until you save them to the server. Don't worry if you make\na mistake - you can undo changes by clicking the undo button, and redo\nchanges by clicking the redo button.\n\nClick 'Save' to finish a group of edits - for instance, if you've completed\nan area of town and would like to start on a new area. You'll have a chance\nto review what you've done, and the editor supplies helpful suggestions\nand warnings if something doesn't seem right about the changes.\n\nIf everything looks good, you can enter a short comment explaining the change\nyou made, and click 'Save' again to post the changes\nto [OpenStreetMap.org](http://www.openstreetmap.org/), where they are visible\nto all other users and available for others to build and improve upon.\n\nIf you can't finish your edits in one sitting, you can leave the editor\nwindow and come back (on the same browser and computer), and the\neditor application will offer to restore your work.\n\n### Using the editor\n\nA list of available keyboard shortcuts can be found [here](http://wiki.openstreetmap.org/wiki/ID/Shortcuts).\n","roads":"# Roads\n\nYou can create, fix, and delete roads with this editor. Roads can be all\nkinds: paths, highways, trails, cycleways, and more - any often-crossed\nsegment should be mappable.\n\n### Selecting\n\nClick on a road to select it. An outline should become visible, along\nwith a small tools menu on the map and a sidebar showing more information\nabout the road.\n\n### Modifying\n\nOften you'll see roads that aren't aligned to the imagery behind them\nor to a GPS track. You can adjust these roads so they are in the correct\nplace.\n\nFirst click on the road you want to change. This will highlight it and show\ncontrol points along it that you can drag to better locations. If\nyou want to add new control points for more detail, double-click a part\nof the road without a node, and one will be added.\n\nIf the road connects to another road, but doesn't properly connect on\nthe map, you can drag one of its control points onto the other road in\norder to join them. Having roads connect is important for the map\nand essential for providing driving directions.\n\nYou can also click the 'Move' tool or press the `M` shortcut key to move the entire road at\none time, and then click again to save that movement.\n\n### Deleting\n\nIf a road is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the road could simply be newly built.\n\nYou can delete a road by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n\n### Creating\n\nFound somewhere there should be a road but there isn't? Click the 'Line'\nicon in the top-left of the editor or press the shortcut key `2` to start drawing\na line.\n\nClick on the start of the road on the map to start drawing. If the road\nbranches off from an existing road, start by clicking on the place where they connect.\n\nThen click on points along the road so that it follows the right path, according\nto satellite imagery or GPS. If the road you are drawing crosses another road, connect\nit by clicking on the intersection point. When you're done drawing, double-click\nor press 'Return' or 'Enter' on your keyboard.\n","gps":"# GPS\n\nCollected GPS traces are one valuable source of data for OpenStreetMap. This editor\nsupports local traces - `.gpx` files on your local computer. You can collect\nthis kind of GPS trace with a number of smartphone applications as well as\npersonal GPS hardware.\n\nFor information on how to perform a GPS survey, read\n[Mapping with a smartphone, GPS, or paper](http://learnosm.org/en/mobile-mapping/).\n\nTo use a GPX track for mapping, drag and drop the GPX file onto the map\neditor. If it's recognized, it will be added to the map as a bright purple\nline. Click on the 'Map Data' menu on the right side to enable,\ndisable, or zoom to this new GPX-powered layer.\n\nThe GPX track isn't directly uploaded to OpenStreetMap - the best way to\nuse it is to draw on the map, using it as a guide for the new features that\nyou add, and also to [upload it to OpenStreetMap](http://www.openstreetmap.org/trace/create)\nfor other users to use.\n","imagery":"# Imagery\n\nAerial imagery is an important resource for mapping. A combination of\nairplane flyovers, satellite views, and freely-compiled sources are available\nin the editor under the 'Background Settings' menu on the right.\n\nBy default a [Bing Maps](http://www.bing.com/maps/) satellite layer is\npresented in the editor, but as you pan and zoom the map to new geographical\nareas, new sources will become available. Some countries, like the United\nStates, France, and Denmark have very high-quality imagery available for some areas.\n\nImagery is sometimes offset from the map data because of a mistake on the\nimagery provider's side. If you see a lot of roads shifted from the background,\ndon't immediately move them all to match the background. Instead you can adjust\nthe imagery so that it matches the existing data by clicking 'Fix alignment' at\nthe bottom of the Background Settings UI.\n","addresses":"# Addresses\n\nAddresses are some of the most useful information for the map.\n\nAlthough addresses are often represented as parts of streets, in OpenStreetMap\nthey're recorded as attributes of buildings and places along streets.\n\nYou can add address information to places mapped as building outlines\nas well as those mapped as single points. The optimal source of address\ndata is from an on-the-ground survey or personal knowledge - as with any\nother feature, copying from commercial sources like Google Maps is strictly\nforbidden.\n","inspector":"# Using the Inspector\n\nThe inspector is the section on the left side of the page that allows you to\nedit the details of the selected feature.\n\n### Selecting a Feature Type\n\nAfter you add a point, line, or area, you can choose what type of feature it\nis, like whether it's a highway or residential road, supermarket or cafe.\nThe inspector will display buttons for common feature types, and you can\nfind others by typing what you're looking for in the search box.\n\nClick the 'i' in the bottom-right-hand corner of a feature type button to\nlearn more about it. Click a button to choose that type.\n\n### Using Forms and Editing Tags\n\nAfter you choose a feature type, or when you select a feature that already\nhas a type assigned, the inspector will display fields with details about\nthe feature like its name and address.\n\nBelow the fields you see, you can click the 'Add field' dropdown to add\nother details, like a Wikipedia link, wheelchair access, and more.\n\nAt the bottom of the inspector, click 'Additional tags' to add arbitrary\nother tags to the element. [Taginfo](http://taginfo.openstreetmap.org/) is a\ngreat resource for learn more about popular tag combinations.\n\nChanges you make in the inspector are automatically applied to the map.\nYou can undo them at any time by clicking the 'Undo' button.\n","buildings":"# Buildings\n\nOpenStreetMap is the world's largest database of buildings. You can create\nand improve this database.\n\n### Selecting\n\nYou can select a building by clicking on its border. This will highlight the\nbuilding and open a small tools menu and a sidebar showing more information\nabout the building.\n\n### Modifying\n\nSometimes buildings are incorrectly placed or have incorrect tags.\n\nTo move an entire building, select it, then click the 'Move' tool. Move your\nmouse to shift the building, and click when it's correctly placed.\n\nTo fix the specific shape of a building, click and drag the nodes that form\nits border into better places.\n\n### Creating\n\nOne of the main questions around adding buildings to the map is that\nOpenStreetMap records buildings both as shapes and points. The rule of thumb\nis to _map a building as a shape whenever possible_, and map companies, homes,\namenities, and other things that operate out of buildings as points placed\nwithin the building shape.\n\nStart drawing a building as a shape by clicking the 'Area' button in the top\nleft of the interface, and end it either by pressing 'Return' on your keyboard\nor clicking on the first node drawn to close the shape.\n\n### Deleting\n\nIf a building is entirely incorrect - you can see that it doesn't exist in satellite\nimagery and ideally have confirmed locally that it's not present - you can delete\nit, which removes it from the map. Be cautious when deleting features -\nlike any other edit, the results are seen by everyone and satellite imagery\nis often out of date, so the building could simply be newly built.\n\nYou can delete a building by clicking on it to select it, then clicking the\ntrash can icon or pressing the 'Delete' key.\n","relations":"# Relations\n\nA relation is a special type of feature in OpenStreetMap that groups together\nother features. For example, two common types of relations are *route relations*,\nwhich group together sections of road that belong to a specific freeway or\nhighway, and *multipolygons*, which group together several lines that define\na complex area (one with several pieces or holes in it like a donut).\n\nThe group of features in a relation are called *members*. In the sidebar, you can\nsee which relations a feature is a member of, and click on a relation there\nto select the it. When the relation is selected, you can see all of its\nmembers listed in the sidebar and highlighted on the map.\n\nFor the most part, iD will take care of maintaining relations automatically\nwhile you edit. The main thing you should be aware of is that if you delete a\nsection of road to redraw it more accurately, you should make sure that the\nnew section is a member of the same relations as the original.\n\n## Editing Relations\n\nIf you want to edit relations, here are the basics.\n\nTo add a feature to a relation, select the feature, click the \"+\" button in the\n\"All relations\" section of the sidebar, and select or type the name of the relation.\n\nTo create a new relation, select the first feature that should be a member,\nclick the \"+\" button in the \"All relations\" section, and select \"New relation...\".\n\nTo remove a feature from a relation, select the feature and click the trash\nbutton next to the relation you want to remove it from.\n\nYou can create multipolygons with holes using the \"Merge\" tool. Draw two areas (inner\nand outer), hold the Shift key and click on each of them to select them both, and then\nclick the \"Merge\" (+) button.\n"},"intro":{"done":"done","ok":"OK","graph":{"block_number":"<value for addr:block_number>","city":"Three Rivers","county":"<value for addr:county>","district":"<value for addr:district>","hamlet":"<value for addr:hamlet>","neighbourhood":"<value for addr:neighbourhood>","postcode":"49093","province":"<value for addr:province>","quarter":"<value for addr:quarter>","state":"MI","subdistrict":"<value for addr:subdistrict>","suburb":"<value for addr:suburb>","countrycode":"us","name":{"1st-avenue":"1st Avenue","2nd-avenue":"2nd Avenue","4th-avenue":"4th Avenue","5th-avenue":"5th Avenue","6th-avenue":"6th Avenue","6th-street":"6th Street","7th-avenue":"7th Avenue","8th-avenue":"8th Avenue","9th-avenue":"9th Avenue","10th-avenue":"10th Avenue","11th-avenue":"11th Avenue","12th-avenue":"12th Avenue","access-point-employment":"Access Point Employment","adams-street":"Adams Street","andrews-elementary-school":"Andrews Elementary School","andrews-street":"Andrews Street","armitage-street":"Armitage Street","barrows-school":"Barrows School","battle-street":"Battle Street","bennett-street":"Bennett Street","bowman-park":"Bowman Park","collins-drive":"Collins Drive","conrail-railroad":"Conrail Railroad","conservation-park":"Conservation Park","constantine-street":"Constantine Street","cushman-street":"Cushman Street","dollar-tree":"Dollar Tree","douglas-avenue":"Douglas Avenue","east-street":"East Street","elm-street":"Elm Street","flower-street":"Flower Street","foster-street":"Foster Street","french-street":"French Street","garden-street":"Garden Street","gem-pawnbroker":"Gem Pawnbroker","golden-finch-framing":"Golden Finch Framing","grant-avenue":"Grant Avenue","hoffman-pond":"Hoffman Pond","hoffman-street":"Hoffman Street","hook-avenue":"Hook Avenue","jefferson-street":"Jefferson Street","kelsey-street":"Kelsey Street","lafayette-park":"LaFayette Park","las-coffee-cafe":"L.A.'s Coffee Cafe","lincoln-avenue":"Lincoln Avenue","lowrys-books":"Lowry's Books","lynns-garage":"Lynn's Garage","main-street-barbell":"Main Street Barbell","main-street-cafe":"Main Street Cafe","main-street-fitness":"Main Street Fitness","main-street":"Main Street","maple-street":"Maple Street","marina-park":"Marina Park","market-street":"Market Street","memory-isle-park":"Memory Isle Park","memory-isle":"Memory Isle","michigan-avenue":"Michigan Avenue","middle-street":"Middle Street","millard-street":"Millard Street","moore-street":"Moore Street","morris-avenue":"Morris Avenue","mural-mall":"Mural Mall","paisanos-bar-and-grill":"Paisano's Bar and Grill","paisley-emporium":"Paisley Emporium","paparazzi-tattoo":"Paparazzi Tattoo","pealer-street":"Pealer Street","pine-street":"Pine Street","pizza-hut":"Pizza Hut","portage-avenue":"Portage Avenue","portage-river":"Portage River","preferred-insurance-services":"Preferred Insurance Services","railroad-drive":"Railroad Drive","river-city-appliance":"River City Appliance","river-drive":"River Drive","river-road":"River Road","river-street":"River Street","riverside-cemetery":"Riverside Cemetery","riverwalk-trail":"Riverwalk Trail","riviera-theatre":"Riviera Theatre","rocky-river":"Rocky River","saint-joseph-river":"Saint Joseph River","scidmore-park-petting-zoo":"Scidmore Park Petting Zoo","scidmore-park":"Scidmore Park","scouter-park":"Scouter Park","sherwin-williams":"Sherwin-Williams","south-street":"South Street","southern-michigan-bank":"Southern Michigan Bank","spring-street":"Spring Street","sturgeon-river-road":"Sturgeon River Road","three-rivers-city-hall":"Three Rivers City Hall","three-rivers-elementary-school":"Three Rivers Elementary School","three-rivers-fire-department":"Three Rivers Fire Department","three-rivers-high-school":"Three Rivers High School","three-rivers-middle-school":"Three Rivers Middle School","three-rivers-municipal-airport":"Three Rivers Municipal Airport","three-rivers-post-office":"Three Rivers Post Office","three-rivers-public-library":"Three Rivers Public Library","three-rivers":"Three Rivers","unique-jewelry":"Unique Jewelry","walnut-street":"Walnut Street","washington-street":"Washington Street","water-street":"Water Street","west-street":"West Street","wheeler-street":"Wheeler Street","william-towing":"William Towing","willow-drive":"Willow Drive","wood-street":"Wood Street","world-fare":"World Fare"}},"welcome":{"title":"Welcome","welcome":"Welcome! This walkthrough will teach you the basics of editing on OpenStreetMap.","practice":"All of the data in this walkthrough is just for practicing, and any edits that you make in the walkthrough will not be saved.","words":"This walkthrough will introduce some new words and concepts. When we introduce a new word, we'll use *italics*.","mouse":"You can use any input device to edit the map, but this walkthrough assumes you have a mouse with left and right buttons. **If you want to attach a mouse, do so now, then click OK.**","leftclick":"When this tutorial asks you to click or double-click, we mean with the left button. On a trackpad it might be a single-click or single-finger tap. **Left-click {num} times.**","rightclick":"Sometimes we'll also ask you to right-click. This might be the same as control-click, or two-finger tap on a trackpad. Your keyboard might even have a 'menu' key that works like right-click. **Right-click {num} times.**","chapters":"So far, so good! You can use the buttons below to skip chapters at any time or to restart a chapter if you get stuck. Let's begin! **Click '{next}' to continue.**"},"navigation":{"title":"Navigation","drag":"The main map area shows OpenStreetMap data on top of a background.{br}You can drag the map by pressing and holding the left mouse button while moving the mouse around. You can also use the arrow keys on your keyboard. **Drag the map!**","zoom":"You can zoom in or out by scrolling with the mouse wheel or trackpad, or by clicking the {plus} / {minus} buttons. **Zoom the map!**","features":"We use the word *features* to describe the things that appear on the map. Anything in the real world can be mapped as a feature on OpenStreetMap.","points_lines_areas":"Map features are represented using *points, lines, or areas.*","nodes_ways":"In OpenStreetMap, points are sometimes called *nodes*, and lines and areas are sometimes called *ways*.","click_townhall":"All features on the map can be selected by clicking on them. **Click on the point to select it.**","selected_townhall":"Great! The point is now selected. Selected features are drawn with a pulsing glow.","editor_townhall":"When a feature is selected, the *feature editor* is displayed alongside the map.","preset_townhall":"The top part of the feature editor shows the feature's type. This point is a {preset}.","fields_townhall":"The middle part of the feature editor contains *fields* showing the feature's attributes, such as its name and address.","close_townhall":"**Close the feature editor by hitting escape or pressing the {button} button in the upper corner.**","search_street":"You can also search for features in the current view, or worldwide. **Search for '{name}'.**","choose_street":"**Choose {name} from the list to select it.**","selected_street":"Great! {name} is now selected.","editor_street":"The fields shown for a street are different than the fields that were shown for the town hall.{br}For this selected street, the feature editor shows fields like '{field1}' and '{field2}'. **Close the feature editor by hitting escape or pressing the {button} button.**","play":"Try moving the map and clicking on some other features to see what kinds of things can be added to OpenStreetMap. **When you are ready to continue to the next chapter, click '{next}'.**"},"points":{"title":"Points","add_point":"*Points* can be used to represent features such as shops, restaurants, and monuments.{br}They mark a specific location, and describe what's there. **Click the {button} Point button to add a new point.**","place_point":"To place the new point on the map, position your mouse cursor where the point should go, then left-click or press the spacebar. **Move the mouse pointer over this building, then left-click or press the spacebar.**","search_cafe":"There are many different features that can be represented by points. The point you just added is a cafe. **Search for '{preset}'.**","choose_cafe":"**Choose {preset} from the list.**","feature_editor":"The point is now marked as a cafe. Using the feature editor, we can add more information about the cafe.","add_name":"In OpenStreetMap, all of the fields are optional, and it's OK to leave a field blank if you are unsure.{br}Let's pretend that you have local knowledge of this cafe, and you know its name. **Add a name for the cafe.**","add_close":"The feature editor will remember all of your changes automatically. **When you are finished adding the name, hit escape, enter, or click the {button} button to close the feature editor.**","reselect":"Often points will already exist, but have mistakes or be incomplete. We can edit existing points. **Click to select the cafe you just created.**","update":"Let's fill in some more details for this cafe. You can change its name, add a cuisine, or add an address. **Change the cafe details.**","update_close":"**When you are finished updating the cafe, hit escape, enter, or click the {button} button to close the feature editor.**","rightclick":"You can right-click on any feature to see the *edit menu*, which shows a list of editing operations that can be performed. **Right-click to select the point you created and show the edit menu.**","delete":"It's OK to delete features that don't exist in the real world.{br}Deleting a feature from OpenStreetMap removes it from the map that everyone uses, so you should make sure a feature is really gone before you delete it. **Click on the {button} button to delete the point.**","undo":"You can always undo any changes up until you save your edits to OpenStreetMap. **Click on the {button} button to undo the delete and get the point back.**","play":"Now that you know how to create and edit points, try creating a few more points for practice! **When you are ready to continue to the next chapter, click '{next}'.**"},"areas":{"title":"Areas","add_playground":"*Areas* are used to show the boundaries of features like lakes, buildings, and residential areas.{br}They can be also be used for more detailed mapping of many features you might normally map as points. **Click the {button} Area button to add a new area.**","start_playground":"Let's add this playground to the map by drawing an area. Areas are drawn by placing *nodes* along the outer edge of the feature. **Click or press spacebar to place a starting node on one of the corners of the playground.**","continue_playground":"Continue drawing the area by placing more nodes along the playground's edge. It is OK to connect the area to the existing walking paths.{br}Tip: You can hold down the Alt key to prevent nodes from connecting to other features. **Continue drawing an area for the playground.**","finish_playground":"Finish the area by pressing enter, or clicking again on either the first or last node. **Finish drawing an area for the playground.**","search_playground":"**Search for '{preset}'.**","choose_playground":"**Choose {preset} from the list.**","add_field":"This playground doesn't have an official name, so we won't add anything in the Name field.{br}Instead let's add some additional details about the playground to the Description field. **Open the Add Field list.**","choose_field":"**Choose {field} from the list.**","retry_add_field":"You didn't select the {field} field. Let's try again.","describe_playground":"**Add a description, then click the {button} button to close the feature editor.**","play":"Good job! Try drawing a few more areas, and see what other kinds of area features you can add to OpenStreetMap. **When you are ready to continue to the next chapter, click '{next}'.**"},"lines":{"title":"Lines","add_line":"*Lines* are used to represent features such as roads, railroads, and rivers. **Click the {button} Line button to add a new line.**","start_line":"Here is a road that is missing. Let's add it!{br}In OpenStreetMap, lines should be drawn down the center of the road. You can drag and zoom the map while drawing if necessary. **Start a new line by clicking at the top end of this missing road.**","intersect":"Click or press spacebar to add more nodes to the line.{br}Roads, and many other types of lines, are part of a larger network. It is important for these lines to be connected properly in order for routing applications to work. **Click on {name} to create an intersection connecting the two lines.**","retry_intersect":"The road needs to intersect {name}. Let's try again!","continue_line":"Continue drawing the line for the new road. Remember that you can drag and zoom the map if needed.{br}When you are finished drawing, click on the last node again. **Finish drawing the road.**","choose_category_road":"**Select {category} from the list.**","choose_preset_residential":"There are many different types of roads, but this one is a residential road. **Choose the {preset} type.**","retry_preset_residential":"You didn't select the {preset} type. **Click here to choose again.**","name_road":"**Give this road a name, then hit escape, enter, or click the {button} button to close the feature editor.**","did_name_road":"Looks good! Next we will learn how to update the shape of a line.","update_line":"Sometimes you will need to change the shape of an existing line. Here is a road that doesn't look quite right.","add_node":"We can add some nodes to this line to improve its shape. One way to add a node is to double-click the line where you want to add a node. **Double-click on the line to create a new node.**","start_drag_endpoint":"When a line is selected, you can drag any of its nodes by clicking and holding down the left mouse button while you drag. **Drag the endpoint to the place where these roads should intersect.**","finish_drag_endpoint":"This spot looks good. **Release the left mouse button to finish dragging.**","start_drag_midpoint":"Small triangles are drawn at the *midpoints* between nodes. Another way to create a new node is to drag a midpoint to a new location. **Drag the midpoint triangle to create a new node along the curve of the road.**","continue_drag_midpoint":"This line is looking much better! Continue to adjust this line by double-clicking or dragging midpoints until the curve matches the road shape. **When you're happy with how the line looks, click OK.**","delete_lines":"It's OK to delete lines for roads that don't exist in the real world.{br}Here's an example where the city planned a {street} but never built it. We can improve this part of the map by deleting the extra lines.","rightclick_intersection":"The last real street is {street1}, so we will *split* {street2} at this intersection and remove everything above it. **Right click on the intersection node.**","split_intersection":"**Click on the {button} button to split {street}.**","retry_split":"You didn't click the Split button. Try again.","did_split_multi":"Good Job! {street1} is now split into two pieces. The top part can be removed. **Click the top part of {street2} to select it.**","did_split_single":"**Click the top part of {street2} to select it.**","multi_select":"{selected} is now selected. Let's also select {other1}. You can shift-click to select multiple things. **Shift-click on {other2}.**","multi_rightclick":"Good! Both lines to delete are now selected. **Right-click on one of the lines to show the edit menu.**","multi_delete":"**Click on the {button} button to delete the extra lines.**","retry_delete":"You didn't click the Delete button. Try again.","play":"Great! Use the skills that you've learned in this chapter to practice editing some more lines. **When you are ready to continue to the next chapter, click '{next}'.**"},"buildings":{"title":"Buildings","add_building":"OpenStreetMap is the world's largest database of buildings.{br}You can help improve this database by tracing buildings that aren't already mapped. **Click the {button} Area button to add a new area.**","start_building":"Let's add this house to the map by tracing its outline.{br}Buildings should be traced around their footprint as accurately as possible. **Click or press spacebar to place a starting node on one of the corners of the building.**","continue_building":"Continue adding more nodes to trace the outline of the building. Remember that you can zoom in if you want to add more details.{br}Finish the building by pressing enter, or clicking again on either the first or last node. **Finish tracing the building.**","retry_building":"It looks like you had some trouble placing the nodes at the building corners. Try again!","choose_category_building":"**Choose {category} from the list.**","choose_preset_house":"There are many different types of buildings, but this one is clearly a house.{br}If you're not sure of the type, it's OK to just choose the generic Building type. **Choose the {preset} type.**","close":"**Hit escape or click the {button} button to close the feature editor.**","rightclick_building":"**Right-click to select the building you created and show the edit menu.**","square_building":"The house that you just added will look even better with perfectly square corners. **Click on the {button} button to square the building shape.**","retry_square":"You didn't click the Square button. Try again.","done_square":"See how the corners of the building moved into place? Let's learn another useful trick.","add_tank":"Next we'll trace this circular storage tank. **Click the {button} Area button to add a new area.**","start_tank":"Don't worry, you won't need to draw a perfect circle. Just draw an area inside the tank that touches its edge. **Click or press spacebar to place a starting node on the edge of the tank.**","continue_tank":"Add a few more nodes around the edge. The circle will be created outside the nodes that you draw.{br}Finish the area by pressing enter, or clicking again on either the first or last node. **Finish tracing the tank.**","search_tank":"**Search for '{preset}'.**","choose_tank":"**Choose {preset} from the list.**","rightclick_tank":"**Right-click to select the storage tank you created and show the edit menu.**","circle_tank":"**Click on the {button} button to make the tank a circle.**","retry_circle":"You didn't click the Circularize button. Try again.","play":"Great Job! Practice tracing a few more buildings, and try some of the other commands on the edit menu. **When you are ready to continue to the next chapter, click '{next}'.**"},"startediting":{"title":"Start Editing","help":"You're now ready to edit OpenStreetMap!{br}You can replay this walkthrough anytime or view more documentation by clicking the {button} Help button.","save":"Don't forget to regularly save your changes!","start":"Start mapping!"}},"presets":{"categories":{"category-barrier":{"name":"Barrier Features"},"category-building":{"name":"Building Features"},"category-golf":{"name":"Golf Features"},"category-landuse":{"name":"Land Use Features"},"category-natural-area":{"name":"Natural Features"},"category-natural-line":{"name":"Natural Features"},"category-natural-point":{"name":"Natural Features"},"category-path":{"name":"Path Features"},"category-rail":{"name":"Rail Features"},"category-restriction":{"name":"Restriction Features"},"category-road":{"name":"Road Features"},"category-route":{"name":"Route Features"},"category-water-area":{"name":"Water Features"},"category-water-line":{"name":"Water Features"}},"fields":{"access_simple":{"label":"Allowed Access"},"access_toilets":{"label":"Access"},"access":{"label":"Allowed Access","placeholder":"Not Specified","types":{"access":"All","foot":"Foot","motor_vehicle":"Motor Vehicles","bicycle":"Bicycles","horse":"Horses"},"options":{"yes":{"title":"Allowed","description":"Access permitted by law; a right of way"},"no":{"title":"Prohibited","description":"Access not permitted to the general public"},"permissive":{"title":"Permissive","description":"Access permitted until such time as the owner revokes the permission"},"private":{"title":"Private","description":"Access permitted only with permission of the owner on an individual basis"},"designated":{"title":"Designated","description":"Access permitted according to signs or specific local laws"},"destination":{"title":"Destination","description":"Access permitted only to reach a destination"},"dismount":{"title":"Dismount","description":"Access permitted but rider must dismount"}}},"address":{"label":"Address","placeholders":{"block_number":"Block Number","block_number!jp":"Block No.","city":"City","city!jp":"City/Town/Village/Tokyo Special Ward","city!vn":"City/Town","conscriptionnumber":"123","country":"Country","county":"County","county!jp":"District","district":"District","district!vn":"Arrondissement/Town/District","floor":"Floor","hamlet":"Hamlet","housename":"Housename","housenumber":"123","housenumber!jp":"Building No./Lot No.","neighbourhood":"Neighbourhood","neighbourhood!jp":"Chōme/Aza/Koaza","place":"Place","postcode":"Postcode","province":"Province","province!jp":"Prefecture","quarter":"Quarter","quarter!jp":"Ōaza/Machi","state":"State","street":"Street","subdistrict":"Subdistrict","subdistrict!vn":"Ward/Commune/Townlet","suburb":"Suburb","suburb!jp":"Ward"}},"admin_level":{"label":"Admin Level"},"aerialway":{"label":"Type"},"aerialway/access":{"label":"Access","options":{"entry":"Entry","exit":"Exit","both":"Both"}},"aerialway/bubble":{"label":"Bubble"},"aerialway/capacity":{"label":"Capacity (per hour)","placeholder":"500, 2500, 5000..."},"aerialway/duration":{"label":"Duration (minutes)","placeholder":"1, 2, 3..."},"aerialway/heating":{"label":"Heated"},"aerialway/occupancy":{"label":"Occupancy","placeholder":"2, 4, 8..."},"aerialway/summer/access":{"label":"Access (summer)","options":{"entry":"Entry","exit":"Exit","both":"Both"}},"aeroway":{"label":"Type"},"amenity":{"label":"Type"},"animal_boarding":{"label":"For Animals"},"animal_breeding":{"label":"For Animals"},"animal_shelter":{"label":"For Animals"},"area/highway":{"label":"Type"},"artist":{"label":"Artist"},"artwork_type":{"label":"Type"},"atm":{"label":"ATM"},"backrest":{"label":"Backrest"},"barrier":{"label":"Type"},"bath/open_air":{"label":"Open Air"},"bath/sand_bath":{"label":"Sand Bath"},"bath/type":{"label":"Specialty","options":{"onsen":"Japanese Onsen","foot_bath":"Foot Bath","hot_spring":"Hot Spring"}},"beauty":{"label":"Shop Type"},"bench":{"label":"Bench"},"bicycle_parking":{"label":"Type"},"bin":{"label":"Waste Bin"},"blood_components":{"label":"Blood Components","options":{"whole":"whole blood","plasma":"plasma","platelets":"platelets","stemcells":"stem cell samples"}},"board_type":{"label":"Type"},"boundary":{"label":"Type"},"brand":{"label":"Brand"},"building_area":{"label":"Building"},"building":{"label":"Building"},"bunker_type":{"label":"Type"},"camera/direction":{"label":"Direction (Degrees Clockwise)","placeholder":"45, 90, 180, 270"},"camera/mount":{"label":"Camera Mount"},"camera/type":{"label":"Camera Type","options":{"fixed":"Fixed","panning":"Panning","dome":"Dome"}},"capacity":{"label":"Capacity","placeholder":"50, 100, 200..."},"cardinal_direction":{"label":"Direction","options":{"N":"North","E":"East","S":"South","W":"West","NE":"Northeast","SE":"Southeast","SW":"Southwest","NW":"Northwest","NNE":"North-northeast","ENE":"East-northeast","ESE":"East-southeast","SSE":"South-southeast","SSW":"South-southwest","WSW":"West-southwest","WNW":"West-northwest","NNW":"North-northwest"}},"castle_type":{"label":"Type"},"clock_direction":{"label":"Direction","options":{"clockwise":"Clockwise","anticlockwise":"Counterclockwise"}},"club":{"label":"Type"},"collection_times":{"label":"Collection Times"},"communication_multi":{"label":"Communication Types"},"construction":{"label":"Type"},"contact/webcam":{"label":"Webcam URL","placeholder":"http://example.com/"},"content":{"label":"Contents"},"country":{"label":"Country"},"covered":{"label":"Covered"},"craft":{"label":"Type"},"crop":{"label":"Crops"},"crossing":{"label":"Type"},"cuisine":{"label":"Cuisines"},"currency_multi":{"label":"Currency Types"},"cycle_network":{"label":"Network"},"cycleway":{"label":"Bike Lanes","placeholder":"none","types":{"cycleway:left":"Left side","cycleway:right":"Right side"},"options":{"none":{"title":"None","description":"No bike lane"},"lane":{"title":"Standard bike lane","description":"A bike lane separated from auto traffic by a painted line"},"shared_lane":{"title":"Shared bike lane","description":"A bike lane with no separation from auto traffic"},"track":{"title":"Bike track","description":"A bike lane separated from traffic by a physical barrier"},"share_busway":{"title":"Bike lane shared with bus","description":"A bike lane shared with a bus lane"},"opposite_lane":{"title":"Opposite bike lane","description":"A bike lane that travels in the opposite direction of traffic"},"opposite":{"title":"Contraflow bike lane","description":"A bike lane that travels in both directions on a one-way street"}}},"date":{"label":"Date"},"delivery":{"label":"Delivery"},"denomination":{"label":"Denomination"},"denotation":{"label":"Denotation"},"description":{"label":"Description"},"diaper":{"label":"Diaper Changing Available"},"display":{"label":"Display"},"dock":{"label":"Type"},"drive_through":{"label":"Drive-Through"},"electrified":{"label":"Electrification","placeholder":"Contact Line, Electrified Rail...","options":{"contact_line":"Contact Line","rail":"Electrified Rail","yes":"Yes (unspecified)","no":"No"}},"elevation":{"label":"Elevation"},"email":{"label":"Email","placeholder":"example@example.com"},"emergency":{"label":"Emergency"},"entrance":{"label":"Type"},"except":{"label":"Exceptions"},"fax":{"label":"Fax","placeholder":"+31 42 123 4567"},"fee":{"label":"Fee"},"fence_type":{"label":"Type"},"fire_hydrant/position":{"label":"Position","options":{"lane":"Lane","parking_lot":"Parking Lot","sidewalk":"Sidewalk","green":"Green"}},"fire_hydrant/type":{"label":"Type","options":{"pillar":"Pillar/Aboveground","underground":"Underground","wall":"Wall","pond":"Pond"}},"fixme":{"label":"Fix Me"},"fuel_multi":{"label":"Fuel Types"},"fuel":{"label":"Fuel"},"gauge":{"label":"Gauge"},"gender":{"label":"Gender","placeholder":"Unknown","options":{"male":"Male","female":"Female","unisex":"Unisex"}},"generator/method":{"label":"Method"},"generator/source":{"label":"Source"},"generator/type":{"label":"Type"},"golf_hole":{"label":"Reference","placeholder":"Hole number (1-18)"},"grape_variety":{"label":"Grape Varieties"},"handicap":{"label":"Handicap","placeholder":"1-18"},"handrail":{"label":"Handrail"},"height":{"label":"Height (Meters)"},"highway":{"label":"Type"},"historic":{"label":"Type"},"historic/civilization":{"label":"Historic Civilization"},"hoops":{"label":"Hoops","placeholder":"1, 2, 4..."},"iata":{"label":"IATA"},"icao":{"label":"ICAO"},"incline_steps":{"label":"Incline","options":{"up":"Up","down":"Down"}},"incline":{"label":"Incline"},"indoor":{"label":"Indoor"},"information":{"label":"Type"},"inscription":{"label":"Inscription"},"internet_access":{"label":"Internet Access","options":{"yes":"Yes","no":"No","wlan":"Wifi","wired":"Wired","terminal":"Terminal"}},"internet_access/fee":{"label":"Internet Access Fee"},"internet_access/ssid":{"label":"SSID (Network Name)"},"kerb":{"label":"Curb Ramp"},"lamp_type":{"label":"Type"},"landuse":{"label":"Type"},"lanes":{"label":"Lanes","placeholder":"1, 2, 3..."},"layer":{"label":"Layer"},"leaf_cycle_singular":{"label":"Leaf Cycle","options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous"}},"leaf_cycle":{"label":"Leaf Cycle","options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous","mixed":"Mixed"}},"leaf_type_singular":{"label":"Leaf Type","options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","leafless":"Leafless"}},"leaf_type":{"label":"Leaf Type","options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","mixed":"Mixed","leafless":"Leafless"}},"leisure":{"label":"Type"},"length":{"label":"Length (Meters)"},"level":{"label":"Level"},"levels":{"label":"Levels","placeholder":"2, 4, 6..."},"lit":{"label":"Lit"},"location":{"label":"Location"},"man_made":{"label":"Type"},"map_size":{"label":"Coverage"},"map_type":{"label":"Type"},"maxheight":{"label":"Max Height","placeholder":"4, 4.5, 5, 14'0\", 14'6\", 15'0\""},"maxspeed":{"label":"Speed Limit","placeholder":"40, 50, 60..."},"maxstay":{"label":"Max Stay"},"mtb/scale":{"label":"Mountain Biking Difficulty","placeholder":"0, 1, 2, 3...","options":{"0":"0: Solid gravel/packed earth, no obstacles, wide curves","1":"1: Some loose surface, small obstacles, wide curves","2":"2: Much loose surface, large obstacles, easy hairpins","3":"3: Slippery surface, large obstacles, tight hairpins","4":"4: Loose surface or boulders, dangerous hairpins","5":"5: Maximum difficulty, boulder fields, landslides","6":"6: Not rideable except by the very best mountain bikers"}},"mtb/scale/imba":{"label":"IMBA Trail Difficulty","placeholder":"Easy, Medium, Difficult...","options":{"0":"Easiest (white circle)","1":"Easy (green circle)","2":"Medium (blue square)","3":"Difficult (black diamond)","4":"Extremely Difficult (double black diamond)"}},"mtb/scale/uphill":{"label":"Mountain Biking Uphill Difficulty","placeholder":"0, 1, 2, 3...","options":{"0":"0: Avg. incline <10%, gravel/packed earth, no obstacles","1":"1: Avg. incline <15%, gravel/packed earth, few small objects","2":"2: Avg. incline <20%, stable surface, fistsize rocks/roots","3":"3: Avg. incline <25%, variable surface, fistsize rocks/branches","4":"4: Avg. incline <30%, poor condition, big rocks/branches","5":"5: Very steep, bike generally needs to be pushed or carried"}},"name":{"label":"Name","placeholder":"Common name (if any)"},"natural":{"label":"Natural"},"network_bicycle":{"label":"Network Type","placeholder":"Local, Regional, National, International","options":{"lcn":"Local","rcn":"Regional","ncn":"National","icn":"International"}},"network_foot":{"label":"Network Type","placeholder":"Local, Regional, National, International","options":{"lwn":"Local","rwn":"Regional","nwn":"National","iwn":"International"}},"network_horse":{"label":"Network Type","placeholder":"Local, Regional, National, International","options":{"lhn":"Local","rhn":"Regional","nhn":"National","ihn":"International"}},"network_road":{"label":"Network"},"network":{"label":"Network"},"note":{"label":"Note"},"office":{"label":"Type"},"oneway_yes":{"label":"One Way","options":{"undefined":"Assumed to be Yes","yes":"Yes","no":"No"}},"oneway":{"label":"One Way","options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}},"opening_hours":{"label":"Hours"},"operator":{"label":"Operator"},"outdoor_seating":{"label":"Outdoor Seating"},"par":{"label":"Par","placeholder":"3, 4, 5..."},"parallel_direction":{"label":"Direction","options":{"forward":"Forward","backward":"Backward"}},"park_ride":{"label":"Park and Ride"},"parking":{"label":"Type","options":{"surface":"Surface","multi-storey":"Multilevel","underground":"Underground","sheds":"Sheds","carports":"Carports","garage_boxes":"Garage Boxes","lane":"Roadside Lane"}},"payment_multi":{"label":"Payment Types"},"phone":{"label":"Phone","placeholder":"+31 42 123 4567"},"piste/difficulty":{"label":"Difficulty","placeholder":"Easy, Intermediate, Advanced...","options":{"novice":"Novice (instructional)","easy":"Easy (green circle)","intermediate":"Intermediate (blue square)","advanced":"Advanced (black diamond)","expert":"Expert (double black diamond)","freeride":"Freeride (off-piste)","extreme":"Extreme (climbing equipment required)"}},"piste/grooming":{"label":"Grooming","options":{"classic":"Classic","mogul":"Mogul","backcountry":"Backcountry","classic+skating":"Classic and Skating","scooter":"Scooter/Snowmobile","skating":"Skating"}},"piste/type":{"label":"Type","options":{"downhill":"Downhill","nordic":"Nordic","skitour":"Skitour","sled":"Sled","hike":"Hike","sleigh":"Sleigh","ice_skate":"Ice Skate","snow_park":"Snow Park","playground":"Playground"}},"place":{"label":"Type"},"plant":{"label":"Plant"},"population":{"label":"Population"},"power_supply":{"label":"Power Supply"},"power":{"label":"Type"},"produce":{"label":"Produce"},"product":{"label":"Products"},"railway":{"label":"Type"},"recycling_accepts":{"label":"Accepts"},"recycling_type":{"label":"Recycling Type","options":{"container":"Container","centre":"Recycling Center"}},"ref":{"label":"Reference"},"relation":{"label":"Type"},"religion":{"label":"Religion"},"restriction":{"label":"Type"},"restrictions":{"label":"Turn Restrictions"},"rooms":{"label":"Rooms"},"route_master":{"label":"Type"},"route":{"label":"Type"},"sac_scale":{"label":"Hiking Difficulty","placeholder":"Mountain Hiking, Alpine Hiking...","options":{"hiking":"T1: Hiking","mountain_hiking":"T2: Mountain Hiking","demanding_mountain_hiking":"T3: Demanding Mountain Hiking","alpine_hiking":"T4: Alpine Hiking","demanding_alpine_hiking":"T5: Demanding Alpine Hiking","difficult_alpine_hiking":"T6: Difficult Alpine Hiking"}},"sanitary_dump_station":{"label":"Toilet Disposal"},"seasonal":{"label":"Seasonal"},"second_hand":{"label":"Sells Used","placeholder":"Yes, No, Only","options":{"yes":"Yes","no":"No","only":"Only"}},"service_rail":{"label":"Service Type","options":{"spur":"Spur","yard":"Yard","siding":"Siding","crossover":"Crossover"}},"service_times":{"label":"Service Times"},"service":{"label":"Type"},"service/bicycle":{"label":"Services"},"service/vehicle":{"label":"Services"},"shelter_type":{"label":"Type"},"shelter":{"label":"Shelter"},"shop":{"label":"Type"},"site":{"label":"Type"},"smoking":{"label":"Smoking","placeholder":"No, Separated, Yes...","options":{"no":"No smoking anywhere","separated":"In smoking areas, not physically isolated","isolated":"In smoking areas, physically isolated","outside":"Allowed outside","yes":"Allowed everywhere","dedicated":"Dedicated to smokers (e.g. smokers' club)"}},"smoothness":{"label":"Smoothness","placeholder":"Thin Rollers, Wheels, Off-Road...","options":{"excellent":"Thin Rollers: rollerblade, skateboard","good":"Thin Wheels: racing bike","intermediate":"Wheels: city bike, wheelchair, scooter","bad":"Robust Wheels: trekking bike, car, rickshaw","very_bad":"High Clearance: light duty off-road vehicle","horrible":"Off-Road: heavy duty off-road vehicle","very_horrible":"Specialized off-road: tractor, ATV","impassable":"Impassable / No wheeled vehicle"}},"social_facility_for":{"label":"People Served"},"social_facility":{"label":"Type"},"source":{"label":"Source"},"sport_ice":{"label":"Sports"},"sport_racing_motor":{"label":"Sports"},"sport_racing_nonmotor":{"label":"Sports"},"sport":{"label":"Sports"},"stars":{"label":"Stars"},"start_date":{"label":"Start Date"},"step_count":{"label":"Number of Steps"},"stop":{"label":"Stop Type","options":{"all":"All Ways","minor":"Minor Road"}},"structure":{"label":"Structure","placeholder":"Unknown","options":{"bridge":"Bridge","tunnel":"Tunnel","embankment":"Embankment","cutting":"Cutting","ford":"Ford"}},"studio":{"label":"Type"},"substation":{"label":"Type"},"supervised":{"label":"Supervised"},"support":{"label":"Support"},"surface":{"label":"Surface"},"surveillance":{"label":"Surveillance Kind"},"surveillance/type":{"label":"Surveillance Type","options":{"camera":"Camera","guard":"Guard","ALPR":"Automatic License Plate Reader"}},"surveillance/zone":{"label":"Surveillance Zone"},"tactile_paving":{"label":"Tactile Paving"},"takeaway":{"label":"Takeaway","placeholder":"Yes, No, Takeaway Only...","options":{"yes":"Yes","no":"No","only":"Takeaway Only"}},"toilets/disposal":{"label":"Disposal","options":{"flush":"Flush","pitlatrine":"Pit/Latrine","chemical":"Chemical","bucket":"Bucket"}},"toll":{"label":"Toll"},"tomb":{"label":"Type"},"tourism":{"label":"Type"},"tower/construction":{"label":"Construction","placeholder":"Guyed, Lattice, Concealed, ..."},"tower/type":{"label":"Type"},"tracktype":{"label":"Track Type","placeholder":"Solid, Mostly Solid, Soft...","options":{"grade1":"Solid: paved or heavily compacted hardcore surface","grade2":"Mostly Solid: gravel/rock with some soft material mixed in","grade3":"Even mixture of hard and soft materials","grade4":"Mostly Soft: soil/sand/grass with some hard material mixed in","grade5":"Soft: soil/sand/grass"}},"traffic_calming":{"label":"Type"},"traffic_signals":{"label":"Type"},"trail_visibility":{"label":"Trail Visibility","placeholder":"Excellent, Good, Bad...","options":{"excellent":"Excellent: unambiguous path or markers everywhere","good":"Good: markers visible, sometimes require searching","intermediate":"Intermediate: few markers, path mostly visible","bad":"Bad: no markers, path sometimes invisible/pathless","horrible":"Horrible: often pathless, some orientation skills required","no":"No: pathless, excellent orientation skills required"}},"trees":{"label":"Trees"},"tunnel":{"label":"Tunnel"},"vending":{"label":"Type of Goods"},"visibility":{"label":"Visibility","options":{"house":"Up to 5m (16ft)","street":"5 to 20m (16 to 65ft)","area":"Over 20m (65ft)"}},"wall":{"label":"Type"},"water_point":{"label":"Water Point"},"water":{"label":"Type"},"waterway":{"label":"Type"},"website":{"label":"Website","placeholder":"http://example.com/"},"wetland":{"label":"Type"},"wheelchair":{"label":"Wheelchair Access"},"width":{"label":"Width (Meters)"},"wikipedia":{"label":"Wikipedia"}},"presets":{"aerialway":{"name":"Aerialway","terms":"ski lift,funifor,funitel"},"aeroway":{"name":"Aeroway","terms":""},"amenity":{"name":"Amenity","terms":""},"highway":{"name":"Highway","terms":""},"place":{"name":"Place","terms":""},"power":{"name":"Power","terms":""},"railway":{"name":"Railway","terms":""},"roundabout":{"name":"Roundabout","terms":""},"waterway":{"name":"Waterway","terms":""},"address":{"name":"Address","terms":""},"advertising/billboard":{"name":"Billboard","terms":""},"aerialway/cable_car":{"name":"Cable Car","terms":"tramway,ropeway"},"aerialway/chair_lift":{"name":"Chair Lift","terms":""},"aerialway/drag_lift":{"name":"Drag Lift","terms":""},"aerialway/gondola":{"name":"Gondola","terms":""},"aerialway/goods":{"name":"Goods Aerialway","terms":""},"aerialway/magic_carpet":{"name":"Magic Carpet Lift","terms":""},"aerialway/mixed_lift":{"name":"Mixed Lift","terms":""},"aerialway/platter":{"name":"Platter Lift","terms":"button lift,poma lift"},"aerialway/pylon":{"name":"Aerialway Pylon","terms":""},"aerialway/rope_tow":{"name":"Rope Tow Lift","terms":"handle tow,bugel lift"},"aerialway/station":{"name":"Aerialway Station","terms":""},"aerialway/t-bar":{"name":"T-bar Lift","terms":""},"aeroway/aerodrome":{"name":"Airport","terms":"airplane,airport,aerodrome"},"aeroway/apron":{"name":"Apron","terms":"ramp"},"aeroway/gate":{"name":"Airport Gate","terms":""},"aeroway/hangar":{"name":"Hangar","terms":""},"aeroway/helipad":{"name":"Helipad","terms":"helicopter,helipad,heliport"},"aeroway/runway":{"name":"Runway","terms":"landing strip"},"aeroway/taxiway":{"name":"Taxiway","terms":""},"aeroway/terminal":{"name":"Airport Terminal","terms":"airport,aerodrome"},"amenity/coworking_space":{"name":"Coworking Space","terms":""},"amenity/nursing_home":{"name":"Nursing Home","terms":""},"amenity/register_office":{"name":"Register Office","terms":""},"amenity/swimming_pool":{"name":"Swimming Pool","terms":""},"amenity/animal_boarding":{"name":"Animal Boarding Facility","terms":"boarding,cat,dog,horse,kitten,pet boarding,pet care,pet hotel,puppy,reptile"},"amenity/animal_breeding":{"name":"Animal Breeding Facility","terms":"breeding,bull,cat,cow,dog,horse,husbandry,kitten,livestock,pet breeding,puppy,reptile"},"amenity/animal_shelter":{"name":"Animal Shelter","terms":"adoption,aspca,cat,dog,horse,kitten,pet care,pet rescue,puppy,raptor,reptile,rescue,spca"},"amenity/arts_centre":{"name":"Arts Center","terms":""},"amenity/atm":{"name":"ATM","terms":"money,cash,machine"},"amenity/bank":{"name":"Bank","terms":"credit union,check,deposit,fund,investment,repository,reserve,safe,savings,stock,treasury,trust,vault"},"amenity/bar":{"name":"Bar","terms":"dive,beer,bier,booze"},"amenity/bbq":{"name":"Barbecue/Grill","terms":"bbq,grill"},"amenity/bench":{"name":"Bench","terms":"seat"},"amenity/bicycle_parking":{"name":"Bicycle Parking","terms":"bike"},"amenity/bicycle_rental":{"name":"Bicycle Rental","terms":"bike"},"amenity/bicycle_repair_station":{"name":"Bicycle Repair Tool Stand","terms":"bike,repair,chain,pump"},"amenity/biergarten":{"name":"Beer Garden","terms":"beer,bier,booze"},"amenity/boat_rental":{"name":"Boat Rental","terms":""},"amenity/bureau_de_change":{"name":"Currency Exchange","terms":"bureau de change,money changer"},"amenity/bus_station":{"name":"Bus Station","terms":""},"amenity/cafe":{"name":"Cafe","terms":"bistro,coffee,tea"},"amenity/car_rental":{"name":"Car Rental","terms":""},"amenity/car_sharing":{"name":"Car Sharing","terms":""},"amenity/car_wash":{"name":"Car Wash","terms":""},"amenity/casino":{"name":"Casino","terms":"gambling,roulette,craps,poker,blackjack"},"amenity/charging_station":{"name":"Charging Station","terms":"EV,Electric Vehicle,Supercharger"},"amenity/childcare":{"name":"Nursery/Childcare","terms":"daycare,orphanage,playgroup"},"amenity/cinema":{"name":"Cinema","terms":"drive-in,film,flick,movie,theater,picture,show,screen"},"amenity/clinic":{"name":"Clinic","terms":"medical,urgentcare"},"amenity/clock":{"name":"Clock","terms":""},"amenity/college":{"name":"College Grounds","terms":"university"},"amenity/community_centre":{"name":"Community Center","terms":"event,hall"},"amenity/compressed_air":{"name":"Compressed Air","terms":""},"amenity/courthouse":{"name":"Courthouse","terms":""},"amenity/crematorium":{"name":"Crematorium","terms":"cemetery,funeral"},"amenity/dentist":{"name":"Dentist","terms":"tooth,teeth"},"amenity/doctors":{"name":"Doctor","terms":"medic*"},"amenity/dojo":{"name":"Dojo / Martial Arts Academy","terms":"martial arts,dojang"},"amenity/drinking_water":{"name":"Drinking Water","terms":"fountain,potable"},"amenity/driving_school":{"name":"Driving School","terms":""},"amenity/embassy":{"name":"Embassy","terms":""},"amenity/fast_food":{"name":"Fast Food","terms":"restaurant,takeaway"},"amenity/ferry_terminal":{"name":"Ferry Terminal","terms":""},"amenity/fire_station":{"name":"Fire Station","terms":""},"amenity/food_court":{"name":"Food Court","terms":"fast food,restaurant,food"},"amenity/fountain":{"name":"Fountain","terms":""},"amenity/fuel":{"name":"Gas Station","terms":"petrol,fuel,gasoline,propane,diesel,lng,cng,biodiesel"},"amenity/grave_yard":{"name":"Graveyard","terms":""},"amenity/grit_bin":{"name":"Grit Bin","terms":"salt,sand"},"amenity/hospital":{"name":"Hospital Grounds","terms":"clinic,doctor,emergency room,health,infirmary,institution,sanatorium,sanitarium,sick,surgery,ward"},"amenity/hunting_stand":{"name":"Hunting Stand","terms":"game,gun,lookout,rifle,shoot*,wild,watch"},"amenity/ice_cream":{"name":"Ice Cream Shop","terms":"gelato,sorbet,sherbet,frozen,yogurt"},"amenity/internet_cafe":{"name":"Internet Cafe","terms":"cybercafe,taxiphone,teleboutique,coffee,cafe,net,lanhouse"},"amenity/kindergarten":{"name":"Preschool/Kindergarten Grounds","terms":"kindergarden,pre-school"},"amenity/library":{"name":"Library","terms":"book"},"amenity/marketplace":{"name":"Marketplace","terms":""},"amenity/motorcycle_parking":{"name":"Motorcycle Parking","terms":""},"amenity/nightclub":{"name":"Nightclub","terms":"disco*,night club,dancing,dance club"},"amenity/parking_entrance":{"name":"Parking Garage Entrance/Exit","terms":""},"amenity/parking_space":{"name":"Parking Space","terms":""},"amenity/parking":{"name":"Car Parking","terms":""},"amenity/pavilion":{"name":"Pavilion","terms":""},"amenity/pharmacy":{"name":"Pharmacy","terms":"drug*,med*,prescription"},"amenity/place_of_worship":{"name":"Place of Worship","terms":"abbey,basilica,bethel,cathedral,chancel,chantry,chapel,church,fold,house of God,house of prayer,house of worship,minster,mission,mosque,oratory,parish,sacellum,sanctuary,shrine,synagogue,tabernacle,temple"},"amenity/place_of_worship/buddhist":{"name":"Buddhist Temple","terms":"stupa,vihara,monastery,temple,pagoda,zendo,dojo"},"amenity/place_of_worship/christian":{"name":"Church","terms":"christian,abbey,basilica,bethel,cathedral,chancel,chantry,chapel,fold,house of God,house of prayer,house of worship,minster,mission,oratory,parish,sacellum,sanctuary,shrine,tabernacle,temple"},"amenity/place_of_worship/jewish":{"name":"Synagogue","terms":"jewish"},"amenity/place_of_worship/muslim":{"name":"Mosque","terms":"muslim"},"amenity/planetarium":{"name":"Planetarium","terms":"museum,astronomy,observatory"},"amenity/police":{"name":"Police","terms":"badge,constable,constabulary,cop,detective,fed,law,enforcement,officer,patrol"},"amenity/post_box":{"name":"Mailbox","terms":"letter,post"},"amenity/post_office":{"name":"Post Office","terms":"letter,mail"},"amenity/prison":{"name":"Prison Grounds","terms":"cell,jail"},"amenity/pub":{"name":"Pub","terms":"alcohol,drink,dive,beer,bier,booze"},"amenity/public_bath":{"name":"Public Bath","terms":"onsen,foot bath,hot springs"},"amenity/public_bookcase":{"name":"Public Bookcase","terms":"library,bookcrossing"},"amenity/ranger_station":{"name":"Ranger Station","terms":"visitor center,visitor centre,permit center,permit centre,backcountry office,warden office,warden center"},"amenity/recycling_centre":{"name":"Recycling Center","terms":"bottle,can,dump,glass,garbage,rubbish,scrap,trash"},"amenity/recycling":{"name":"Recycling","terms":"bin,can,bottle,glass,garbage,rubbish,scrap,trash"},"amenity/restaurant":{"name":"Restaurant","terms":"bar,breakfast,cafe,café,canteen,coffee,dine,dining,dinner,drive-in,eat,grill,lunch,table"},"amenity/sanitary_dump_station":{"name":"RV Toilet Disposal","terms":"Motor Home,Camper,Sanitary,Dump Station,Elsan,CDP,CTDP,Chemical Toilet"},"amenity/school":{"name":"School Grounds","terms":"academy,elementary school,middle school,high school"},"amenity/shelter":{"name":"Shelter","terms":"lean-to,gazebo,picnic"},"amenity/social_facility":{"name":"Social Facility","terms":""},"amenity/social_facility/food_bank":{"name":"Food Bank","terms":""},"amenity/social_facility/group_home":{"name":"Elderly Group Home","terms":"old,senior,living"},"amenity/social_facility/homeless_shelter":{"name":"Homeless Shelter","terms":"houseless,unhoused,displaced"},"amenity/social_facility/nursing_home":{"name":"Nursing Home","terms":"elderly,living,nursing,old,senior"},"amenity/studio":{"name":"Studio","terms":"recording,radio,television"},"amenity/taxi":{"name":"Taxi Stand","terms":"cab"},"amenity/telephone":{"name":"Telephone","terms":"phone"},"amenity/theatre":{"name":"Theater","terms":"theatre,performance,play,musical"},"amenity/toilets":{"name":"Toilets","terms":"bathroom,restroom,outhouse,privy,head,lavatory,latrine,water closet,WC,W.C."},"amenity/townhall":{"name":"Town Hall","terms":"village,city,government,courthouse,municipal"},"amenity/university":{"name":"University Grounds","terms":"college"},"amenity/vending_machine":{"name":"Vending Machine","terms":""},"amenity/vending_machine/news_papers":{"name":"Newspaper Vending Machine","terms":"newspaper"},"amenity/vending_machine/cigarettes":{"name":"Cigarette Vending Machine","terms":"cigarette"},"amenity/vending_machine/condoms":{"name":"Condom Vending Machine","terms":"condom"},"amenity/vending_machine/drinks":{"name":"Drink Vending Machine","terms":"drink,soda,beverage,juice,pop"},"amenity/vending_machine/excrement_bags":{"name":"Excrement Bag Vending Machine","terms":"excrement bags,poop,dog,animal"},"amenity/vending_machine/newspapers":{"name":"Newspaper Vending Machine","terms":"newspaper"},"amenity/vending_machine/parcel_pickup_dropoff":{"name":"Parcel Pickup/Dropoff Vending Machine","terms":"parcel,mail,pickup"},"amenity/vending_machine/parking_tickets":{"name":"Parking Ticket Vending Machine","terms":"parking,ticket"},"amenity/vending_machine/public_transport_tickets":{"name":"Transit Ticket Vending Machine","terms":"bus,train,ferry,rail,ticket,transportation"},"amenity/vending_machine/sweets":{"name":"Snack Vending Machine","terms":"candy,gum,chip,pretzel,cookie,cracker"},"amenity/veterinary":{"name":"Veterinary","terms":"pet clinic,veterinarian,animal hospital,pet doctor"},"amenity/waste_basket":{"name":"Waste Basket","terms":"bin,garbage,rubbish,litter,trash"},"amenity/waste_disposal":{"name":"Garbage Dumpster","terms":"garbage,rubbish,litter,trash"},"amenity/waste_transfer_station":{"name":"Waste Transfer Station","terms":"dump,garbage,recycling,rubbish,scrap,trash"},"amenity/water_point":{"name":"RV Drinking Water","terms":""},"amenity/watering_place":{"name":"Animal Watering Place","terms":""},"area":{"name":"Area","terms":""},"area/highway":{"name":"Road Surface","terms":""},"barrier":{"name":"Barrier","terms":""},"barrier/entrance":{"name":"Entrance","terms":""},"barrier/block":{"name":"Block","terms":""},"barrier/bollard":{"name":"Bollard","terms":""},"barrier/border_control":{"name":"Border Control","terms":""},"barrier/cattle_grid":{"name":"Cattle Grid","terms":""},"barrier/city_wall":{"name":"City Wall","terms":""},"barrier/cycle_barrier":{"name":"Cycle Barrier","terms":""},"barrier/ditch":{"name":"Trench","terms":""},"barrier/fence":{"name":"Fence","terms":""},"barrier/gate":{"name":"Gate","terms":""},"barrier/hedge":{"name":"Hedge","terms":""},"barrier/kissing_gate":{"name":"Kissing Gate","terms":""},"barrier/lift_gate":{"name":"Lift Gate","terms":""},"barrier/retaining_wall":{"name":"Retaining Wall","terms":""},"barrier/stile":{"name":"Stile","terms":""},"barrier/toll_booth":{"name":"Toll Booth","terms":""},"barrier/wall":{"name":"Wall","terms":""},"boundary/administrative":{"name":"Administrative Boundary","terms":""},"building":{"name":"Building","terms":""},"building/bunker":{"name":"Bunker","terms":""},"building/entrance":{"name":"Entrance/Exit","terms":""},"building/train_station":{"name":"Train Station","terms":""},"building/apartments":{"name":"Apartments","terms":""},"building/barn":{"name":"Barn","terms":""},"building/cabin":{"name":"Cabin","terms":""},"building/cathedral":{"name":"Cathedral Building","terms":""},"building/chapel":{"name":"Chapel Building","terms":""},"building/church":{"name":"Church Building","terms":""},"building/college":{"name":"College Building","terms":"university"},"building/commercial":{"name":"Commercial Building","terms":""},"building/construction":{"name":"Building Under Construction","terms":""},"building/detached":{"name":"Detached House","terms":"home,single,family,residence,dwelling"},"building/dormitory":{"name":"Dormitory","terms":""},"building/garage":{"name":"Garage","terms":""},"building/garages":{"name":"Garages","terms":""},"building/greenhouse":{"name":"Greenhouse","terms":""},"building/hospital":{"name":"Hospital Building","terms":""},"building/hotel":{"name":"Hotel Building","terms":""},"building/house":{"name":"House","terms":"home,family,residence,dwelling"},"building/hut":{"name":"Hut","terms":""},"building/industrial":{"name":"Industrial Building","terms":""},"building/kindergarten":{"name":"Preschool/Kindergarten Building","terms":"kindergarden,pre-school"},"building/public":{"name":"Public Building","terms":""},"building/residential":{"name":"Residential Building","terms":""},"building/retail":{"name":"Retail Building","terms":""},"building/roof":{"name":"Roof","terms":""},"building/school":{"name":"School Building","terms":"academy,elementary school,middle school,high school"},"building/semidetached_house":{"name":"Semi-Detached House","terms":"home,double,duplex,twin,family,residence,dwelling"},"building/shed":{"name":"Shed","terms":""},"building/stable":{"name":"Stable","terms":""},"building/static_caravan":{"name":"Static Mobile Home","terms":""},"building/terrace":{"name":"Row Houses","terms":"home,terrace,brownstone,family,residence,dwelling"},"building/university":{"name":"University Building","terms":"college"},"building/warehouse":{"name":"Warehouse","terms":""},"camp_site/camp_pitch":{"name":"Camp Pitch","terms":"tent,rv"},"club":{"name":"Club","terms":"social"},"craft":{"name":"Craft","terms":""},"craft/jeweler":{"name":"Jeweler","terms":""},"craft/locksmith":{"name":"Locksmith","terms":""},"craft/optician":{"name":"Optician","terms":""},"craft/tailor":{"name":"Tailor","terms":"clothes,suit"},"craft/basket_maker":{"name":"Basket Maker","terms":""},"craft/beekeeper":{"name":"Beekeeper","terms":""},"craft/blacksmith":{"name":"Blacksmith","terms":""},"craft/boatbuilder":{"name":"Boat Builder","terms":""},"craft/bookbinder":{"name":"Bookbinder","terms":"book repair"},"craft/brewery":{"name":"Brewery","terms":"beer,bier"},"craft/carpenter":{"name":"Carpenter","terms":"woodworker"},"craft/carpet_layer":{"name":"Carpet Layer","terms":""},"craft/caterer":{"name":"Caterer","terms":""},"craft/clockmaker":{"name":"Clockmaker","terms":""},"craft/confectionery":{"name":"Confectionery","terms":"sweets,candy"},"craft/dressmaker":{"name":"Dressmaker","terms":"seamstress"},"craft/electrician":{"name":"Electrician","terms":"power,wire"},"craft/gardener":{"name":"Gardener","terms":"landscaper,grounds keeper"},"craft/glaziery":{"name":"Glaziery","terms":"glass,stained-glass,window"},"craft/handicraft":{"name":"Handicraft","terms":""},"craft/hvac":{"name":"HVAC","terms":"heat*,vent*,air conditioning"},"craft/insulator":{"name":"Insulator","terms":""},"craft/key_cutter":{"name":"Key Cutter","terms":""},"craft/metal_construction":{"name":"Metal Construction","terms":""},"craft/painter":{"name":"Painter","terms":""},"craft/photographer":{"name":"Photographer","terms":""},"craft/photographic_laboratory":{"name":"Photographic Laboratory","terms":"film"},"craft/plasterer":{"name":"Plasterer","terms":""},"craft/plumber":{"name":"Plumber","terms":"pipe"},"craft/pottery":{"name":"Pottery","terms":"ceramic"},"craft/rigger":{"name":"Rigger","terms":""},"craft/roofer":{"name":"Roofer","terms":""},"craft/saddler":{"name":"Saddler","terms":""},"craft/sailmaker":{"name":"Sailmaker","terms":""},"craft/sawmill":{"name":"Sawmill","terms":"lumber"},"craft/scaffolder":{"name":"Scaffolder","terms":""},"craft/sculpter":{"name":"Sculpter","terms":""},"craft/shoemaker":{"name":"Shoemaker","terms":"cobbler"},"craft/stonemason":{"name":"Stonemason","terms":"masonry"},"craft/sweep":{"name":"Chimney Sweep","terms":""},"craft/tiler":{"name":"Tiler","terms":""},"craft/tinsmith":{"name":"Tinsmith","terms":""},"craft/upholsterer":{"name":"Upholsterer","terms":""},"craft/watchmaker":{"name":"Watchmaker","terms":""},"craft/window_construction":{"name":"Window Construction","terms":"glass"},"craft/winery":{"name":"Winery","terms":""},"embankment":{"name":"Embankment","terms":""},"emergency/designated":{"name":"Emergency Access Designated","terms":""},"emergency/destination":{"name":"Emergency Access Destination","terms":""},"emergency/no":{"name":"Emergency Access No","terms":""},"emergency/official":{"name":"Emergency Access Official","terms":""},"emergency/private":{"name":"Emergency Access Private","terms":""},"emergency/yes":{"name":"Emergency Access Yes","terms":""},"emergency/ambulance_station":{"name":"Ambulance Station","terms":"EMS,EMT,rescue"},"emergency/defibrillator":{"name":"Defibrillator","terms":"AED"},"emergency/fire_hydrant":{"name":"Fire Hydrant","terms":"fire plug"},"emergency/phone":{"name":"Emergency Phone","terms":""},"entrance":{"name":"Entrance/Exit","terms":""},"footway/crossing":{"name":"Street Crossing","terms":""},"footway/crosswalk":{"name":"Pedestrian Crosswalk","terms":"zebra crossing"},"footway/sidewalk":{"name":"Sidewalk","terms":""},"ford":{"name":"Ford","terms":""},"golf/bunker":{"name":"Sand Trap","terms":"hazard,bunker"},"golf/fairway":{"name":"Fairway","terms":""},"golf/green":{"name":"Putting Green","terms":""},"golf/hole":{"name":"Golf Hole","terms":""},"golf/lateral_water_hazard_area":{"name":"Lateral Water Hazard","terms":""},"golf/lateral_water_hazard_line":{"name":"Lateral Water Hazard","terms":""},"golf/rough":{"name":"Rough","terms":""},"golf/tee":{"name":"Tee Box","terms":"teeing ground"},"golf/water_hazard_area":{"name":"Water Hazard","terms":""},"golf/water_hazard_line":{"name":"Water Hazard","terms":""},"healthcare/blood_donation":{"name":"Blood Donor Center","terms":"blood bank,blood donation,blood transfusion,apheresis,plasmapheresis,plateletpheresis,stem cell donation"},"highway/bridleway":{"name":"Bridle Path","terms":"bridleway,equestrian,horse"},"highway/bus_stop":{"name":"Bus Stop","terms":""},"highway/corridor":{"name":"Indoor Corridor","terms":"gallery,hall,hallway,indoor,passage,passageway"},"highway/crossing":{"name":"Street Crossing","terms":""},"highway/crosswalk":{"name":"Pedestrian Crosswalk","terms":"zebra crossing"},"highway/cycleway":{"name":"Cycle Path","terms":"bike"},"highway/footway":{"name":"Foot Path","terms":"hike,hiking,trackway,trail,walk"},"highway/give_way":{"name":"Yield Sign","terms":"give way,yield,sign"},"highway/living_street":{"name":"Living Street","terms":""},"highway/mini_roundabout":{"name":"Mini-Roundabout","terms":""},"highway/motorway_junction":{"name":"Motorway Junction / Exit","terms":""},"highway/motorway_link":{"name":"Motorway Link","terms":"ramp,on ramp,off ramp"},"highway/motorway":{"name":"Motorway","terms":"autobahn,expressway,freeway,highway,interstate,parkway,thruway,turnpike"},"highway/path":{"name":"Path","terms":"hike,hiking,trackway,trail,walk"},"highway/pedestrian":{"name":"Pedestrian Street","terms":""},"highway/primary_link":{"name":"Primary Link","terms":"ramp,on ramp,off ramp"},"highway/primary":{"name":"Primary Road","terms":""},"highway/raceway":{"name":"Racetrack (Motorsport)","terms":"auto*,formula one,kart,motocross,nascar,race*,track"},"highway/residential":{"name":"Residential Road","terms":""},"highway/rest_area":{"name":"Rest Area","terms":"rest stop"},"highway/road":{"name":"Unknown Road","terms":""},"highway/secondary_link":{"name":"Secondary Link","terms":"ramp,on ramp,off ramp"},"highway/secondary":{"name":"Secondary Road","terms":""},"highway/service":{"name":"Service Road","terms":""},"highway/service/alley":{"name":"Alley","terms":""},"highway/service/drive-through":{"name":"Drive-Through","terms":""},"highway/service/driveway":{"name":"Driveway","terms":""},"highway/service/emergency_access":{"name":"Emergency Access","terms":""},"highway/service/parking_aisle":{"name":"Parking Aisle","terms":""},"highway/services":{"name":"Service Area","terms":"services,travel plaza,service station"},"highway/speed_camera":{"name":"Speed Camera","terms":""},"highway/steps":{"name":"Steps","terms":"stairs,staircase"},"highway/stop":{"name":"Stop Sign","terms":"stop,halt,sign"},"highway/street_lamp":{"name":"Street Lamp","terms":"streetlight,street light,lamp,light,gaslight"},"highway/tertiary_link":{"name":"Tertiary Link","terms":"ramp,on ramp,off ramp"},"highway/tertiary":{"name":"Tertiary Road","terms":""},"highway/track":{"name":"Unmaintained Track Road","terms":"woods road,forest road,logging road,fire road,farm road,agricultural road,ranch road,carriage road,primitive,unmaintained,rut,offroad,4wd,4x4,four wheel drive,atv,quad,jeep,double track,two track"},"highway/traffic_mirror":{"name":"Traffic Mirror","terms":"blind spot,convex,corner,curved,roadside,round,safety,sphere,visibility"},"highway/traffic_signals":{"name":"Traffic Signals","terms":"light,stoplight,traffic light"},"highway/trunk_link":{"name":"Trunk Link","terms":"ramp,on ramp,off ramp"},"highway/trunk":{"name":"Trunk Road","terms":""},"highway/turning_circle":{"name":"Turning Circle","terms":"cul-de-sac"},"highway/turning_loop":{"name":"Turning Loop (Island)","terms":"cul-de-sac"},"highway/unclassified":{"name":"Minor/Unclassified Road","terms":""},"historic":{"name":"Historic Site","terms":""},"historic/archaeological_site":{"name":"Archaeological Site","terms":""},"historic/boundary_stone":{"name":"Boundary Stone","terms":""},"historic/castle":{"name":"Castle","terms":""},"historic/memorial":{"name":"Memorial","terms":""},"historic/monument":{"name":"Monument","terms":""},"historic/ruins":{"name":"Ruins","terms":""},"historic/tomb":{"name":"Tomb","terms":""},"historic/wayside_cross":{"name":"Wayside Cross","terms":""},"historic/wayside_shrine":{"name":"Wayside Shrine","terms":""},"junction":{"name":"Junction","terms":""},"landuse":{"name":"Land Use","terms":""},"landuse/farm":{"name":"Farmland","terms":""},"landuse/allotments":{"name":"Community Garden","terms":"allotment,garden"},"landuse/aquaculture":{"name":"Aquaculture","terms":"fish farm,crustacean,algae,aquafarming,shrimp farm,oyster farm,mariculture,algaculture"},"landuse/basin":{"name":"Basin","terms":""},"landuse/cemetery":{"name":"Cemetery","terms":""},"landuse/churchyard":{"name":"Churchyard","terms":""},"landuse/commercial":{"name":"Commercial Area","terms":""},"landuse/construction":{"name":"Construction","terms":""},"landuse/farmland":{"name":"Farmland","terms":"crop,grow,plant"},"landuse/farmyard":{"name":"Farmyard","terms":"crop,grow,plant"},"landuse/forest":{"name":"Forest","terms":"tree"},"landuse/garages":{"name":"Garages","terms":""},"landuse/grass":{"name":"Grass","terms":""},"landuse/harbour":{"name":"Harbor","terms":"boat"},"landuse/industrial":{"name":"Industrial Area","terms":""},"landuse/landfill":{"name":"Landfill","terms":"dump"},"landuse/meadow":{"name":"Meadow","terms":""},"landuse/military":{"name":"Military Area","terms":""},"landuse/military/airfield":{"name":"Military Airfield","terms":"air force,army,base,bomb,fight,force,guard,heli*,jet,marine,navy,plane,troop,war"},"landuse/military/barracks":{"name":"Barracks","terms":"air force,army,base,fight,force,guard,marine,navy,troop,war"},"landuse/military/bunker":{"name":"Military Bunker","terms":"air force,army,base,fight,force,guard,marine,navy,troop,war"},"landuse/military/checkpoint":{"name":"Checkpoint","terms":"air force,army,base,force,guard,marine,navy,troop,war"},"landuse/military/danger_area":{"name":"Danger Area","terms":"air force,army,base,blast,bomb,explo*,force,guard,mine,marine,navy,troop,war"},"landuse/military/naval_base":{"name":"Naval Base","terms":"base,fight,force,guard,marine,navy,ship,sub,troop,war"},"landuse/military/nuclear_explosion_site":{"name":"Nuclear Explosion Site","terms":"atom,blast,bomb,detonat*,nuke,site,test"},"landuse/military/obstacle_course":{"name":"Obstacle Course","terms":"army,base,force,guard,marine,navy,troop,war"},"landuse/military/office":{"name":"Military Office","terms":"air force,army,base,enlist,fight,force,guard,marine,navy,recruit,troop,war"},"landuse/military/range":{"name":"Military Range","terms":"air force,army,base,fight,fire,force,guard,gun,marine,navy,rifle,shoot*,snip*,train,troop,war"},"landuse/military/training_area":{"name":"Training Area","terms":"air force,army,base,fight,fire,force,guard,gun,marine,navy,rifle,shoot*,snip*,train,troop,war"},"landuse/orchard":{"name":"Orchard","terms":"fruit"},"landuse/plant_nursery":{"name":"Plant Nursery","terms":"flower,garden,grow,vivero"},"landuse/quarry":{"name":"Quarry","terms":""},"landuse/railway":{"name":"Railway Corridor","terms":"rail,train,track"},"landuse/recreation_ground":{"name":"Recreation Ground","terms":"playing fields"},"landuse/residential":{"name":"Residential Area","terms":""},"landuse/retail":{"name":"Retail Area","terms":""},"landuse/vineyard":{"name":"Vineyard","terms":"grape,wine"},"leisure":{"name":"Leisure","terms":""},"leisure/adult_gaming_centre":{"name":"Adult Gaming Center","terms":"gambling,slot machine"},"leisure/bird_hide":{"name":"Bird Hide","terms":"machan,ornithology"},"leisure/bowling_alley":{"name":"Bowling Alley","terms":""},"leisure/common":{"name":"Common","terms":"open space"},"leisure/dance":{"name":"Dance Hall","terms":"ballroom,jive,swing,tango,waltz"},"leisure/dog_park":{"name":"Dog Park","terms":""},"leisure/firepit":{"name":"Firepit","terms":"fireplace,campfire"},"leisure/fitness_centre":{"name":"Gym / Fitness Center","terms":"health,gym,leisure,studio"},"leisure/fitness_centre/yoga":{"name":"Yoga Studio","terms":"studio"},"leisure/fitness_station":{"name":"Outdoor Fitness Station","terms":"fitness,gym"},"leisure/garden":{"name":"Garden","terms":""},"leisure/golf_course":{"name":"Golf Course","terms":"links"},"leisure/horse_riding":{"name":"Horseback Riding Facility","terms":"equestrian,stable"},"leisure/ice_rink":{"name":"Ice Rink","terms":"hockey,skating,curling"},"leisure/marina":{"name":"Marina","terms":"boat"},"leisure/miniature_golf":{"name":"Miniature Golf","terms":"crazy golf,mini golf,putt-putt"},"leisure/nature_reserve":{"name":"Nature Reserve","terms":"protected,wildlife"},"leisure/park":{"name":"Park","terms":"esplanade,estate,forest,garden,grass,green,grounds,lawn,lot,meadow,parkland,place,playground,plaza,pleasure garden,recreation area,square,tract,village green,woodland"},"leisure/picnic_table":{"name":"Picnic Table","terms":"bench"},"leisure/pitch":{"name":"Sport Pitch","terms":"field"},"leisure/pitch/american_football":{"name":"American Football Field","terms":""},"leisure/pitch/baseball":{"name":"Baseball Diamond","terms":""},"leisure/pitch/basketball":{"name":"Basketball Court","terms":""},"leisure/pitch/beachvolleyball":{"name":"Beach Volleyball Court","terms":"volleyball"},"leisure/pitch/bowls":{"name":"Bowling Green","terms":""},"leisure/pitch/cricket":{"name":"Cricket Field","terms":""},"leisure/pitch/equestrian":{"name":"Riding Arena","terms":"dressage,equestrian,horse,horseback,riding"},"leisure/pitch/rugby_league":{"name":"Rugby League Field","terms":""},"leisure/pitch/rugby_union":{"name":"Rugby Union Field","terms":""},"leisure/pitch/skateboard":{"name":"Skate Park","terms":""},"leisure/pitch/soccer":{"name":"Soccer Field","terms":""},"leisure/pitch/table_tennis":{"name":"Ping Pong Table","terms":"table tennis,ping pong"},"leisure/pitch/tennis":{"name":"Tennis Court","terms":""},"leisure/pitch/volleyball":{"name":"Volleyball Court","terms":""},"leisure/playground":{"name":"Playground","terms":"jungle gym,play area"},"leisure/resort":{"name":"Resort","terms":""},"leisure/running_track":{"name":"Racetrack (Running)","terms":"race*,running,sprint,track"},"leisure/slipway":{"name":"Slipway","terms":"boat launch,boat ramp"},"leisure/sports_centre":{"name":"Sports Center / Complex","terms":""},"leisure/sports_centre/swimming":{"name":"Swimming Pool Facility","terms":"dive,water"},"leisure/stadium":{"name":"Stadium","terms":""},"leisure/swimming_pool":{"name":"Swimming Pool","terms":"dive,water"},"leisure/track":{"name":"Racetrack (Non-Motorsport)","terms":"cycle,dog,greyhound,horse,race*,track"},"leisure/water_park":{"name":"Water Park","terms":"swim,pool,dive"},"line":{"name":"Line","terms":""},"man_made":{"name":"Man Made","terms":""},"man_made/embankment":{"name":"Embankment","terms":""},"man_made/adit":{"name":"Adit","terms":"entrance,underground,mine,cave"},"man_made/breakwater":{"name":"Breakwater","terms":""},"man_made/bridge":{"name":"Bridge","terms":""},"man_made/chimney":{"name":"Chimney","terms":""},"man_made/cutline":{"name":"Cut line","terms":""},"man_made/flagpole":{"name":"Flagpole","terms":""},"man_made/gasometer":{"name":"Gasometer","terms":"gas holder"},"man_made/groyne":{"name":"Groyne","terms":""},"man_made/lighthouse":{"name":"Lighthouse","terms":""},"man_made/mast":{"name":"Mast","terms":"antenna,broadcast tower,cell phone tower,cell tower,communication mast,communication tower,guyed tower,mobile phone tower,radio mast,radio tower,television tower,transmission mast,transmission tower,tv tower"},"man_made/observation":{"name":"Observation Tower","terms":"lookout tower,fire tower"},"man_made/petroleum_well":{"name":"Oil Well","terms":"drilling rig,oil derrick,oil drill,oil horse,oil rig,oil pump,petroleum well,pumpjack"},"man_made/pier":{"name":"Pier","terms":"dock"},"man_made/pipeline":{"name":"Pipeline","terms":""},"man_made/pumping_station":{"name":"Pumping Station","terms":""},"man_made/silo":{"name":"Silo","terms":"grain,corn,wheat"},"man_made/storage_tank":{"name":"Storage Tank","terms":"water,oil,gas,petrol"},"man_made/surveillance_camera":{"name":"Surveillance Camera","terms":"anpr,alpr,camera,car plate recognition,cctv,guard,license plate recognition,monitoring,number plate recognition,security,video,webcam"},"man_made/surveillance":{"name":"Surveillance","terms":"anpr,alpr,camera,car plate recognition,cctv,guard,license plate recognition,monitoring,number plate recognition,security,video,webcam"},"man_made/survey_point":{"name":"Survey Point","terms":""},"man_made/tower":{"name":"Tower","terms":""},"man_made/wastewater_plant":{"name":"Wastewater Plant","terms":"sewage*,water treatment plant,reclamation plant"},"man_made/water_tower":{"name":"Water Tower","terms":""},"man_made/water_well":{"name":"Water Well","terms":""},"man_made/water_works":{"name":"Water Works","terms":""},"man_made/works":{"name":"Factory","terms":"assembly,build,brewery,car,plant,plastic,processing,manufacture,refinery"},"natural":{"name":"Natural","terms":""},"natural/bare_rock":{"name":"Bare Rock","terms":"rock"},"natural/bay":{"name":"Bay","terms":""},"natural/beach":{"name":"Beach","terms":"shore"},"natural/cave_entrance":{"name":"Cave Entrance","terms":"cavern,hollow,grotto,shelter,cavity"},"natural/cliff":{"name":"Cliff","terms":"escarpment"},"natural/coastline":{"name":"Coastline","terms":"shore"},"natural/fell":{"name":"Fell","terms":""},"natural/glacier":{"name":"Glacier","terms":""},"natural/grassland":{"name":"Grassland","terms":"prairie,savanna"},"natural/heath":{"name":"Heath","terms":""},"natural/peak":{"name":"Peak","terms":"acme,aiguille,alp,climax,crest,crown,hill,mount,mountain,pinnacle,summit,tip,top"},"natural/ridge":{"name":"Ridge","terms":"crest"},"natural/saddle":{"name":"Saddle","terms":"pass,mountain pass,top"},"natural/sand":{"name":"Sand","terms":"desert"},"natural/scree":{"name":"Scree","terms":"loose rocks"},"natural/scrub":{"name":"Scrub","terms":"bush,shrubs"},"natural/spring":{"name":"Spring","terms":""},"natural/tree_row":{"name":"Tree row","terms":""},"natural/tree":{"name":"Tree","terms":""},"natural/volcano":{"name":"Volcano","terms":"mountain,crater"},"natural/water":{"name":"Water","terms":""},"natural/water/lake":{"name":"Lake","terms":"lakelet,loch,mere"},"natural/water/pond":{"name":"Pond","terms":"lakelet,millpond,tarn,pool,mere"},"natural/water/reservoir":{"name":"Reservoir","terms":""},"natural/wetland":{"name":"Wetland","terms":""},"natural/wood":{"name":"Wood","terms":"tree"},"noexit/yes":{"name":"No Exit","terms":"no exit,road end,dead end"},"office":{"name":"Office","terms":""},"office/travel_agent":{"name":"Travel Agency","terms":""},"office/accountant":{"name":"Accountant","terms":""},"office/administrative":{"name":"Administrative Office","terms":""},"office/architect":{"name":"Architect","terms":""},"office/company":{"name":"Company Office","terms":""},"office/coworking":{"name":"Coworking Space","terms":"coworking,office"},"office/educational_institution":{"name":"Educational Institution","terms":""},"office/employment_agency":{"name":"Employment Agency","terms":"job"},"office/estate_agent":{"name":"Real Estate Office","terms":""},"office/financial":{"name":"Financial Office","terms":""},"office/government":{"name":"Government Office","terms":""},"office/government/register_office":{"name":"Register Office","terms":"clerk,marriage,death,birth,certificate"},"office/insurance":{"name":"Insurance Office","terms":""},"office/it":{"name":"IT Office","terms":""},"office/lawyer":{"name":"Law Office","terms":""},"office/lawyer/notary":{"name":"Notary Office","terms":"clerk,signature,wills,deeds,estate"},"office/newspaper":{"name":"Newspaper","terms":""},"office/ngo":{"name":"NGO Office","terms":""},"office/physician":{"name":"Physician","terms":""},"office/political_party":{"name":"Political Party","terms":""},"office/research":{"name":"Research Office","terms":""},"office/telecommunication":{"name":"Telecom Office","terms":""},"office/therapist":{"name":"Therapist","terms":""},"piste":{"name":"Piste/Ski Trail","terms":"ski,sled,sleigh,snowboard,nordic,downhill,snowmobile"},"place/farm":{"name":"Farm","terms":""},"place/city":{"name":"City","terms":""},"place/hamlet":{"name":"Hamlet","terms":""},"place/island":{"name":"Island","terms":"archipelago,atoll,bar,cay,isle,islet,key,reef"},"place/isolated_dwelling":{"name":"Isolated Dwelling","terms":""},"place/locality":{"name":"Locality","terms":""},"place/neighbourhood":{"name":"Neighborhood","terms":"neighbourhood"},"place/quarter":{"name":"Sub-Borough / Quarter","terms":"boro,borough,quarter"},"place/square":{"name":"Square","terms":""},"place/suburb":{"name":"Borough / Suburb","terms":"boro,borough,quarter"},"place/town":{"name":"Town","terms":""},"place/village":{"name":"Village","terms":""},"point":{"name":"Point","terms":""},"power/sub_station":{"name":"Substation","terms":""},"power/generator":{"name":"Power Generator","terms":""},"power/line":{"name":"Power Line","terms":""},"power/minor_line":{"name":"Minor Power Line","terms":""},"power/plant":{"name":"Power Station Grounds","terms":"coal,gas,generat*,hydro,nuclear,power,station"},"power/pole":{"name":"Power Pole","terms":""},"power/substation":{"name":"Substation","terms":""},"power/tower":{"name":"High-Voltage Tower","terms":""},"power/transformer":{"name":"Transformer","terms":""},"public_transport/platform":{"name":"Platform","terms":""},"public_transport/stop_position":{"name":"Stop Position","terms":""},"railway/abandoned":{"name":"Abandoned Railway","terms":""},"railway/crossing":{"name":"Railway Crossing (Path)","terms":"crossing,pedestrian crossing,railroad crossing,level crossing,grade crossing,path through railroad,train crossing"},"railway/disused":{"name":"Disused Railway","terms":""},"railway/funicular":{"name":"Funicular","terms":"venicular,cliff railway,cable car,cable railway,funicular railway"},"railway/halt":{"name":"Railway Halt","terms":"break,interrupt,rest,wait,interruption"},"railway/level_crossing":{"name":"Railway Crossing (Road)","terms":"crossing,railroad crossing,level crossing,grade crossing,road through railroad,train crossing"},"railway/monorail":{"name":"Monorail","terms":""},"railway/narrow_gauge":{"name":"Narrow Gauge Rail","terms":"narrow gauge railway,narrow gauge railroad"},"railway/platform":{"name":"Railway Platform","terms":""},"railway/rail":{"name":"Rail","terms":""},"railway/station":{"name":"Railway Station","terms":"train station,station"},"railway/subway_entrance":{"name":"Subway Entrance","terms":""},"railway/subway":{"name":"Subway","terms":""},"railway/tram_stop":{"name":"Tram Stop","terms":"light rail,streetcar,tram,trolley"},"railway/tram":{"name":"Tram","terms":"light rail,streetcar,tram,trolley"},"relation":{"name":"Relation","terms":""},"route/ferry":{"name":"Ferry Route","terms":""},"shop":{"name":"Shop","terms":""},"shop/fishmonger":{"name":"Fishmonger","terms":""},"shop/vacant":{"name":"Vacant Shop","terms":""},"shop/alcohol":{"name":"Liquor Store","terms":"alcohol,beer,booze,wine"},"shop/anime":{"name":"Anime Shop","terms":"manga,japan,cosplay,figurine,dakimakura"},"shop/antiques":{"name":"Antiques Shop","terms":""},"shop/art":{"name":"Art Store","terms":"art*,exhibit*,gallery"},"shop/baby_goods":{"name":"Baby Goods Store","terms":""},"shop/bag":{"name":"Bag/Luggage Store","terms":"handbag,purse"},"shop/bakery":{"name":"Bakery","terms":""},"shop/bathroom_furnishing":{"name":"Bathroom Furnishing Store","terms":""},"shop/beauty":{"name":"Beauty Shop","terms":"spa,salon,tanning"},"shop/beauty/nails":{"name":"Nail Salon","terms":"manicure,pedicure"},"shop/beauty/tanning":{"name":"Tanning Salon","terms":""},"shop/bed":{"name":"Bedding/Mattress Store","terms":""},"shop/beverages":{"name":"Beverage Store","terms":""},"shop/bicycle":{"name":"Bicycle Shop","terms":"bike,repair"},"shop/bookmaker":{"name":"Bookmaker","terms":"betting"},"shop/books":{"name":"Book Store","terms":""},"shop/boutique":{"name":"Boutique","terms":""},"shop/butcher":{"name":"Butcher","terms":"meat"},"shop/candles":{"name":"Candle Shop","terms":""},"shop/car_parts":{"name":"Car Parts Store","terms":"auto"},"shop/car_repair":{"name":"Car Repair Shop","terms":"auto,garage,service"},"shop/car":{"name":"Car Dealership","terms":"auto"},"shop/carpet":{"name":"Carpet Store","terms":"rug"},"shop/charity":{"name":"Charity Store","terms":"thrift,op shop,nonprofit"},"shop/cheese":{"name":"Cheese Store","terms":""},"shop/chemist":{"name":"Drugstore","terms":"med*,drug*,gift"},"shop/chocolate":{"name":"Chocolate Store","terms":""},"shop/clothes":{"name":"Clothing Store","terms":""},"shop/coffee":{"name":"Coffee Store","terms":""},"shop/computer":{"name":"Computer Store","terms":""},"shop/confectionery":{"name":"Candy Store","terms":""},"shop/convenience":{"name":"Convenience Store","terms":""},"shop/copyshop":{"name":"Copy Store","terms":""},"shop/cosmetics":{"name":"Cosmetics Store","terms":""},"shop/craft":{"name":"Arts and Crafts Store","terms":"art*,paint*,frame"},"shop/curtain":{"name":"Curtain Store","terms":"drape*,window"},"shop/dairy":{"name":"Dairy Store","terms":"milk,egg,cheese"},"shop/deli":{"name":"Deli","terms":"lunch,meat,sandwich"},"shop/department_store":{"name":"Department Store","terms":""},"shop/doityourself":{"name":"DIY Store","terms":""},"shop/dry_cleaning":{"name":"Dry Cleaner","terms":""},"shop/e-cigarette":{"name":"E-Cigarette Shop","terms":"electronic,vapor"},"shop/electronics":{"name":"Electronics Store","terms":"appliance,audio,computer,tv"},"shop/erotic":{"name":"Erotic Store","terms":"sex,porn"},"shop/fabric":{"name":"Fabric Store","terms":"sew"},"shop/farm":{"name":"Produce Stand","terms":"farm shop,farm stand"},"shop/fashion":{"name":"Fashion Store","terms":""},"shop/florist":{"name":"Florist","terms":"flower"},"shop/frame":{"name":"Framing Shop","terms":"art*,paint*,photo*,frame"},"shop/funeral_directors":{"name":"Funeral Home","terms":"undertaker,memorial home"},"shop/furnace":{"name":"Furnace Store","terms":"oven,stove"},"shop/furniture":{"name":"Furniture Store","terms":"chair,sofa,table"},"shop/garden_centre":{"name":"Garden Center","terms":"landscape,mulch,shrub,tree"},"shop/gas":{"name":"Bottled Gas Shop","terms":"cng,lpg,natural gas,propane,refill,tank"},"shop/gift":{"name":"Gift Shop","terms":"souvenir"},"shop/greengrocer":{"name":"Greengrocer","terms":"fruit,vegetable"},"shop/hairdresser":{"name":"Hairdresser","terms":"barber"},"shop/hardware":{"name":"Hardware Store","terms":""},"shop/hearing_aids":{"name":"Hearing Aids Store","terms":""},"shop/herbalist":{"name":"Herbalist","terms":""},"shop/hifi":{"name":"Hifi Store","terms":"stereo,video"},"shop/houseware":{"name":"Houseware Store","terms":"home,household"},"shop/interior_decoration":{"name":"Interior Decoration Store","terms":""},"shop/jewelry":{"name":"Jeweler","terms":"diamond,gem,ring"},"shop/kiosk":{"name":"News Kiosk","terms":""},"shop/kitchen":{"name":"Kitchen Design Store","terms":""},"shop/laundry":{"name":"Laundry","terms":""},"shop/leather":{"name":"Leather Store","terms":""},"shop/locksmith":{"name":"Locksmith","terms":"key,lockpick"},"shop/lottery":{"name":"Lottery Shop","terms":""},"shop/mall":{"name":"Mall","terms":"shopping"},"shop/massage":{"name":"Massage Shop","terms":""},"shop/medical_supply":{"name":"Medical Supply Store","terms":""},"shop/mobile_phone":{"name":"Mobile Phone Store","terms":""},"shop/money_lender":{"name":"Money Lender","terms":""},"shop/motorcycle":{"name":"Motorcycle Dealership","terms":"bike"},"shop/music":{"name":"Music Store","terms":"CD,vinyl"},"shop/musical_instrument":{"name":"Musical Instrument Store","terms":"guitar"},"shop/newsagent":{"name":"Newspaper/Magazine Shop","terms":""},"shop/nutrition_supplements":{"name":"Nutrition Supplements Store","terms":""},"shop/optician":{"name":"Optician","terms":"eye,glasses"},"shop/organic":{"name":"Organic Goods Store","terms":""},"shop/outdoor":{"name":"Outdoors Store","terms":"camping,climbing,hiking"},"shop/paint":{"name":"Paint Store","terms":""},"shop/pastry":{"name":"Pastry Shop","terms":"patisserie,cake shop,cakery"},"shop/pawnbroker":{"name":"Pawn Shop","terms":""},"shop/perfumery":{"name":"Perfume Store","terms":""},"shop/pet":{"name":"Pet Store","terms":"animal,cat,dog,fish,kitten,puppy,reptile"},"shop/photo":{"name":"Photography Store","terms":"camera,film"},"shop/pyrotechnics":{"name":"Fireworks Store","terms":""},"shop/radiotechnics":{"name":"Radio/Electronic Component Store","terms":""},"shop/religion":{"name":"Religious Store","terms":""},"shop/scuba_diving":{"name":"Scuba Diving Shop","terms":""},"shop/seafood":{"name":"Seafood Shop","terms":"fishmonger"},"shop/second_hand":{"name":"Consignment/Thrift Store","terms":"secondhand,second hand,resale,thrift,used"},"shop/shoes":{"name":"Shoe Store","terms":""},"shop/sports":{"name":"Sporting Goods Store","terms":""},"shop/stationery":{"name":"Stationery Store","terms":"card,paper"},"shop/storage_rental":{"name":"Storage Rental","terms":""},"shop/supermarket":{"name":"Supermarket","terms":"grocery,store,shop"},"shop/tailor":{"name":"Tailor","terms":"clothes,suit"},"shop/tattoo":{"name":"Tattoo Parlor","terms":""},"shop/tea":{"name":"Tea Store","terms":""},"shop/ticket":{"name":"Ticket Seller","terms":""},"shop/tobacco":{"name":"Tobacco Shop","terms":""},"shop/toys":{"name":"Toy Store","terms":""},"shop/travel_agency":{"name":"Travel Agency","terms":""},"shop/tyres":{"name":"Tire Store","terms":""},"shop/vacuum_cleaner":{"name":"Vacuum Cleaner Store","terms":""},"shop/variety_store":{"name":"Variety Store","terms":""},"shop/video_games":{"name":"Video Game Store","terms":""},"shop/video":{"name":"Video Store","terms":"DVD"},"shop/watches":{"name":"Watches Shop","terms":""},"shop/water_sports":{"name":"Watersport/Swim Shop","terms":""},"shop/weapons":{"name":"Weapon Shop","terms":"ammo,gun,knife,knives"},"shop/window_blind":{"name":"Window Blind Store","terms":""},"shop/wine":{"name":"Wine Shop","terms":""},"tourism":{"name":"Tourism","terms":""},"tourism/alpine_hut":{"name":"Alpine Hut","terms":""},"tourism/apartment":{"name":"Guest Apartment / Condo","terms":""},"tourism/aquarium":{"name":"Aquarium","terms":"fish,sea,water"},"tourism/artwork":{"name":"Artwork","terms":"mural,sculpture,statue"},"tourism/attraction":{"name":"Tourist Attraction","terms":""},"tourism/camp_site":{"name":"Campground","terms":"tent,rv"},"tourism/caravan_site":{"name":"RV Park","terms":"Motor Home,Camper"},"tourism/chalet":{"name":"Chalet","terms":""},"tourism/gallery":{"name":"Art Gallery","terms":"art*,exhibit*,paint*,photo*,sculpt*"},"tourism/guest_house":{"name":"Guest House","terms":"B&B,Bed and Breakfast"},"tourism/hostel":{"name":"Hostel","terms":""},"tourism/hotel":{"name":"Hotel","terms":""},"tourism/information":{"name":"Information","terms":""},"tourism/information/board":{"name":"Information Board","terms":""},"tourism/information/guidepost":{"name":"Guidepost","terms":""},"tourism/information/map":{"name":"Map","terms":""},"tourism/information/office":{"name":"Tourist Information Office","terms":""},"tourism/motel":{"name":"Motel","terms":""},"tourism/museum":{"name":"Museum","terms":"art*,exhibit*,gallery,foundation,hall,institution,paint*,photo*,sculpt*"},"tourism/picnic_site":{"name":"Picnic Site","terms":"camp"},"tourism/theme_park":{"name":"Theme Park","terms":""},"tourism/viewpoint":{"name":"Viewpoint","terms":""},"tourism/zoo":{"name":"Zoo","terms":"animal"},"traffic_calming":{"name":"Traffic Calming","terms":"bump,hump,slow,speed"},"traffic_calming/bump":{"name":"Speed Bump","terms":"hump,speed,slow"},"traffic_calming/chicane":{"name":"Traffic Chicane","terms":"driveway link,speed,slow"},"traffic_calming/choker":{"name":"Traffic Choker","terms":"speed,slow"},"traffic_calming/cushion":{"name":"Speed Cushion","terms":"bump,hump,speed,slow"},"traffic_calming/dip":{"name":"Dip","terms":"speed,slow"},"traffic_calming/hump":{"name":"Speed Hump","terms":"bump,speed,slow"},"traffic_calming/island":{"name":"Traffic Island","terms":"circle,roundabout,slow"},"traffic_calming/rumble_strip":{"name":"Rumble Strip","terms":"audible lines,sleeper lines,growlers"},"traffic_calming/table":{"name":"Raised Pedestrian Crossing","terms":"flat top,hump,speed,slow"},"type/multipolygon":{"name":"Multipolygon","terms":""},"type/boundary":{"name":"Boundary","terms":""},"type/boundary/administrative":{"name":"Administrative Boundary","terms":""},"type/restriction":{"name":"Restriction","terms":""},"type/restriction/no_left_turn":{"name":"No Left Turn","terms":""},"type/restriction/no_right_turn":{"name":"No Right Turn","terms":""},"type/restriction/no_straight_on":{"name":"No Straight On","terms":""},"type/restriction/no_u_turn":{"name":"No U-turn","terms":""},"type/restriction/only_left_turn":{"name":"Left Turn Only","terms":""},"type/restriction/only_right_turn":{"name":"Right Turn Only","terms":""},"type/restriction/only_straight_on":{"name":"No Turns","terms":""},"type/route_master":{"name":"Route Master","terms":""},"type/route":{"name":"Route","terms":""},"type/route/bicycle":{"name":"Cycle Route","terms":""},"type/route/bus":{"name":"Bus Route","terms":""},"type/route/detour":{"name":"Detour Route","terms":""},"type/route/ferry":{"name":"Ferry Route","terms":""},"type/route/foot":{"name":"Foot Route","terms":""},"type/route/hiking":{"name":"Hiking Route","terms":""},"type/route/horse":{"name":"Riding Route","terms":""},"type/route/pipeline":{"name":"Pipeline Route","terms":""},"type/route/power":{"name":"Power Route","terms":""},"type/route/road":{"name":"Road Route","terms":""},"type/route/train":{"name":"Train Route","terms":""},"type/route/tram":{"name":"Tram Route","terms":""},"type/site":{"name":"Site","terms":""},"vertex":{"name":"Other","terms":""},"waterway/boatyard":{"name":"Boatyard","terms":""},"waterway/canal":{"name":"Canal","terms":""},"waterway/dam":{"name":"Dam","terms":""},"waterway/ditch":{"name":"Ditch","terms":""},"waterway/dock":{"name":"Wet Dock / Dry Dock","terms":"boat,ship,vessel,marine"},"waterway/drain":{"name":"Drain","terms":""},"waterway/fuel":{"name":"Marine Fuel Station","terms":"petrol,gas,diesel,boat"},"waterway/river":{"name":"River","terms":"beck,branch,brook,course,creek,estuary,rill,rivulet,run,runnel,stream,tributary,watercourse"},"waterway/riverbank":{"name":"Riverbank","terms":""},"waterway/sanitary_dump_station":{"name":"Marine Toilet Disposal","terms":"Boat,Watercraft,Sanitary,Dump Station,Pumpout,Pump out,Elsan,CDP,CTDP,Chemical Toilet"},"waterway/stream":{"name":"Stream","terms":"beck,branch,brook,burn,course,creek,current,drift,flood,flow,freshet,race,rill,rindle,rivulet,run,runnel,rush,spate,spritz,surge,tide,torrent,tributary,watercourse"},"waterway/water_point":{"name":"Marine Drinking Water","terms":""},"waterway/waterfall":{"name":"Waterfall","terms":"fall"},"waterway/weir":{"name":"Weir","terms":""}}}};
18624
18625 var dataImagery = [{"id":"sjcgis.org-Aerials_2013_WM","name":"2013 aerial imagery for San Juan County WA","type":"tms","template":"http://sjcgis.org/arcgis/rest/services/Basemaps/Aerials_2013_WM/MapServer/tile/{zoom}/{y}/{x}","description":"Public domain aerial imagery taken in May/June 2013 from San Juan County, WA. Resolution is 9 inch.","scaleExtent":[0,19],"polygon":[[[-123.02167396992,48.44667085335],[-122.9466579482,48.44780949945],[-122.90151100606,48.41306930778],[-122.80263405293,48.40771378918],[-122.79199104756,48.44279926564],[-122.8088138625,48.47865708877],[-122.73911934346,48.49572334021],[-122.78546791524,48.62160819278],[-122.73087959737,48.6361306644],[-122.75559883565,48.71207854113],[-122.95747261494,48.71592956034],[-122.97086220235,48.695765074],[-122.99970131367,48.69780454658],[-123.00347786397,48.73427448605],[-123.04330330342,48.74310484148],[-123.0762622878,48.70528190578],[-123.08484535664,48.66334903433],[-123.12844734639,48.66380254936],[-123.22698097676,48.70301615666],[-123.24655037373,48.68352650341],[-123.17445259541,48.64701977542],[-123.21513634175,48.60106537642],[-123.21393471211,48.57335906966],[-123.18080406636,48.56574853208],[-123.16621284932,48.52006125122],[-123.10235481709,48.47683634964],[-123.02167396992,48.44667085335]],[[-122.98339348286,48.78214357977],[-122.93498497456,48.76653172572],[-122.91181068867,48.73857664785],[-122.80229073018,48.73982194177],[-122.81945686787,48.75498940888],[-122.93429832906,48.79571515892],[-122.98373680562,48.79435816618],[-122.98339348286,48.78214357977]]]},{"id":"sjcgis.org-Aerials_2016_WM","name":"2016 aerial imagery for San Juan County WA","type":"tms","template":"http://sjcgis.org/arcgis/rest/services/Basemaps/Aerials_2016_WM/MapServer/tile/{zoom}/{y}/{x}","description":"Public domain aerial imagery taken in May, June, and July from San Juan County, WA. Resolution is 6 inch countywide.","scaleExtent":[0,19],"polygon":[[[-123.02167396992,48.44667085335],[-122.9466579482,48.44780949945],[-122.90151100606,48.41306930778],[-122.80263405293,48.40771378918],[-122.79199104756,48.44279926564],[-122.8088138625,48.47865708877],[-122.73911934346,48.49572334021],[-122.78546791524,48.62160819278],[-122.73087959737,48.6361306644],[-122.75559883565,48.71207854113],[-122.95747261494,48.71592956034],[-122.97086220235,48.695765074],[-122.99970131367,48.69780454658],[-123.00347786397,48.73427448605],[-123.04330330342,48.74310484148],[-123.0762622878,48.70528190578],[-123.08484535664,48.66334903433],[-123.12844734639,48.66380254936],[-123.22698097676,48.70301615666],[-123.24655037373,48.68352650341],[-123.17445259541,48.64701977542],[-123.21513634175,48.60106537642],[-123.21393471211,48.57335906966],[-123.18080406636,48.56574853208],[-123.16621284932,48.52006125122],[-123.10235481709,48.47683634964],[-123.02167396992,48.44667085335]],[[-122.98339348286,48.78214357977],[-122.93498497456,48.76653172572],[-122.91181068867,48.73857664785],[-122.80229073018,48.73982194177],[-122.81945686787,48.75498940888],[-122.93429832906,48.79571515892],[-122.98373680562,48.79435816618],[-122.98339348286,48.78214357977]]],"best":true},{"id":"OS7","name":"7th Series (OS7)","type":"tms","template":"http://ooc.openstreetmap.org/os7/{zoom}/{x}/{y}.jpg","polygon":[[[-6.4585407,49.9044128],[-6.3872009,49.9841116],[-6.2296827,49.9896159],[-6.2171269,49.8680087],[-6.4551164,49.8591793],[-6.4585407,49.9044128]],[[-1.4495137,60.8634056],[-0.7167114,60.8545122],[-0.7349744,60.4359756],[-0.6938826,60.4168218],[-0.7258429,60.3942735],[-0.7395401,60.0484714],[-0.9267357,60.0461918],[-0.9381501,59.8266157],[-1.4586452,59.831205],[-1.4455187,60.0535999],[-1.463211,60.0535999],[-1.4643524,60.0630002],[-1.5716475,60.0638546],[-1.5693646,60.1790005],[-1.643558,60.1807033],[-1.643558,60.1892162],[-1.8216221,60.1894999],[-1.8204807,60.3615507],[-1.8415973,60.3697345],[-1.8216221,60.3832755],[-1.8179852,60.5934321],[-1.453168,60.5934321],[-1.4495137,60.8634056]],[[-4.9089213,54.4242078],[-4.282598,54.4429861],[-4.2535417,54.029769],[-4.8766366,54.0221831],[-4.9089213,54.4242078]],[[-5.8667408,59.1444603],[-5.7759966,59.1470945],[-5.7720016,59.1014052],[-5.8621751,59.0990605],[-5.8667408,59.1444603]],[[-1.7065887,59.5703599],[-1.5579165,59.5693481],[-1.5564897,59.4965695],[-1.7054472,59.4975834],[-1.7065887,59.5703599]],[[-7.6865827,58.2940975],[-7.5330594,58.3006957],[-7.5256401,58.2646905],[-7.6797341,58.2577853],[-7.6865827,58.2940975]],[[-4.5338281,59.0359871],[-4.481322,59.0371616],[-4.4796099,59.0186583],[-4.5332574,59.0180707],[-4.5338281,59.0359871]],[[-8.6710698,57.8769896],[-8.4673234,57.8897332],[-8.4467775,57.7907],[-8.6510947,57.7779213],[-8.6710698,57.8769896]],[[-5.2395519,50.3530581],[-5.7920073,50.3384899],[-5.760047,49.9317027],[-4.6551363,49.9581461],[-4.677965,50.2860073],[-4.244219,50.2801723],[-4.2487848,50.2042525],[-3.3812929,50.2042525],[-3.4223846,50.5188201],[-3.1164796,50.5246258],[-3.1210453,50.6579592],[-2.6736357,50.6619495],[-2.5953453,50.6394325],[-2.5905026,50.5728419],[-2.4791203,50.5733545],[-2.4758919,50.5066704],[-2.3967943,50.5056438],[-2.401637,50.5723293],[-1.0400296,50.5718167],[-1.0335726,50.7059289],[-0.549302,50.7038843],[-0.5460736,50.7886618],[-0.0924734,50.7856002],[-0.0876307,50.7181949],[0.4789659,50.7120623],[0.487037,50.8182467],[0.9761503,50.8049868],[0.9922927,51.0126311],[1.4491213,51.0004424],[1.4781775,51.4090372],[1.0229632,51.4271576],[1.035877,51.7640881],[1.6105448,51.7500992],[1.646058,52.1560003],[1.7267698,52.1540195],[1.749369,52.4481811],[1.7870672,52.4811624],[1.759102,52.522505],[1.7933451,52.9602749],[0.3798147,52.9958468],[0.3895238,53.2511239],[0.3478614,53.2511239],[0.3238912,53.282186],[0.3461492,53.6538501],[0.128487,53.6575466],[0.116582,53.6674703],[0.1350586,54.0655731],[-0.0609831,54.065908],[-0.0414249,54.4709448],[-0.5662701,54.4771794],[-0.5592078,54.6565127],[-1.1665638,54.6623485],[-1.1637389,54.842611],[-1.3316194,54.843909],[-1.3257065,55.2470842],[-1.529453,55.2487108],[-1.524178,55.6540122],[-1.7638798,55.6540122],[-1.7733693,55.9719116],[-2.1607858,55.9682981],[-2.1543289,56.0621387],[-2.4578051,56.0585337],[-2.4190635,56.641717],[-2.0962164,56.641717],[-2.0833025,57.0021322],[-1.9283359,57.0126802],[-1.9180966,57.3590895],[-1.7502161,57.3625721],[-1.7695869,57.7608634],[-3.6937554,57.7574187],[-3.7066693,57.9806386],[-3.5969013,57.9772149],[-3.6033582,58.1207277],[-3.0222335,58.1309566],[-3.0286905,58.5410788],[-2.8478961,58.530968],[-2.86081,58.8430508],[-2.679624,58.8414991],[-2.6841897,58.885175],[-2.6339665,58.9052239],[-2.679624,58.9335083],[-2.6887555,59.0229231],[-2.3668703,59.0229231],[-2.3702946,59.2652861],[-2.3429001,59.2821989],[-2.3714361,59.2996861],[-2.3737189,59.3707083],[-2.3429001,59.385825],[-2.3725775,59.400354],[-2.3714361,59.4259098],[-3.0734196,59.4230067],[-3.0711368,59.3433649],[-3.103097,59.3311405],[-3.0745611,59.3136695],[-3.0722782,59.232603],[-3.3850319,59.1484167],[-3.3747589,58.9352753],[-3.5653789,58.9323303],[-3.554829,58.69759],[-5.2808579,58.6667732],[-5.2534159,58.3514125],[-5.5068508,58.3437887],[-5.4761804,58.0323557],[-5.8974958,58.0212436],[-5.8522972,57.6171758],[-6.1396311,57.6137174],[-6.1541592,57.7423183],[-6.2913692,57.7380102],[-6.3365678,58.1398784],[-6.1121891,58.1466944],[-6.1473778,58.5106285],[-6.2934817,58.5416182],[-6.8413713,58.2977321],[-7.0057382,58.2929331],[-7.1016189,58.2064403],[-7.2573132,58.1793148],[-7.2531092,58.1004928],[-7.4070698,58.0905566],[-7.391347,57.7911354],[-7.790991,57.7733151],[-7.7624215,57.5444165],[-7.698501,57.1453194],[-7.7943817,57.1304547],[-7.716764,56.7368628],[-7.0122067,56.7654359],[-6.979922,56.5453858],[-7.0638622,56.5453858],[-7.0444914,56.3562587],[-6.500676,56.3812917],[-6.4491433,55.9793649],[-6.563287,55.9691456],[-6.5393742,55.7030135],[-6.5595521,55.6907321],[-6.5345315,55.6761713],[-6.5216176,55.5704434],[-5.8912587,55.5923416],[-5.8560127,55.2320733],[-5.2293639,55.2515958],[-5.1837064,54.6254139],[-3.6655956,54.6518373],[-3.6496155,54.4320023],[-3.5400375,54.4306744],[-3.530906,54.0290181],[-3.0697656,54.030359],[-3.0675737,53.8221388],[-3.0804876,53.7739911],[-3.0619239,53.7477488],[-3.0611168,53.6737049],[-3.2144691,53.6708361],[-3.2057699,53.4226163],[-3.2799632,53.355224],[-3.2896655,53.3608441],[-3.3327547,53.364931],[-3.3761293,53.3540318],[-4.0888976,53.3433102],[-4.0945474,53.4612036],[-4.697412,53.4448624],[-4.6882805,53.3318598],[-4.7202407,53.2895771],[-4.6837148,53.2486184],[-4.6768661,53.1542644],[-4.8480816,53.1446807],[-4.8178336,52.7440299],[-4.2545751,52.7558939],[-4.228876,52.254876],[-4.2607571,52.2536408],[-4.2724603,52.2432637],[-4.8136263,52.230095],[-4.8079191,52.1138892],[-5.3889104,52.0991668],[-5.3717888,51.9129667],[-5.4208706,51.9101502],[-5.414022,51.8453218],[-5.3683645,51.8474373],[-5.3466772,51.5595332],[-4.773676,51.5758518],[-4.7656859,51.4885146],[-4.1915432,51.4970427],[-4.1869775,51.4344663],[-3.6151177,51.4444274],[-3.6105519,51.3746543],[-3.1494115,51.3789292],[-3.1494115,51.2919281],[-4.3038735,51.2745907],[-4.2861169,51.0508721],[-4.8543277,51.0366633],[-4.8372201,50.7212787],[-5.2618345,50.7082694],[-5.2395519,50.3530581]],[[-2.1502671,60.171318],[-2.0030218,60.1696146],[-2.0013096,60.0997023],[-2.148555,60.1011247],[-2.1502671,60.171318]],[[-6.2086011,59.1163488],[-6.1229934,59.1166418],[-6.121852,59.0714985],[-6.2097426,59.0714985],[-6.2086011,59.1163488]],[[-4.4159559,59.0889036],[-4.4212022,59.0770848],[-4.3971904,59.0779143],[-4.3913388,59.0897328],[-4.4159559,59.0889036]]]},{"id":"AGRI-black_and_white-2.5m","name":"AGRI black-and-white 2.5m","type":"tms","template":"http://agri.openstreetmap.org/{zoom}/{x}/{y}.png","polygon":[[[112.28778,-28.784589],[112.71488,-31.13894],[114.11263,-34.178287],[113.60788,-37.39012],[117.17992,-37.451794],[119.31538,-37.42096],[121.72262,-36.708394],[123.81925,-35.76893],[125.9547,-34.3066],[127.97368,-33.727398],[130.07031,-33.24166],[130.10913,-33.888704],[131.00214,-34.049705],[131.0798,-34.72257],[132.28342,-35.39],[134.18591,-35.61126],[133.8753,-37.1119],[134.8459,-37.6365],[139.7769,-37.82075],[139.93223,-39.4283],[141.6017,-39.8767],[142.3783,-39.368294],[142.3783,-40.64702],[142.49478,-42.074874],[144.009,-44.060127],[147.23161,-44.03222],[149.05645,-42.534313],[149.52237,-40.99959],[149.9494,-40.852921],[150.8036,-38.09627],[151.81313,-38.12682],[156.20052,-22.667706],[156.20052,-20.10109],[156.62761,-17.417627],[155.26869,-17.19521],[154.14272,-19.51662],[153.5215,-18.34139],[153.05558,-16.5636],[152.78379,-15.256768],[152.27905,-13.4135],[151.3472,-12.391767],[149.48354,-12.05024],[146.9598,-9.992408],[135.9719,-9.992408],[130.3032,-10.33636],[128.09016,-12.164136],[125.91588,-12.315912],[124.3239,-11.860326],[122.03323,-11.974295],[118.26706,-16.9353],[115.93747,-19.11357],[114.0738,-21.11863],[113.49141,-22.596033],[112.28778,-28.784589]]],"terms_text":"AGRI"},{"id":"lu.geoportail.opendata.basemap","name":"Basemap geoportail.lu","type":"tms","template":"https://{switch:wmts3,wmts4}.geoportail.lu/opendata/wmts/basemap/GLOBAL_WEBMERCATOR_4_V3/{zoom}/{x}/{y}.png","scaleExtent":[0,20],"polygon":[[[5.961753,50.17631],[6.026268,50.18496],[6.033182,50.16395],[6.060695,50.15536],[6.07668,50.15913],[6.078237,50.17255],[6.101762,50.17199],[6.122501,50.16437],[6.120101,50.15594],[6.127695,50.14993],[6.113228,50.13739],[6.123691,50.13719],[6.140929,50.1305],[6.135554,50.11899],[6.138082,50.10263],[6.131085,50.09964],[6.135473,50.09119],[6.121939,50.09059],[6.126335,50.07817],[6.131858,50.07348],[6.121171,50.064],[6.114444,50.06139],[6.115631,50.05817],[6.123611,50.06323],[6.136608,50.04178],[6.130343,50.02975],[6.148207,50.02307],[6.13868,50.01572],[6.135938,50.01485],[6.131384,50.01905],[6.130243,50.01819],[6.139343,50.01116],[6.151702,50.01058],[6.145464,49.99689],[6.139657,49.9994],[6.138524,49.99829],[6.142178,49.99535],[6.150227,49.99518],[6.156247,49.98867],[6.173045,49.98589],[6.17348,49.98344],[6.170353,49.98376],[6.165487,49.97115],[6.171512,49.96298],[6.176298,49.962],[6.179954,49.95386],[6.183393,49.9548],[6.179829,49.96307],[6.183312,49.9686],[6.192774,49.97158],[6.199783,49.95352],[6.207066,49.95672],[6.212689,49.9514],[6.225023,49.95039],[6.22044,49.94369],[6.228241,49.93726],[6.22635,49.92766],[6.219133,49.92354],[6.229862,49.92125],[6.236032,49.91355],[6.231867,49.91064],[6.227694,49.91062],[6.232286,49.9072],[6.23381,49.90028],[6.246919,49.89535],[6.257809,49.88724],[6.263008,49.88101],[6.276455,49.87725],[6.281126,49.87957],[6.291661,49.87548],[6.297699,49.86673],[6.309889,49.87107],[6.315324,49.8673],[6.314651,49.86057],[6.323611,49.85188],[6.321577,49.8409],[6.327406,49.83673],[6.336561,49.83998],[6.339366,49.8507],[6.364651,49.85164],[6.402203,49.82098],[6.426434,49.81629],[6.428071,49.81186],[6.43097,49.81129],[6.441608,49.81547],[6.443442,49.81233],[6.45366,49.81275],[6.464538,49.81975],[6.47057,49.82385],[6.496805,49.81277],[6.50669,49.80993],[6.511554,49.80238],[6.51485,49.80513],[6.519604,49.81446],[6.529808,49.81048],[6.532249,49.80686],[6.530829,49.80116],[6.506225,49.78899],[6.519171,49.78344],[6.511055,49.77422],[6.520563,49.76818],[6.520516,49.76134],[6.503734,49.75086],[6.502627,49.73298],[6.507266,49.72938],[6.518092,49.7242],[6.516417,49.72129],[6.511763,49.72016],[6.504791,49.725],[6.498913,49.72639],[6.495576,49.72443],[6.507122,49.71655],[6.507884,49.71215],[6.504598,49.71227],[6.427139,49.66237],[6.439899,49.66025],[6.442511,49.65591],[6.421781,49.61809],[6.398978,49.60094],[6.379408,49.59526],[6.375507,49.58809],[6.384426,49.5801],[6.381188,49.57509],[6.369093,49.5783],[6.357913,49.57166],[6.384902,49.55817],[6.380095,49.54856],[6.358555,49.53296],[6.359322,49.52481],[6.370763,49.50545],[6.370562,49.45732],[6.333403,49.46493],[6.321894,49.47244],[6.295034,49.47928],[6.287889,49.48379],[6.271912,49.49995],[6.241327,49.50693],[6.196692,49.50331],[6.173373,49.50577],[6.160858,49.50085],[6.167099,49.49006],[6.140179,49.48525],[6.129367,49.48803],[6.127247,49.47081],[6.101403,49.46726],[6.104826,49.45076],[6.081667,49.45417],[6.077222,49.46139],[6.059167,49.46306],[6.052222,49.46028],[6.044213,49.44553],[6.025294,49.44703],[6.021545,49.45127],[6.01574,49.44885],[5.994123,49.45301],[5.976569,49.44885],[5.977725,49.45955],[5.972317,49.46087],[5.968912,49.48202],[5.9616,49.49026],[5.915781,49.49835],[5.890334,49.4948],[5.863321,49.50006],[5.84897,49.50826],[5.84828,49.51397],[5.83641,49.51817],[5.831868,49.52639],[5.84308,49.53081],[5.835622,49.54114],[5.816251,49.53325],[5.805201,49.54272],[5.859432,49.57158],[5.868663,49.587],[5.862888,49.58525],[5.851102,49.58379],[5.847116,49.58961],[5.845652,49.5981],[5.869401,49.6106],[5.881819,49.63815],[5.899978,49.63907],[5.899339,49.66239],[5.856561,49.67628],[5.856283,49.68211],[5.875703,49.71118],[5.864811,49.72331],[5.843249,49.71822],[5.82191,49.72128],[5.824894,49.73767],[5.820728,49.74878],[5.786264,49.79079],[5.765172,49.78961],[5.750937,49.79094],[5.741591,49.82126],[5.745814,49.82435],[5.737197,49.83353],[5.740531,49.84142],[5.747012,49.84048],[5.746237,49.84783],[5.753989,49.84878],[5.740663,49.85152],[5.752288,49.85922],[5.749545,49.87554],[5.775668,49.87438],[5.775053,49.88057],[5.734598,49.89341],[5.733033,49.90285],[5.757834,49.91737],[5.760393,49.93252],[5.770728,49.93711],[5.768783,49.94239],[5.768802,49.96104],[5.786724,49.96816],[5.80524,49.96677],[5.806521,49.97321],[5.831293,49.97995],[5.834616,49.98656],[5.818057,49.99936],[5.815606,50.01437],[5.847923,50.02809],[5.861889,50.04581],[5.850872,50.0563],[5.857809,50.07186],[5.880997,50.08069],[5.891965,50.12041],[5.952856,50.13384],[5.961753,50.17631]]],"terms_url":"https://data.public.lu/en/datasets/carte-de-base-webservices-wms-et-wmts/","terms_text":"Administration du Cadastre et de la Topographie"},{"id":"basemap.at","name":"basemap.at","type":"tms","template":"https://maps{switch:1,2,3,4}.wien.gv.at/basemap/geolandbasemap/normal/google3857/{zoom}/{y}/{x}.png","description":"Basemap of Austria, based on goverment data.","scaleExtent":[0,19],"polygon":[[[16.5073284,46.9929304],[16.283417,46.9929304],[16.135839,46.8713046],[15.9831722,46.8190947],[16.0493278,46.655175],[15.8610387,46.7180116],[15.7592608,46.6900933],[15.5607938,46.6796202],[15.5760605,46.6342132],[15.4793715,46.6027553],[15.4335715,46.6516819],[15.2249267,46.6342132],[15.0468154,46.6481886],[14.9908376,46.5887681],[14.9603042,46.6237293],[14.8534374,46.6027553],[14.8330818,46.5012666],[14.7516595,46.4977636],[14.6804149,46.4381781],[14.6142593,46.4381781],[14.578637,46.3785275],[14.4412369,46.4311638],[14.1613476,46.4276563],[14.1257253,46.4767409],[14.0188585,46.4767409],[13.9119917,46.5257813],[13.8254805,46.5047694],[13.4438134,46.560783],[13.3064132,46.5502848],[13.1283019,46.5887681],[12.8433237,46.6132433],[12.7262791,46.6412014],[12.5125455,46.6656529],[12.3598787,46.7040543],[12.3649676,46.7703197],[12.2886341,46.7772902],[12.2733674,46.8852187],[12.2072118,46.8747835],[12.1308784,46.9026062],[12.1156117,46.9998721],[12.2530119,47.0657733],[12.2123007,47.0934969],[11.9833004,47.0449712],[11.7339445,46.9616816],[11.6321666,47.010283],[11.5405665,46.9755722],[11.4998553,47.0068129],[11.418433,46.9651546],[11.2555884,46.9755722],[11.1130993,46.913036],[11.0418548,46.7633482],[10.8891879,46.7598621],[10.7416099,46.7842599],[10.7059877,46.8643462],[10.5787653,46.8399847],[10.4566318,46.8504267],[10.4769874,46.9269392],[10.3853873,46.9894592],[10.2327204,46.8643462],[10.1207647,46.8330223],[9.8663199,46.9408389],[9.9019422,47.0033426],[9.6831197,47.0588402],[9.6118752,47.0380354],[9.6322307,47.128131],[9.5813418,47.1662025],[9.5406306,47.2664422],[9.6067863,47.3492559],[9.6729419,47.369939],[9.6424085,47.4457079],[9.5660751,47.4801122],[9.7136531,47.5282405],[9.7848976,47.5969187],[9.8357866,47.5454185],[9.9477423,47.538548],[10.0902313,47.4491493],[10.1105869,47.3664924],[10.2428982,47.3871688],[10.1869203,47.2698953],[10.3243205,47.2975125],[10.4820763,47.4491493],[10.4311873,47.4869904],[10.4413651,47.5900549],[10.4871652,47.5522881],[10.5482319,47.5351124],[10.5991209,47.5660246],[10.7568766,47.5316766],[10.8891879,47.5454185],[10.9400769,47.4869904],[10.9960547,47.3906141],[11.2352328,47.4422662],[11.2810328,47.3975039],[11.4235219,47.5144941],[11.5761888,47.5076195],[11.6067221,47.5900549],[11.8357224,47.5866227],[12.003656,47.6243647],[12.2072118,47.6037815],[12.1614117,47.6963421],[12.2581008,47.7442718],[12.2530119,47.6792136],[12.4311232,47.7100408],[12.4921899,47.631224],[12.5685234,47.6277944],[12.6295901,47.6894913],[12.7720792,47.6689338],[12.8331459,47.5419833],[12.975635,47.4732332],[13.0417906,47.4938677],[13.0367017,47.5557226],[13.0977685,47.6415112],[13.0316128,47.7100408],[12.9043905,47.7203125],[13.0061684,47.84683],[12.9451016,47.9355501],[12.8636793,47.9594103],[12.8636793,48.0036929],[12.7517236,48.0989418],[12.8738571,48.2109733],[12.9603683,48.2109733],[13.0417906,48.2652035],[13.1842797,48.2990682],[13.2606131,48.2922971],[13.3980133,48.3565867],[13.4438134,48.417418],[13.4387245,48.5523383],[13.509969,48.5860123],[13.6117469,48.5725454],[13.7287915,48.5118999],[13.7847694,48.5725454],[13.8203916,48.6263915],[13.7949471,48.7171267],[13.850925,48.7741724],[14.0595697,48.6633774],[14.0137696,48.6331182],[14.0748364,48.5927444],[14.2173255,48.5961101],[14.3649034,48.5489696],[14.4666813,48.6499311],[14.5582815,48.5961101],[14.5989926,48.6263915],[14.7211261,48.5759124],[14.7211261,48.6868997],[14.822904,48.7271983],[14.8178151,48.777526],[14.9647227,48.7851754],[14.9893637,49.0126611],[15.1485933,48.9950306],[15.1943934,48.9315502],[15.3063491,48.9850128],[15.3928603,48.9850128],[15.4844604,48.9282069],[15.749083,48.8545973],[15.8406831,48.8880697],[16.0086166,48.7808794],[16.2070835,48.7339115],[16.3953727,48.7372678],[16.4920617,48.8110498],[16.6905286,48.7741724],[16.7057953,48.7339115],[16.8991733,48.713769],[16.9755067,48.515271],[16.8482844,48.4511817],[16.8533733,48.3464411],[16.9551512,48.2516513],[16.9907734,48.1498955],[17.0925513,48.1397088],[17.0823736,48.0241182],[17.1739737,48.0207146],[17.0823736,47.8741447],[16.9856845,47.8673174],[17.0823736,47.8092489],[17.0925513,47.7031919],[16.7414176,47.6792136],[16.7057953,47.7511153],[16.5378617,47.7545368],[16.5480395,47.7066164],[16.4208172,47.6689338],[16.573484,47.6175045],[16.670173,47.631224],[16.7108842,47.538548],[16.6599952,47.4491493],[16.5429506,47.3940591],[16.4615283,47.3940591],[16.4920617,47.276801],[16.425906,47.1973317],[16.4717061,47.1489007],[16.5480395,47.1489007],[16.476795,47.0796369],[16.527684,47.0588402],[16.5073284,46.9929304]]],"terms_text":"basemap.at"},{"id":"basemap.at-orthofoto","name":"basemap.at Orthofoto","type":"tms","template":"https://maps{switch:1,2,3,4}.wien.gv.at/basemap/bmaporthofoto30cm/normal/google3857/{zoom}/{y}/{x}.jpeg","description":"Orthofoto layer provided by basemap.at. \"Successor\" of geoimage.at imagery.","scaleExtent":[0,19],"polygon":[[[16.5073284,46.9929304],[16.283417,46.9929304],[16.135839,46.8713046],[15.9831722,46.8190947],[16.0493278,46.655175],[15.8610387,46.7180116],[15.7592608,46.6900933],[15.5607938,46.6796202],[15.5760605,46.6342132],[15.4793715,46.6027553],[15.4335715,46.6516819],[15.2249267,46.6342132],[15.0468154,46.6481886],[14.9908376,46.5887681],[14.9603042,46.6237293],[14.8534374,46.6027553],[14.8330818,46.5012666],[14.7516595,46.4977636],[14.6804149,46.4381781],[14.6142593,46.4381781],[14.578637,46.3785275],[14.4412369,46.4311638],[14.1613476,46.4276563],[14.1257253,46.4767409],[14.0188585,46.4767409],[13.9119917,46.5257813],[13.8254805,46.5047694],[13.4438134,46.560783],[13.3064132,46.5502848],[13.1283019,46.5887681],[12.8433237,46.6132433],[12.7262791,46.6412014],[12.5125455,46.6656529],[12.3598787,46.7040543],[12.3649676,46.7703197],[12.2886341,46.7772902],[12.2733674,46.8852187],[12.2072118,46.8747835],[12.1308784,46.9026062],[12.1156117,46.9998721],[12.2530119,47.0657733],[12.2123007,47.0934969],[11.9833004,47.0449712],[11.7339445,46.9616816],[11.6321666,47.010283],[11.5405665,46.9755722],[11.4998553,47.0068129],[11.418433,46.9651546],[11.2555884,46.9755722],[11.1130993,46.913036],[11.0418548,46.7633482],[10.8891879,46.7598621],[10.7416099,46.7842599],[10.7059877,46.8643462],[10.5787653,46.8399847],[10.4566318,46.8504267],[10.4769874,46.9269392],[10.3853873,46.9894592],[10.2327204,46.8643462],[10.1207647,46.8330223],[9.8663199,46.9408389],[9.9019422,47.0033426],[9.6831197,47.0588402],[9.6118752,47.0380354],[9.6322307,47.128131],[9.5813418,47.1662025],[9.5406306,47.2664422],[9.6067863,47.3492559],[9.6729419,47.369939],[9.6424085,47.4457079],[9.5660751,47.4801122],[9.7136531,47.5282405],[9.7848976,47.5969187],[9.8357866,47.5454185],[9.9477423,47.538548],[10.0902313,47.4491493],[10.1105869,47.3664924],[10.2428982,47.3871688],[10.1869203,47.2698953],[10.3243205,47.2975125],[10.4820763,47.4491493],[10.4311873,47.4869904],[10.4413651,47.5900549],[10.4871652,47.5522881],[10.5482319,47.5351124],[10.5991209,47.5660246],[10.7568766,47.5316766],[10.8891879,47.5454185],[10.9400769,47.4869904],[10.9960547,47.3906141],[11.2352328,47.4422662],[11.2810328,47.3975039],[11.4235219,47.5144941],[11.5761888,47.5076195],[11.6067221,47.5900549],[11.8357224,47.5866227],[12.003656,47.6243647],[12.2072118,47.6037815],[12.1614117,47.6963421],[12.2581008,47.7442718],[12.2530119,47.6792136],[12.4311232,47.7100408],[12.4921899,47.631224],[12.5685234,47.6277944],[12.6295901,47.6894913],[12.7720792,47.6689338],[12.8331459,47.5419833],[12.975635,47.4732332],[13.0417906,47.4938677],[13.0367017,47.5557226],[13.0977685,47.6415112],[13.0316128,47.7100408],[12.9043905,47.7203125],[13.0061684,47.84683],[12.9451016,47.9355501],[12.8636793,47.9594103],[12.8636793,48.0036929],[12.7517236,48.0989418],[12.8738571,48.2109733],[12.9603683,48.2109733],[13.0417906,48.2652035],[13.1842797,48.2990682],[13.2606131,48.2922971],[13.3980133,48.3565867],[13.4438134,48.417418],[13.4387245,48.5523383],[13.509969,48.5860123],[13.6117469,48.5725454],[13.7287915,48.5118999],[13.7847694,48.5725454],[13.8203916,48.6263915],[13.7949471,48.7171267],[13.850925,48.7741724],[14.0595697,48.6633774],[14.0137696,48.6331182],[14.0748364,48.5927444],[14.2173255,48.5961101],[14.3649034,48.5489696],[14.4666813,48.6499311],[14.5582815,48.5961101],[14.5989926,48.6263915],[14.7211261,48.5759124],[14.7211261,48.6868997],[14.822904,48.7271983],[14.8178151,48.777526],[14.9647227,48.7851754],[14.9893637,49.0126611],[15.1485933,48.9950306],[15.1943934,48.9315502],[15.3063491,48.9850128],[15.3928603,48.9850128],[15.4844604,48.9282069],[15.749083,48.8545973],[15.8406831,48.8880697],[16.0086166,48.7808794],[16.2070835,48.7339115],[16.3953727,48.7372678],[16.4920617,48.8110498],[16.6905286,48.7741724],[16.7057953,48.7339115],[16.8991733,48.713769],[16.9755067,48.515271],[16.8482844,48.4511817],[16.8533733,48.3464411],[16.9551512,48.2516513],[16.9907734,48.1498955],[17.0925513,48.1397088],[17.0823736,48.0241182],[17.1739737,48.0207146],[17.0823736,47.8741447],[16.9856845,47.8673174],[17.0823736,47.8092489],[17.0925513,47.7031919],[16.7414176,47.6792136],[16.7057953,47.7511153],[16.5378617,47.7545368],[16.5480395,47.7066164],[16.4208172,47.6689338],[16.573484,47.6175045],[16.670173,47.631224],[16.7108842,47.538548],[16.6599952,47.4491493],[16.5429506,47.3940591],[16.4615283,47.3940591],[16.4920617,47.276801],[16.425906,47.1973317],[16.4717061,47.1489007],[16.5480395,47.1489007],[16.476795,47.0796369],[16.527684,47.0588402],[16.5073284,46.9929304]]],"terms_text":"basemap.at","best":true},{"id":"bavaria-DOP80","name":"Bavaria DOP 80cm","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/BAYERNDOP80/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[0,18],"polygon":[[[10.1235886,50.568462],[10.1428576,50.5507804],[10.2028056,50.5574195],[10.2520485,50.5179575],[10.3269835,50.4934473],[10.4104825,50.4184762],[10.6031724,50.3310874],[10.6224414,50.2271041],[10.7252093,50.2106649],[10.7294913,50.2476451],[10.8515282,50.2435376],[10.7187863,50.3201525],[10.7123633,50.3652428],[10.8558102,50.3966441],[10.9371682,50.3966441],[10.9906932,50.3666085],[11.1277171,50.3666085],[11.1791011,50.3133169],[11.1619731,50.294172],[11.24119,50.2928042],[11.249754,50.3734364],[11.24119,50.479825],[11.358945,50.5234025],[11.4381619,50.5097889],[11.4424439,50.4893611],[11.425316,50.4771001],[11.425316,50.4416618],[11.4895459,50.4225686],[11.4916869,50.3980089],[11.5195199,50.3980089],[11.5259429,50.3761673],[11.5987369,50.4034677],[11.6372748,50.3884544],[11.7935678,50.4212045],[11.8363877,50.3925494],[11.9220277,50.4280246],[11.9862577,50.3870894],[11.9841167,50.3570478],[12.0483466,50.3310874],[12.0933076,50.3297207],[12.1297046,50.2982751],[12.1404096,50.2722826],[12.1061536,50.255859],[12.1125766,50.2353216],[12.1489736,50.236691],[12.1982166,50.2010728],[12.2239086,50.1640565],[12.2046396,50.1434795],[12.2067806,50.1077916],[12.2431775,50.0995522],[12.2774335,50.0720772],[12.4936744,49.985428],[12.4979564,49.9413559],[12.5557634,49.9220616],[12.5493404,49.8682726],[12.4808284,49.7881677],[12.4101755,49.7577484],[12.4615594,49.7065456],[12.5471994,49.6802313],[12.5878784,49.552613],[12.6542493,49.534553],[12.6628133,49.4330153],[12.7527353,49.4107323],[12.7976963,49.3466124],[12.9047462,49.3563752],[12.9968092,49.3368477],[13.0546161,49.2754251],[13.1316921,49.2195199],[13.1916401,49.1439475],[13.236601,49.1215335],[13.296549,49.1229347],[13.371484,49.0808823],[13.414304,49.0289687],[13.414304,48.9798112],[13.5791609,48.9699739],[13.6348268,48.9432629],[13.6776468,48.8869823],[13.7375948,48.8926132],[13.7846968,48.8334571],[13.8403627,48.774231],[13.8168118,48.7064584],[13.8446447,48.7008065],[13.8425037,48.6003807],[13.7654278,48.5422972],[13.7525818,48.5040106],[13.6712238,48.5054291],[13.6433908,48.5437146],[13.4571239,48.5508013],[13.4571239,48.4159838],[13.40574,48.3605338],[13.283703,48.2751083],[13.0931541,48.2694081],[12.9582712,48.1909669],[12.8769132,48.1852574],[12.7720043,48.0938188],[12.8640672,48.0136764],[12.8983232,47.9549216],[12.9454252,47.9563555],[12.9968092,47.8846147],[13.0139372,47.834337],[12.9347202,47.7321953],[13.0588981,47.7249947],[13.1188461,47.6385093],[13.0653211,47.5692178],[13.0567571,47.473792],[13.0032322,47.4520801],[12.7677223,47.5504355],[12.7698633,47.6327385],[12.7398893,47.6731207],[12.6670953,47.6702373],[12.5750324,47.621195],[12.4808284,47.6197519],[12.4144575,47.6702373],[12.2431775,47.6774455],[12.2132036,47.6918589],[12.1917936,47.6817699],[12.2132036,47.6659119],[12.2110626,47.603875],[12.1746656,47.5952129],[12.1382686,47.603875],[11.8920537,47.603875],[11.8513747,47.5793285],[11.6394158,47.5822169],[11.5944549,47.5489905],[11.5901729,47.5128508],[11.5173789,47.498388],[11.4403029,47.5041736],[11.395342,47.4752392],[11.427457,47.4448409],[11.346099,47.4433929],[11.279728,47.3955873],[11.2133571,47.3883402],[11.247613,47.4318076],[11.1020251,47.3926886],[10.9650012,47.3897897],[10.9778472,47.4361524],[10.9178992,47.4752392],[10.8707972,47.4752392],[10.8558102,47.4940484],[10.9007712,47.5142969],[10.8729382,47.5359831],[10.8108493,47.5128508],[10.6438513,47.5489905],[10.5946084,47.5547705],[10.5796214,47.5287553],[10.4618664,47.5403192],[10.4661484,47.4839212],[10.4875584,47.4781333],[10.4875584,47.4129762],[10.4597254,47.4028333],[10.4597254,47.375293],[10.4104825,47.3738431],[10.4083415,47.3433862],[10.3205605,47.2867768],[10.2820225,47.2780622],[10.2841635,47.2620819],[10.1471396,47.2620819],[10.1921006,47.3027497],[10.1942416,47.3738431],[10.1664086,47.3738431],[10.1664086,47.3462876],[10.1000376,47.3433862],[10.0614996,47.3636928],[10.0679226,47.4187712],[10.0936146,47.426014],[10.0957556,47.4419449],[9.9780007,47.485368],[9.9565907,47.5273097],[9.8945017,47.5287553],[9.8559637,47.5085124],[9.8174258,47.544655],[9.8217078,47.5764399],[9.7746058,47.5822169],[9.7382088,47.525864],[9.6739788,47.5345376],[9.5840569,47.564884],[9.6397228,47.6053186],[9.7167988,47.603875],[9.8559637,47.6760039],[9.9780007,47.6558179],[10.0293846,47.6817699],[10.1000376,47.6673537],[10.1321526,47.6760039],[10.1428576,47.7019459],[10.0614996,47.7725005],[10.1128836,47.8098988],[10.0829096,47.8530173],[10.1086016,47.9090177],[10.0764866,47.9649577],[10.1300116,48.020837],[10.1342936,48.1066872],[10.1000376,48.1281274],[10.0550766,48.2622821],[9.9694367,48.3676462],[10.0315256,48.4259299],[10.0293846,48.461436],[10.1235886,48.4770509],[10.1535626,48.4514968],[10.2349205,48.5125212],[10.3162785,48.516776],[10.2991505,48.6187835],[10.2456255,48.6682961],[10.2734585,48.7064584],[10.3698035,48.6838472],[10.4318924,48.6993935],[10.4511614,48.7276471],[10.4019185,48.7460035],[10.4404564,48.8489571],[10.4340334,48.9587289],[10.3376885,49.0205451],[10.2499075,49.0359872],[10.2499075,49.0738701],[10.2006646,49.1033147],[10.2520485,49.1327418],[10.1235886,49.1971401],[10.1193066,49.2628519],[10.1514216,49.2893915],[10.1043196,49.3452175],[10.1407166,49.3940134],[10.1086016,49.445545],[10.1107426,49.5053651],[10.0722046,49.5331635],[10.0165387,49.4761598],[9.9266167,49.478942],[9.9244757,49.5567797],[9.8987837,49.5817727],[9.8559637,49.5387213],[9.8067208,49.5567797],[9.8666687,49.6067529],[9.8538227,49.6441991],[9.8174258,49.6608327],[9.8345537,49.6899277],[9.7960158,49.7203895],[9.7574778,49.7079302],[9.7403498,49.6857723],[9.7060938,49.7162368],[9.6782608,49.7162368],[9.6825428,49.6885426],[9.6204539,49.6913127],[9.6461458,49.78955],[9.5583649,49.7743431],[9.5712109,49.7356133],[9.5069809,49.7522156],[9.4919939,49.7798735],[9.4684429,49.7605146],[9.425623,49.7784909],[9.404213,49.7646636],[9.33356,49.770195],[9.329278,49.7342295],[9.408495,49.725926],[9.427764,49.6982374],[9.414918,49.6441991],[9.380662,49.6386533],[9.359252,49.6497443],[9.339983,49.6372668],[9.31215,49.648358],[9.277894,49.626173],[9.284317,49.6081403],[9.241497,49.5748315],[9.0980501,49.5720547],[9.0659351,49.6081403],[9.1001911,49.6511305],[9.0916271,49.6926978],[9.1301651,49.7120837],[9.1387291,49.7425316],[9.1087551,49.7563653],[9.1365881,49.7909322],[9.1001911,49.78955],[9.0723581,49.8282367],[9.0359611,49.8351418],[9.0166922,50.0267091],[8.9631672,50.0308352],[8.9567442,50.0597083],[9.0017052,50.0707031],[9.0209742,50.1105378],[9.1216011,50.1228936],[9.1558571,50.1132838],[9.1965361,50.1187753],[9.1858311,50.1352462],[9.235074,50.1475956],[9.37638,50.1270115],[9.408495,50.0816953],[9.5219679,50.095432],[9.5048399,50.1421073],[9.5326729,50.1640565],[9.4898529,50.1695422],[9.4941349,50.2435376],[9.6140309,50.221625],[9.6654148,50.2353216],[9.6354408,50.2490142],[9.6675558,50.2722826],[9.7424908,50.3092151],[9.7296448,50.3584137],[9.7703238,50.4293885],[9.8688097,50.4007384],[9.9180527,50.4089259],[10.0358076,50.479825],[10.0379486,50.5111504],[10.1235886,50.568462]]]},{"id":"GRB","name":"Belgium AGIV GRB Flanders","type":"tms","template":"http://tile.informatievlaanderen.be/ws/raadpleegdiensten/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=grb_bsk&STYLE=&FORMAT=image/png&tileMatrixSet=GoogleMapsVL&tileMatrix={zoom}&tileRow={y}&tileCol={x}","scaleExtent":[0,21],"polygon":[[[2.522393220658428,51.101723961331],[3.1260610915867457,51.34117672029327],[3.174929443042849,51.382459567439525],[3.3761520666856217,51.38784154353026],[3.410647373595811,51.33040116175589],[3.4020235468682634,51.28547573497245],[3.4911364230529203,51.256700377228974],[3.4825125963253734,51.30345118353617],[3.5773746903283947,51.323216048914524],[3.813092620881357,51.27288873325703],[3.8217164476089045,51.236906864834886],[3.9309515861578386,51.236906864834886],[4.054559769252684,51.27468708752057],[4.20116482362099,51.35194974615148],[4.169544125619984,51.38066543475199],[4.342020660170932,51.395016527087456],[4.3650175314443915,51.46491366130351],[4.5374940659953396,51.50071687469512],[4.571989372905529,51.479238319799464],[4.560490937268798,51.44879304380801],[4.638105377816725,51.45058450468522],[4.750215125274841,51.5239738914927],[4.8364533925503155,51.507874144493115],[5.080795149830825,51.49892738159079],[5.135412719105292,51.447001512638565],[5.106666630013469,51.391429175957505],[5.264770120018504,51.31782647548482],[5.264770120018504,51.28727359653538],[5.4085005654776275,51.292666758936925],[5.486115006025553,51.325012432665545],[5.5809771000285755,51.28367780302667],[5.583851708937758,51.23510703218069],[5.767826679125435,51.20449910348059],[5.8770618176743685,51.161253258857485],[5.704585283123422,50.80292546633848],[5.905807906766195,50.7865720955422],[5.9374286047672005,50.732019528192964],[5.902933297857012,50.70107817444857],[5.8138204216723555,50.69379488717487],[5.615472406938765,50.761122144578216],[5.500488050571466,50.71200098472672],[5.204403332925673,50.70289881954383],[5.164158808197117,50.67558172042608],[5.037676016193088,50.70107817444857],[4.988807664736986,50.750210783384084],[4.916942442007425,50.72656077355532],[4.790459650003396,50.766576871275696],[4.681224511454462,50.77021300246129],[4.6697260758177315,50.73565834458533],[4.287403090896464,50.67922491935501],[3.91082932379356,50.677403355240585],[3.718230526878334,50.752029520237265],[3.6549891308763196,50.71200098472672],[3.5342555566906557,50.710180693059606],[3.514133294326379,50.741116039142966],[3.45664111614273,50.74384464791457],[3.373277457776438,50.69561581502901],[3.310036061774423,50.70745012302645],[3.2899137994101473,50.7365680045137],[3.1648683118607086,50.742935129324266],[3.1318103094051106,50.77203096207303],[3.080067349039826,50.76021296163662],[2.8745328120332805,50.73929687829333],[2.8960923788521487,50.71109084772858],[2.8745328120332805,50.69561581502901],[2.796918371485353,50.70289881954383],[2.699181668573149,50.80020030189157],[2.6201299235706315,50.79747497850781],[2.5698242676599374,50.85830267681076],[2.5669496587507554,50.923581424665855],[2.6028822701155367,50.94984841176044],[2.549702005295661,50.996006093918574],[2.522393220658428,51.101723961331]]],"terms_text":"GRB Flanders (c) AGIV"},{"id":"AGIV","name":"Belgium AGIV Orthophoto Flanders","type":"tms","template":"http://tile.informatievlaanderen.be/ws/raadpleegdiensten/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=omwrgbmrvl&STYLE=&FORMAT=image/png&tileMatrixSet=GoogleMapsVL&tileMatrix={zoom}&tileRow={y}&tileCol={x}","scaleExtent":[0,21],"polygon":[[[2.522393220658428,51.101723961331],[3.1260610915867457,51.34117672029327],[3.174929443042849,51.382459567439525],[3.3761520666856217,51.38784154353026],[3.410647373595811,51.33040116175589],[3.4020235468682634,51.28547573497245],[3.4911364230529203,51.256700377228974],[3.4825125963253734,51.30345118353617],[3.5773746903283947,51.323216048914524],[3.813092620881357,51.27288873325703],[3.8217164476089045,51.236906864834886],[3.9309515861578386,51.236906864834886],[4.054559769252684,51.27468708752057],[4.20116482362099,51.35194974615148],[4.169544125619984,51.38066543475199],[4.342020660170932,51.395016527087456],[4.3650175314443915,51.46491366130351],[4.5374940659953396,51.50071687469512],[4.571989372905529,51.479238319799464],[4.560490937268798,51.44879304380801],[4.638105377816725,51.45058450468522],[4.750215125274841,51.5239738914927],[4.8364533925503155,51.507874144493115],[5.080795149830825,51.49892738159079],[5.135412719105292,51.447001512638565],[5.106666630013469,51.391429175957505],[5.264770120018504,51.31782647548482],[5.264770120018504,51.28727359653538],[5.4085005654776275,51.292666758936925],[5.486115006025553,51.325012432665545],[5.5809771000285755,51.28367780302667],[5.583851708937758,51.23510703218069],[5.767826679125435,51.20449910348059],[5.8770618176743685,51.161253258857485],[5.704585283123422,50.80292546633848],[5.905807906766195,50.7865720955422],[5.9374286047672005,50.732019528192964],[5.902933297857012,50.70107817444857],[5.8138204216723555,50.69379488717487],[5.615472406938765,50.761122144578216],[5.500488050571466,50.71200098472672],[5.204403332925673,50.70289881954383],[5.164158808197117,50.67558172042608],[5.037676016193088,50.70107817444857],[4.988807664736986,50.750210783384084],[4.916942442007425,50.72656077355532],[4.790459650003396,50.766576871275696],[4.681224511454462,50.77021300246129],[4.6697260758177315,50.73565834458533],[4.287403090896464,50.67922491935501],[3.91082932379356,50.677403355240585],[3.718230526878334,50.752029520237265],[3.6549891308763196,50.71200098472672],[3.5342555566906557,50.710180693059606],[3.514133294326379,50.741116039142966],[3.45664111614273,50.74384464791457],[3.373277457776438,50.69561581502901],[3.310036061774423,50.70745012302645],[3.2899137994101473,50.7365680045137],[3.1648683118607086,50.742935129324266],[3.1318103094051106,50.77203096207303],[3.080067349039826,50.76021296163662],[2.8745328120332805,50.73929687829333],[2.8960923788521487,50.71109084772858],[2.8745328120332805,50.69561581502901],[2.796918371485353,50.70289881954383],[2.699181668573149,50.80020030189157],[2.6201299235706315,50.79747497850781],[2.5698242676599374,50.85830267681076],[2.5669496587507554,50.923581424665855],[2.6028822701155367,50.94984841176044],[2.549702005295661,50.996006093918574],[2.522393220658428,51.101723961331]]],"terms_text":"Orthophoto Flanders most recent (c) AGIV","best":true},{"id":"Benin_cotonou_pleiade_2016","name":"Benin: Cotonou Pleiade 2016","type":"tms","template":"http://geoxxx.agrocampus-ouest.fr/owsifl/gwc/service/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=Benin:cotonou_pleiade_2016&STYLE=&FORMAT=image/jpeg&tileMatrixSet=EPSG:3857&tileMatrix=EPSG:3857:{zoom}&tileRow={y}&tileCol={x}","scaleExtent":[0,21],"polygon":[[[2.31953818544,6.55745092536],[2.33645249928,6.56023631702],[2.36377172444,6.56211241002],[2.36737717181,6.56067658005],[2.37777373205,6.54939665325],[2.3777926612,6.53484752744],[2.36994151563,6.4933195729],[2.37038356708,6.45527010853],[2.36958186167,6.45269435578],[2.36188103586,6.44177160245],[2.35391742884,6.40545220189],[2.3674929737,6.40149524022],[2.39525870424,6.40071623744],[2.40128040262,6.40374371884],[2.40587684694,6.40340733291],[2.42045897749,6.39382909301],[2.42485054154,6.3979366042],[2.42949152505,6.39887495342],[2.43625257397,6.39628121034],[2.43958410532,6.40041525877],[2.44439433776,6.40189359345],[2.45375647532,6.39899446003],[2.47144744127,6.3963166199],[2.48162019208,6.3910582748],[2.49453210303,6.38739776192],[2.50893162289,6.38888498676],[2.50719014059,6.39228876781],[2.50120407357,6.39162040687],[2.4963025358,6.39521449649],[2.49509997769,6.40123077776],[2.49543290813,6.40400928653],[2.49830345887,6.41022131795],[2.50191336015,6.41281720321],[2.5108701911,6.41321333458],[2.52218648559,6.40849403999],[2.53352059576,6.4051656109],[2.53809922441,6.40960941297],[2.5411100736,6.41090182623],[2.54650822333,6.41099034757],[2.54654385468,6.40651114868],[2.57638511144,6.40723702943],[2.57642074279,6.41176933466],[2.58575615684,6.41196408125],[2.58867792765,6.41095493903],[2.60877400982,6.39413560832],[2.62569890171,6.39487921149],[2.64554556441,6.39728706193],[2.65039142819,6.39339200408],[2.6536650586,6.36823275735],[2.6431181786,6.3665949733],[2.61251084779,6.3628944474],[2.56867983171,6.3607044406],[2.54682890549,6.36055393954],[2.54687344468,6.35546343647],[2.50206702036,6.35461353888],[2.47064016846,6.35595920942],[2.46777184468,6.35202842507],[2.46422652522,6.35020467258],[2.45253944198,6.35006302163],[2.4511320036,6.34813302357],[2.44737289603,6.34629155079],[2.43757427441,6.34653944174],[2.43297783009,6.33841209773],[2.43016295333,6.33706638135],[2.42244876576,6.33706638135],[2.39236031651,6.34114999999],[2.39315311407,6.34114999999],[2.3652849434,6.34445228474],[2.35386064137,6.34529777247],[2.34377474198,6.34457844399],[2.34093759563,6.34533982549],[2.31086028117,6.36567095094],[2.28434610184,6.37465215648],[2.28146887022,6.37761782314],[2.27599054995,6.39517244756],[2.27611525968,6.39819996182],[2.31528747657,6.4926104105],[2.31579967725,6.5530659484],[2.31953818544,6.55745092536]],[[1.69563043958,6.25076170066],[1.70009994721,6.24711901182],[1.70417862346,6.24697179839],[1.75874803806,6.25835802546],[1.77079143482,6.25995187823],[1.81712109941,6.27161341959],[1.84456614779,6.27656750346],[1.85767848509,6.27944518918],[1.88843363033,6.28325588467],[1.90481876292,6.28594870029],[1.90617692982,6.29435189983],[1.90083111364,6.29721233234],[1.89880903445,6.29953873942],[1.89404334121,6.30085024405],[1.89047742238,6.29969866569],[1.88747882146,6.29636150888],[1.88344050885,6.29622344016],[1.86969682855,6.29226563906],[1.8564007671,6.29198230539],[1.85206654725,6.28674503171],[1.84991419093,6.28906373821],[1.84691224958,6.29202989661],[1.8435272712,6.29332703219],[1.84040507404,6.29315437611],[1.83626738336,6.29129499924],[1.83409832485,6.28733273348],[1.83416513363,6.2851988527],[1.83229560117,6.28456355663],[1.82785949792,6.28644177291],[1.82182443779,6.2908379014],[1.81562903657,6.28997904337],[1.81211044063,6.29143113241],[1.80757635117,6.29570768815],[1.80471693522,6.29692955475],[1.80073513171,6.29709778253],[1.79775991387,6.29612383144],[1.79625448928,6.29491967121],[1.79490049792,6.28965143736],[1.79641483036,6.28608317469],[1.80097564333,6.28338261222],[1.79566657198,6.28013306439],[1.79156005874,6.28174455931],[1.78498607441,6.28122215216],[1.78092410036,6.27752986974],[1.77588226414,6.27550220232],[1.76744654171,6.27696318619],[1.75653444036,6.27496207997],[1.74833032171,6.27238985028],[1.74761769468,6.27726423691],[1.74572477914,6.27938486862],[1.73948038482,6.27984972411],[1.73680357955,6.27761398678],[1.73572127725,6.27891558552],[1.72901812928,6.27911038233],[1.72435487617,6.27422273126],[1.72449294765,6.2678607472],[1.72555966124,6.26683029328],[1.69933944056,6.26159387355],[1.69572953928,6.25725948175],[1.69563043958,6.25076170066]]],"best":true},{"id":"Bing","name":"Bing aerial imagery","type":"bing","template":"http://www.bing.com/maps/","description":"Satellite and aerial imagery.","scaleExtent":[0,22],"default":true},{"id":"British_Columbia_Mosaic","name":"British Columbia Mosaic","type":"tms","template":"http://{switch:a,b,c,d}.imagery.paulnorman.ca/tiles/bc_mosaic/{zoom}/{x}/{y}.png","scaleExtent":[9,20],"polygon":[[[-123.3176032,49.3272567],[-123.4405258,49.3268222],[-123.440717,49.3384429],[-123.4398375,49.3430357],[-123.4401258,49.3435398],[-123.4401106,49.3439946],[-123.4406265,49.3444493],[-123.4404747,49.3455762],[-123.4397768,49.3460606],[-123.4389726,49.3461298],[-123.4372904,49.3567236],[-123.4374774,49.3710843],[-123.4335292,49.3709446],[-123.4330357,49.373725],[-123.4332717,49.3751221],[-123.4322847,49.3761001],[-123.4317482,49.3791736],[-123.4314264,49.3795927],[-123.4307826,49.3823866],[-123.4313405,49.3827358],[-123.4312118,49.3838533],[-123.4300415,49.3845883],[-123.4189858,49.3847087],[-123.4192235,49.4135198],[-123.3972532,49.4135691],[-123.3972758,49.4243473],[-123.4006929,49.4243314],[-123.4007741,49.5703491],[-123.4000812,49.570345],[-123.4010761,49.5933838],[-123.3760399,49.5932848],[-123.3769811,49.6756063],[-123.3507288,49.6756396],[-123.3507969,49.7086751],[-123.332887,49.708722],[-123.3327888,49.7256288],[-123.3007111,49.7255625],[-123.3009164,49.7375384],[-123.2885986,49.737638],[-123.2887823,49.8249207],[-123.2997955,49.8249207],[-123.3011721,49.8497814],[-123.3218218,49.850669],[-123.3273284,49.8577696],[-123.3276726,49.9758852],[-123.3008279,49.9752212],[-123.3007204,50.0997002],[-123.2501716,50.100735],[-123.25091,50.2754901],[-123.0224338,50.2755598],[-123.0224879,50.3254853],[-123.0009318,50.3254689],[-123.0007778,50.3423899],[-122.9775023,50.3423408],[-122.9774766,50.3504306],[-122.9508137,50.3504961],[-122.950795,50.3711984],[-122.9325221,50.3711521],[-122.9321048,50.399793],[-122.8874234,50.3999748],[-122.8873385,50.4256108],[-122.6620152,50.4256959],[-122.6623083,50.3994506],[-122.5990316,50.3992413],[-122.5988274,50.3755206],[-122.5724832,50.3753706],[-122.5735621,50.2493891],[-122.5990415,50.2494643],[-122.5991504,50.2265663],[-122.6185016,50.2266359],[-122.6185741,50.2244081],[-122.6490609,50.2245126],[-122.6492181,50.1993528],[-122.7308575,50.1993758],[-122.7311583,50.1244287],[-122.7490352,50.1245109],[-122.7490541,50.0903032],[-122.7687806,50.0903435],[-122.7689801,49.9494546],[-122.999047,49.9494706],[-122.9991199,49.8754553],[-122.9775894,49.8754553],[-122.9778145,49.6995098],[-122.9992362,49.6994781],[-122.9992524,49.6516526],[-123.0221525,49.6516526],[-123.0221162,49.5995096],[-123.0491898,49.5994625],[-123.0491898,49.5940523],[-123.0664647,49.5940405],[-123.0663594,49.5451868],[-123.0699906,49.5451202],[-123.0699008,49.5413153],[-123.0706835,49.5392837],[-123.0708888,49.5379931],[-123.0711454,49.5368773],[-123.0711069,49.5358115],[-123.0713764,49.532822],[-123.0716458,49.5321141],[-123.07171,49.5313896],[-123.0720308,49.5304153],[-123.0739554,49.5303486],[-123.0748023,49.5294992],[-123.0748151,49.5288079],[-123.0743403,49.5280584],[-123.073532,49.5274588],[-123.0733652,49.5270423],[-123.0732882,49.5255932],[-123.0737116,49.5249602],[-123.0736218,49.5244938],[-123.0992583,49.5244854],[-123.0991649,49.4754502],[-123.071052,49.4755252],[-123.071088,49.4663034],[-123.0739204,49.4663054],[-123.07422,49.4505028],[-123.0746319,49.4500858],[-123.074651,49.449329],[-123.0745999,49.449018],[-123.0744619,49.4486927],[-123.0743336,49.4479899],[-123.0742427,49.4477688],[-123.0743061,49.4447473],[-123.0747103,49.4447556],[-123.0746384,49.4377306],[-122.9996506,49.4377363],[-122.9996506,49.4369214],[-122.8606163,49.4415314],[-122.8102616,49.4423972],[-122.8098984,49.3766739],[-122.4036093,49.3766617],[-122.4036341,49.3771944],[-122.264739,49.3773028],[-122.263542,49.2360088],[-122.2155742,49.236139],[-122.0580956,49.235878],[-121.9538274,49.2966525],[-121.9400911,49.3045389],[-121.9235761,49.3142257],[-121.8990871,49.3225436],[-121.8883447,49.3259752],[-121.8552982,49.3363575],[-121.832697,49.3441519],[-121.7671336,49.3654361],[-121.6736683,49.3654589],[-121.6404153,49.3743775],[-121.5961976,49.3860493],[-121.5861178,49.3879193],[-121.5213684,49.3994649],[-121.5117375,49.4038378],[-121.4679302,49.4229024],[-121.4416803,49.4345607],[-121.422429,49.4345788],[-121.3462885,49.3932312],[-121.3480144,49.3412388],[-121.5135035,49.320577],[-121.6031683,49.2771727],[-121.6584065,49.1856125],[-121.679953,49.1654109],[-121.7815793,49.0702559],[-121.8076228,49.0622471],[-121.9393997,49.0636219],[-121.9725524,49.0424179],[-121.9921394,49.0332869],[-122.0035289,49.0273413],[-122.0178564,49.0241067],[-122.1108634,48.9992786],[-122.1493067,48.9995305],[-122.1492705,48.9991498],[-122.1991447,48.9996019],[-122.199181,48.9991974],[-122.234365,48.9994829],[-122.234365,49.000173],[-122.3994722,49.0012385],[-122.4521338,49.0016326],[-122.4521338,49.000883],[-122.4584089,49.0009306],[-122.4584814,48.9993124],[-122.4992458,48.9995022],[-122.4992458,48.9992906],[-122.5492618,48.9995107],[-122.5492564,48.9993206],[-122.6580785,48.9994212],[-122.6581061,48.9954007],[-122.7067604,48.9955344],[-122.7519761,48.9956392],[-122.7922063,48.9957204],[-122.7921907,48.9994331],[-123.0350417,48.9995724],[-123.0350437,49.0000958],[-123.0397091,49.0000536],[-123.0397444,49.0001812],[-123.0485506,49.0001348],[-123.0485329,49.0004712],[-123.0557122,49.000448],[-123.0556324,49.0002284],[-123.0641365,49.0001293],[-123.064158,48.9999421],[-123.074899,48.9996928],[-123.0750717,49.0006218],[-123.0899573,49.0003726],[-123.109229,48.9999421],[-123.1271193,49.0003046],[-123.1359953,48.9998741],[-123.1362716,49.0005765],[-123.153851,48.9998061],[-123.1540533,49.0006806],[-123.1710015,49.0001274],[-123.2000916,48.9996849],[-123.2003446,49.0497785],[-123.2108845,49.0497232],[-123.2112218,49.051989],[-123.2070479,49.0520857],[-123.2078911,49.0607884],[-123.2191688,49.0600978],[-123.218958,49.0612719],[-123.2251766,49.0612719],[-123.2253874,49.0622388],[-123.2297088,49.0620316],[-123.2298142,49.068592],[-123.2331869,49.0687301],[-123.2335031,49.0705945],[-123.249313,49.0702493],[-123.2497346,49.0802606],[-123.2751358,49.0803986],[-123.2751358,49.0870947],[-123.299483,49.0873018],[-123.29944,49.080253],[-123.3254508,49.0803944],[-123.3254353,49.1154662],[-123.2750966,49.1503341],[-123.275181,49.1873267],[-123.2788067,49.1871063],[-123.278891,49.1910741],[-123.3004767,49.1910741],[-123.3004186,49.2622933],[-123.3126185,49.2622416],[-123.3125958,49.2714948],[-123.3154251,49.2714727],[-123.3156628,49.2818906],[-123.3174735,49.2818832],[-123.3174961,49.2918488],[-123.3190353,49.2918488],[-123.3190692,49.298602],[-123.3202349,49.2985651],[-123.3202786,49.3019749],[-123.3222679,49.3019605],[-123.3223943,49.3118263],[-123.3254002,49.3118086],[-123.3253898,49.3201721],[-123.3192695,49.3201957],[-123.3192242,49.3246748],[-123.3179437,49.3246596],[-123.3179861,49.3254065],[-123.3176032,49.3272567]]],"terms_url":"http://imagery.paulnorman.ca/tiles/about.html","terms_text":"Copyright Province of British Columbia, City of Surrey"},{"id":"lu.geoportail.opendata.cadastre","name":"Cadastre geoportail.lu","type":"tms","template":"https://{switch:wmts3,wmts4}.geoportail.lu/opendata/wmts/cadastre/GLOBAL_WEBMERCATOR_4_V3/{zoom}/{x}/{y}.png","scaleExtent":[0,20],"polygon":[[[5.961753,50.17631],[6.026268,50.18496],[6.033182,50.16395],[6.060695,50.15536],[6.07668,50.15913],[6.078237,50.17255],[6.101762,50.17199],[6.122501,50.16437],[6.120101,50.15594],[6.127695,50.14993],[6.113228,50.13739],[6.123691,50.13719],[6.140929,50.1305],[6.135554,50.11899],[6.138082,50.10263],[6.131085,50.09964],[6.135473,50.09119],[6.121939,50.09059],[6.126335,50.07817],[6.131858,50.07348],[6.121171,50.064],[6.114444,50.06139],[6.115631,50.05817],[6.123611,50.06323],[6.136608,50.04178],[6.130343,50.02975],[6.148207,50.02307],[6.13868,50.01572],[6.135938,50.01485],[6.131384,50.01905],[6.130243,50.01819],[6.139343,50.01116],[6.151702,50.01058],[6.145464,49.99689],[6.139657,49.9994],[6.138524,49.99829],[6.142178,49.99535],[6.150227,49.99518],[6.156247,49.98867],[6.173045,49.98589],[6.17348,49.98344],[6.170353,49.98376],[6.165487,49.97115],[6.171512,49.96298],[6.176298,49.962],[6.179954,49.95386],[6.183393,49.9548],[6.179829,49.96307],[6.183312,49.9686],[6.192774,49.97158],[6.199783,49.95352],[6.207066,49.95672],[6.212689,49.9514],[6.225023,49.95039],[6.22044,49.94369],[6.228241,49.93726],[6.22635,49.92766],[6.219133,49.92354],[6.229862,49.92125],[6.236032,49.91355],[6.231867,49.91064],[6.227694,49.91062],[6.232286,49.9072],[6.23381,49.90028],[6.246919,49.89535],[6.257809,49.88724],[6.263008,49.88101],[6.276455,49.87725],[6.281126,49.87957],[6.291661,49.87548],[6.297699,49.86673],[6.309889,49.87107],[6.315324,49.8673],[6.314651,49.86057],[6.323611,49.85188],[6.321577,49.8409],[6.327406,49.83673],[6.336561,49.83998],[6.339366,49.8507],[6.364651,49.85164],[6.402203,49.82098],[6.426434,49.81629],[6.428071,49.81186],[6.43097,49.81129],[6.441608,49.81547],[6.443442,49.81233],[6.45366,49.81275],[6.464538,49.81975],[6.47057,49.82385],[6.496805,49.81277],[6.50669,49.80993],[6.511554,49.80238],[6.51485,49.80513],[6.519604,49.81446],[6.529808,49.81048],[6.532249,49.80686],[6.530829,49.80116],[6.506225,49.78899],[6.519171,49.78344],[6.511055,49.77422],[6.520563,49.76818],[6.520516,49.76134],[6.503734,49.75086],[6.502627,49.73298],[6.507266,49.72938],[6.518092,49.7242],[6.516417,49.72129],[6.511763,49.72016],[6.504791,49.725],[6.498913,49.72639],[6.495576,49.72443],[6.507122,49.71655],[6.507884,49.71215],[6.504598,49.71227],[6.427139,49.66237],[6.439899,49.66025],[6.442511,49.65591],[6.421781,49.61809],[6.398978,49.60094],[6.379408,49.59526],[6.375507,49.58809],[6.384426,49.5801],[6.381188,49.57509],[6.369093,49.5783],[6.357913,49.57166],[6.384902,49.55817],[6.380095,49.54856],[6.358555,49.53296],[6.359322,49.52481],[6.370763,49.50545],[6.370562,49.45732],[6.333403,49.46493],[6.321894,49.47244],[6.295034,49.47928],[6.287889,49.48379],[6.271912,49.49995],[6.241327,49.50693],[6.196692,49.50331],[6.173373,49.50577],[6.160858,49.50085],[6.167099,49.49006],[6.140179,49.48525],[6.129367,49.48803],[6.127247,49.47081],[6.101403,49.46726],[6.104826,49.45076],[6.081667,49.45417],[6.077222,49.46139],[6.059167,49.46306],[6.052222,49.46028],[6.044213,49.44553],[6.025294,49.44703],[6.021545,49.45127],[6.01574,49.44885],[5.994123,49.45301],[5.976569,49.44885],[5.977725,49.45955],[5.972317,49.46087],[5.968912,49.48202],[5.9616,49.49026],[5.915781,49.49835],[5.890334,49.4948],[5.863321,49.50006],[5.84897,49.50826],[5.84828,49.51397],[5.83641,49.51817],[5.831868,49.52639],[5.84308,49.53081],[5.835622,49.54114],[5.816251,49.53325],[5.805201,49.54272],[5.859432,49.57158],[5.868663,49.587],[5.862888,49.58525],[5.851102,49.58379],[5.847116,49.58961],[5.845652,49.5981],[5.869401,49.6106],[5.881819,49.63815],[5.899978,49.63907],[5.899339,49.66239],[5.856561,49.67628],[5.856283,49.68211],[5.875703,49.71118],[5.864811,49.72331],[5.843249,49.71822],[5.82191,49.72128],[5.824894,49.73767],[5.820728,49.74878],[5.786264,49.79079],[5.765172,49.78961],[5.750937,49.79094],[5.741591,49.82126],[5.745814,49.82435],[5.737197,49.83353],[5.740531,49.84142],[5.747012,49.84048],[5.746237,49.84783],[5.753989,49.84878],[5.740663,49.85152],[5.752288,49.85922],[5.749545,49.87554],[5.775668,49.87438],[5.775053,49.88057],[5.734598,49.89341],[5.733033,49.90285],[5.757834,49.91737],[5.760393,49.93252],[5.770728,49.93711],[5.768783,49.94239],[5.768802,49.96104],[5.786724,49.96816],[5.80524,49.96677],[5.806521,49.97321],[5.831293,49.97995],[5.834616,49.98656],[5.818057,49.99936],[5.815606,50.01437],[5.847923,50.02809],[5.861889,50.04581],[5.850872,50.0563],[5.857809,50.07186],[5.880997,50.08069],[5.891965,50.12041],[5.952856,50.13384],[5.961753,50.17631]]],"terms_url":"https://data.public.lu/en/datasets/plan-cadastral-numerise-pcn-webservices-wms-et-wmts/","terms_text":"Administration du Cadastre et de la Topographie"},{"id":"osm-cambodia_laos_thailand_vietnam-bilingual","name":"Cambodia, Laos, Thailand, Vietnam, Myanmar bilingual","type":"tms","template":"http://{switch:a,b,c,d}.tile.osm-tools.org/osm_then/{zoom}/{x}/{y}.png","scaleExtent":[0,19],"polygon":[[[92.1023798,20.8135629],[93.5690546,24.0975527],[94.1733026,23.9269484],[95.1950312,26.707274],[96.7550898,27.5286657],[97.5845575,28.5805966],[98.738122,27.514051],[98.7436151,25.8799151],[97.6779413,24.7577376],[97.9635858,24.042382],[98.8205194,24.1627239],[99.5236444,22.9593356],[100.3695917,21.5051376],[101.7923212,22.4830518],[105.3628778,23.3331079],[106.8185663,22.8480137],[108.1973505,21.3619661],[107.4389505,18.8539792],[117.1453714,7.4656173],[119.6172953,5.2875389],[118.1231546,4.0502277],[117.2552347,4.3624942],[115.8654642,4.3460623],[115.5084085,3.0249771],[114.552598,1.5100953],[113.5418558,1.2574836],[112.9650736,1.5704982],[112.2454691,1.5100953],[111.67418,1.0158321],[110.4546976,0.9004918],[109.4988871,1.9218969],[103.2256937,1.1256762],[100.4626322,3.2388904],[97.6721048,8.0588831],[93.892808,15.9398659],[92.1023798,20.8135629]]],"terms_url":"http://www.osm-tools.org/","terms_text":"© osm-tools.org & OpenStreetMap contributors, CC-BY-SA"},{"id":"South_Africa-CapeTown-Aerial-2013","name":"City of Cape Town 2013 Aerial","type":"tms","template":"http://{switch:a,b,c}.coct.aerial.openstreetmap.org.za/layer/za_coct_aerial_2013/{zoom}/{x}/{y}.jpg","description":"OpenStreetMap use only. City of Cape Town Aerial ortho-photography of the municipal area. 12cm ground sample distance","scaleExtent":[1,21],"polygon":[[[18.4486565,-33.893623],[18.4485868,-33.902644],[18.4702,-33.9027665],[18.4813902,-33.8472383],[18.4492466,-33.801069],[18.4281537,-33.7356408],[18.43914,-33.7177232],[18.4071895,-33.6589917],[18.3322379,-33.5775191],[18.3324525,-33.5504487],[18.353996,-33.5505918],[18.3542535,-33.5236025],[18.3652398,-33.5236561],[18.3650252,-33.5148009],[18.3760115,-33.5147652],[18.3760545,-33.5058017],[18.4296557,-33.5059449],[18.4296986,-33.4878541],[18.4404919,-33.4878899],[18.4405991,-33.4698849],[18.4943721,-33.4700997],[18.4943292,-33.4791564],[18.5158297,-33.4791743],[18.5157439,-33.4881941],[18.5264727,-33.4883015],[18.5263225,-33.5243538],[18.5479304,-33.5244253],[18.5479519,-33.5153913],[18.5693666,-33.5154987],[18.5693666,-33.524479],[18.5801169,-33.5245327],[18.580074,-33.5425978],[18.5907814,-33.5425978],[18.5907385,-33.5606413],[18.5799453,-33.5605341],[18.5798809,-33.569617],[18.5906956,-33.569617],[18.5906526,-33.5786811],[18.6230108,-33.5787347],[18.622925,-33.5877264],[18.6659691,-33.5878872],[18.6659262,-33.614928],[18.6767194,-33.6149726],[18.6765772,-33.6510279],[18.687298,-33.6510167],[18.6873409,-33.6600365],[18.6980697,-33.6600901],[18.6980697,-33.6690733],[18.7520358,-33.6692519],[18.7520787,-33.6421924],[18.7736437,-33.642246],[18.773708,-33.6331886],[18.8274595,-33.6332958],[18.8275239,-33.6603044],[18.8166663,-33.6602866],[18.8166019,-33.6783233],[18.8058087,-33.6783055],[18.8058087,-33.7053892],[18.8273951,-33.7054428],[18.8273308,-33.7234701],[18.838124,-33.7234344],[18.8380381,-33.7413865],[18.8165161,-33.7413687],[18.8163659,-33.7955057],[18.8055941,-33.7955057],[18.8055083,-33.8135675],[18.794758,-33.8135497],[18.7947151,-33.8315364],[18.7731072,-33.8315186],[18.7731287,-33.8405194],[18.7623569,-33.8405194],[18.7622711,-33.903588],[18.7514564,-33.9035167],[18.7510809,-33.9847823],[18.7619063,-33.9848001],[18.7617776,-34.0298785],[18.772603,-34.0298963],[18.7725815,-34.0389073],[18.7940338,-34.0389406],[18.7938756,-34.0406987],[18.7984461,-34.0411855],[18.8032445,-34.0411788],[18.8034055,-34.0389206],[18.8159367,-34.038974],[18.8163444,-34.0299318],[18.8379845,-34.0316479],[18.8380006,-34.030003],[18.8484183,-34.0300074],[18.8484666,-34.0218491],[18.859925,-34.0234675],[18.8598606,-34.0210132],[18.868272,-34.0220803],[18.8681862,-34.0211733],[18.8854596,-34.0234319],[18.8851806,-34.0213156],[18.9025184,-34.021031],[18.9025828,-34.0119958],[18.9134189,-34.0119958],[18.9134833,-33.9939582],[18.9458844,-33.9940294],[18.9458629,-34.003102],[18.9674279,-34.0029953],[18.9674708,-34.0120848],[18.9782211,-34.0120848],[18.9783284,-34.0211377],[18.9891431,-34.0211377],[18.9891645,-34.039134],[19.0000167,-34.0391251],[19.0000221,-34.0571798],[19.0108368,-34.0572509],[19.0107939,-34.0841436],[19.0000007,-34.0841258],[19.0000221,-34.0931977],[18.9891538,-34.0931711],[18.9891753,-34.1021976],[18.9783177,-34.1021798],[18.9783177,-34.111232],[18.967503,-34.1112143],[18.9674923,-34.1292536],[18.9566025,-34.1292358],[18.9565596,-34.1382408],[18.9674172,-34.1383118],[18.9674172,-34.1473157],[18.9891753,-34.147298],[18.9891753,-34.165303],[18.9782748,-34.1652852],[18.9783177,-34.1742863],[18.9674172,-34.1742685],[18.9674601,-34.1833042],[18.9565596,-34.1833219],[18.9565596,-34.1923565],[18.9457449,-34.192321],[18.945702,-34.2013192],[18.9348659,-34.2013725],[18.9348873,-34.2193305],[18.9023575,-34.2193482],[18.9017567,-34.2362557],[18.8878414,-34.2373467],[18.8894185,-34.2554123],[18.8805887,-34.2553414],[18.8792744,-34.2644348],[18.8696882,-34.2644126],[18.8697097,-34.2734386],[18.8371369,-34.2734208],[18.8371155,-34.2643771],[18.848016,-34.2644037],[18.8480267,-34.237391],[18.8154861,-34.210281],[18.8156471,-34.1741265],[18.8548824,-34.1562743],[18.7617561,-34.0840547],[18.6533734,-34.077479],[18.4797433,-34.1101217],[18.4463713,-34.1342269],[18.4444508,-34.1640868],[18.4359965,-34.1640513],[18.435975,-34.1820172],[18.4468111,-34.182106],[18.4467253,-34.1911052],[18.4659299,-34.1912117],[18.4866151,-34.2453911],[18.4788904,-34.2543659],[18.4860036,-34.2543748],[18.4677109,-34.2994116],[18.4892222,-34.3445792],[18.500112,-34.3445837],[18.4999189,-34.3626174],[18.467432,-34.3625111],[18.4673676,-34.3534947],[18.3916005,-34.3170651],[18.3917722,-34.2900161],[18.3701643,-34.2808678],[18.370682,-34.2178866],[18.3492324,-34.1816178],[18.3274743,-34.1814936],[18.3276674,-34.1634565],[18.3118746,-34.1543832],[18.3114025,-34.1435331],[18.3236656,-34.1346886],[18.3499297,-34.1042053],[18.3393189,-34.0882843],[18.3612487,-34.0597219],[18.3550474,-34.0553843],[18.3427522,-34.064326],[18.3199963,-34.0644326],[18.296071,-34.045126],[18.3068213,-34.0252637],[18.3287725,-34.0191992],[18.3289227,-34.001252],[18.3397374,-34.0012698],[18.3398017,-33.9866282],[18.3628687,-33.9735145],[18.3638129,-33.9292474],[18.3726212,-33.9292741],[18.3728358,-33.917763],[18.3977267,-33.8933469],[18.4486565,-33.893623]]],"terms_url":"https://www.capetown.gov.za","terms_text":"City of Cape Town Aerial - OPENSTREETMAP USE ONLY"},{"id":"South_Africa-CapeTown-Aerial","name":"City of Cape Town 2015 Aerial","type":"tms","template":"http://{switch:a,b,c}.coct.aerial.openstreetmap.org.za/layer/za_coct_aerial_2015/{zoom}/{x}/{y}.jpg","description":"OpenStreetMap use only. City of Cape Town Aerial ortho-photography of the municipal area. 8cm ground sample distance","scaleExtent":[1,21],"polygon":[[[18.4486565,-33.893623],[18.4485868,-33.902644],[18.4702,-33.9027665],[18.4813902,-33.8472383],[18.4492466,-33.801069],[18.4281537,-33.7356408],[18.43914,-33.7177232],[18.4071895,-33.6589917],[18.3322379,-33.5775191],[18.3324525,-33.5504487],[18.353996,-33.5505918],[18.3542535,-33.5236025],[18.3652398,-33.5236561],[18.3650252,-33.5148009],[18.3760115,-33.5147652],[18.3760545,-33.5058017],[18.4296557,-33.5059449],[18.4296986,-33.4878541],[18.4404919,-33.4878899],[18.4405991,-33.4698849],[18.4943721,-33.4700997],[18.4943292,-33.4791564],[18.5158297,-33.4791743],[18.5157439,-33.4881941],[18.5264727,-33.4883015],[18.5263225,-33.5243538],[18.5479304,-33.5244253],[18.5479519,-33.5153913],[18.5693666,-33.5154987],[18.5693666,-33.524479],[18.5801169,-33.5245327],[18.580074,-33.5425978],[18.5907814,-33.5425978],[18.5907385,-33.5606413],[18.5799453,-33.5605341],[18.5798809,-33.569617],[18.5906956,-33.569617],[18.5906526,-33.5786811],[18.6230108,-33.5787347],[18.622925,-33.5877264],[18.6659691,-33.5878872],[18.6659262,-33.614928],[18.6767194,-33.6149726],[18.6765772,-33.6510279],[18.687298,-33.6510167],[18.6873409,-33.6600365],[18.6980697,-33.6600901],[18.6980697,-33.6690733],[18.7520358,-33.6692519],[18.7520787,-33.6421924],[18.7736437,-33.642246],[18.773708,-33.6331886],[18.8274595,-33.6332958],[18.8275239,-33.6603044],[18.8166663,-33.6602866],[18.8166019,-33.6783233],[18.8058087,-33.6783055],[18.8058087,-33.7053892],[18.8273951,-33.7054428],[18.8273308,-33.7234701],[18.838124,-33.7234344],[18.8380381,-33.7413865],[18.8165161,-33.7413687],[18.8163659,-33.7955057],[18.8055941,-33.7955057],[18.8055083,-33.8135675],[18.794758,-33.8135497],[18.7947151,-33.8315364],[18.7731072,-33.8315186],[18.7731287,-33.8405194],[18.7623569,-33.8405194],[18.7622711,-33.903588],[18.7514564,-33.9035167],[18.7510809,-33.9847823],[18.7619063,-33.9848001],[18.7617776,-34.0298785],[18.772603,-34.0298963],[18.7725815,-34.0389073],[18.7940338,-34.0389406],[18.7938756,-34.0406987],[18.7984461,-34.0411855],[18.8032445,-34.0411788],[18.8034055,-34.0389206],[18.8159367,-34.038974],[18.8163444,-34.0299318],[18.8379845,-34.0316479],[18.8380006,-34.030003],[18.8484183,-34.0300074],[18.8484666,-34.0218491],[18.859925,-34.0234675],[18.8598606,-34.0210132],[18.868272,-34.0220803],[18.8681862,-34.0211733],[18.8854596,-34.0234319],[18.8851806,-34.0213156],[18.9025184,-34.021031],[18.9025828,-34.0119958],[18.9134189,-34.0119958],[18.9134833,-33.9939582],[18.9458844,-33.9940294],[18.9458629,-34.003102],[18.9674279,-34.0029953],[18.9674708,-34.0120848],[18.9782211,-34.0120848],[18.9783284,-34.0211377],[18.9891431,-34.0211377],[18.9891645,-34.039134],[19.0000167,-34.0391251],[19.0000221,-34.0571798],[19.0108368,-34.0572509],[19.0107939,-34.0841436],[19.0000007,-34.0841258],[19.0000221,-34.0931977],[18.9891538,-34.0931711],[18.9891753,-34.1021976],[18.9783177,-34.1021798],[18.9783177,-34.111232],[18.967503,-34.1112143],[18.9674923,-34.1292536],[18.9566025,-34.1292358],[18.9565596,-34.1382408],[18.9674172,-34.1383118],[18.9674172,-34.1473157],[18.9891753,-34.147298],[18.9891753,-34.165303],[18.9782748,-34.1652852],[18.9783177,-34.1742863],[18.9674172,-34.1742685],[18.9674601,-34.1833042],[18.9565596,-34.1833219],[18.9565596,-34.1923565],[18.9457449,-34.192321],[18.945702,-34.2013192],[18.9348659,-34.2013725],[18.9348873,-34.2193305],[18.9023575,-34.2193482],[18.9017567,-34.2362557],[18.8878414,-34.2373467],[18.8894185,-34.2554123],[18.8805887,-34.2553414],[18.8792744,-34.2644348],[18.8696882,-34.2644126],[18.8697097,-34.2734386],[18.8371369,-34.2734208],[18.8371155,-34.2643771],[18.848016,-34.2644037],[18.8480267,-34.237391],[18.8154861,-34.210281],[18.8156471,-34.1741265],[18.8548824,-34.1562743],[18.7617561,-34.0840547],[18.6533734,-34.077479],[18.4797433,-34.1101217],[18.4463713,-34.1342269],[18.4444508,-34.1640868],[18.4359965,-34.1640513],[18.435975,-34.1820172],[18.4468111,-34.182106],[18.4467253,-34.1911052],[18.4659299,-34.1912117],[18.4866151,-34.2453911],[18.4788904,-34.2543659],[18.4860036,-34.2543748],[18.4677109,-34.2994116],[18.4892222,-34.3445792],[18.500112,-34.3445837],[18.4999189,-34.3626174],[18.467432,-34.3625111],[18.4673676,-34.3534947],[18.3916005,-34.3170651],[18.3917722,-34.2900161],[18.3701643,-34.2808678],[18.370682,-34.2178866],[18.3492324,-34.1816178],[18.3274743,-34.1814936],[18.3276674,-34.1634565],[18.3118746,-34.1543832],[18.3114025,-34.1435331],[18.3236656,-34.1346886],[18.3499297,-34.1042053],[18.3393189,-34.0882843],[18.3612487,-34.0597219],[18.3550474,-34.0553843],[18.3427522,-34.064326],[18.3199963,-34.0644326],[18.296071,-34.045126],[18.3068213,-34.0252637],[18.3287725,-34.0191992],[18.3289227,-34.001252],[18.3397374,-34.0012698],[18.3398017,-33.9866282],[18.3628687,-33.9735145],[18.3638129,-33.9292474],[18.3726212,-33.9292741],[18.3728358,-33.917763],[18.3977267,-33.8933469],[18.4486565,-33.893623]]],"terms_url":"https://www.capetown.gov.za","terms_text":"City of Cape Town Aerial - OPENSTREETMAP USE ONLY","best":true},{"id":"CRAIG-Auvergne-2013","name":"CRAIG - Auvergne 2013 - 25 cm","type":"tms","template":"http://tiles.craig.fr/osm/tms/1.0.0/ortho_2013/webmercator/{zoom-1}/{x}/{-y}.jpeg","polygon":[[[2.9401192,44.6338837],[2.9971896,44.633931],[2.9971676,44.6473385],[3.0159744,44.6473541],[3.0159305,44.6741168],[3.0349486,44.6741326],[3.0349036,44.7015216],[3.0536338,44.7015371],[3.0535675,44.7418954],[3.0723301,44.741911],[3.0722196,44.8091687],[3.0921583,44.8091852],[3.092137,44.8221252],[3.1301398,44.8221567],[3.1300495,44.8770722],[3.1485587,44.8770875],[3.1485807,44.8636964],[3.1682313,44.8637126],[3.1682538,44.8500261],[3.2064,44.8500576],[3.2063789,44.8628393],[3.2439492,44.8628704],[3.2439263,44.8767893],[3.2631452,44.8768052],[3.2630782,44.9175197],[3.3200437,44.9175667],[3.3200227,44.9303336],[3.3390815,44.9303493],[3.3390586,44.9441978],[3.3769989,44.9442292],[3.3770218,44.9302879],[3.396031,44.9303036],[3.39612,44.8762713],[3.4148252,44.8762867],[3.4148923,44.8355255],[3.4333371,44.8355408],[3.4333819,44.8082784],[3.4525549,44.8082943],[3.4525774,44.7946344],[3.5089262,44.7946811],[3.508904,44.8081469],[3.604265,44.8082258],[3.6042213,44.8348239],[3.6236136,44.83484],[3.6235695,44.8616583],[3.6424823,44.8616739],[3.642549,44.821102],[3.6610055,44.8211172],[3.6610275,44.8077696],[3.6992999,44.8078013],[3.6992782,44.820994],[3.7361139,44.8210245],[3.7361819,44.7797075],[3.7751058,44.7797397],[3.775151,44.7522344],[3.8118352,44.7522648],[3.8118567,44.7392021],[3.8311822,44.7392181],[3.8312061,44.7246766],[3.887824,44.7247235],[3.8878019,44.7381833],[3.925626,44.7382146],[3.9256039,44.7516682],[3.9454097,44.7516846],[3.9453656,44.7784691],[3.9643737,44.7784848],[3.9643516,44.7919273],[4.0033183,44.7919596],[4.0032964,44.8052575],[4.0216937,44.8052727],[4.0216718,44.8185687],[4.0596515,44.8186001],[4.0596082,44.8449216],[4.0798132,44.8449383],[4.0797928,44.8573502],[4.173882,44.857428],[4.1738604,44.8705468],[4.1932576,44.8705628],[4.193235,44.8842744],[4.2140385,44.8842916],[4.2139961,44.9100242],[4.2324138,44.9100394],[4.2323689,44.9373093],[4.2715486,44.9373416],[4.2715273,44.9502971],[4.3288672,44.9503445],[4.3287793,45.0036659],[4.3489259,45.0036825],[4.3489038,45.0170656],[4.4060793,45.0171127],[4.4059904,45.0710024],[4.3884707,45.0709879],[4.3884482,45.0845976],[4.407943,45.0846137],[4.4079231,45.09663],[4.4843608,45.0966929],[4.4842941,45.1370472],[4.4663631,45.1370324],[4.4663413,45.1502035],[4.4864469,45.15022],[4.4864022,45.1772415],[4.5065524,45.177258],[4.5064402,45.2450058],[4.4881342,45.2449908],[4.4881106,45.2592077],[4.4698588,45.2591927],[4.469836,45.2729835],[4.4508849,45.2729679],[4.4508626,45.2864203],[4.3936753,45.2863733],[4.3936303,45.3135182],[4.3750893,45.3135029],[4.3750662,45.3274054],[4.3950734,45.3274218],[4.3950283,45.3545849],[4.3767871,45.35457],[4.3767639,45.3685486],[4.3576564,45.3685329],[4.3576335,45.3823359],[4.2814576,45.3822734],[4.2814334,45.3968834],[4.2444556,45.3968531],[4.2444325,45.4107893],[4.1481178,45.4107104],[4.1481388,45.3980659],[4.1291913,45.3980504],[4.1292145,45.3840899],[4.0902138,45.3840579],[4.0902351,45.3712093],[4.0135507,45.3711464],[4.0135259,45.3860975],[3.9170932,45.3860185],[3.9170704,45.3997355],[3.9375703,45.3997523],[3.9375481,45.4131142],[3.975277,45.4131451],[3.9752552,45.4262061],[3.9953725,45.4262226],[3.9956999,45.5209568],[3.9777821,45.5209421],[3.977693,45.5743873],[3.9581755,45.5743714],[3.9581522,45.5883658],[3.9396019,45.5883506],[3.9395781,45.6026212],[3.9202279,45.6026054],[3.9202048,45.6164603],[3.8818916,45.616429],[3.8818468,45.643276],[3.8441329,45.6432453],[3.8441098,45.6570896],[3.8261689,45.657075],[3.8261241,45.6838865],[3.8072175,45.6838711],[3.8071277,45.7375802],[3.7882101,45.7375648],[3.7881863,45.7517966],[3.7688482,45.7517809],[3.7688028,45.7789651],[3.750719,45.7789504],[3.7505822,45.8606554],[3.7696692,45.8606709],[3.7695793,45.914333],[3.751661,45.9143185],[3.7516379,45.9280879],[3.7328974,45.9280727],[3.7328527,45.9547155],[3.8101795,45.9547782],[3.8101569,45.9682278],[3.8495994,45.9682598],[3.8495098,46.0216192],[3.8318849,46.0216049],[3.8317936,46.0759058],[3.8505037,46.0759209],[3.8504583,46.1029545],[3.8324727,46.10294],[3.8323353,46.1845598],[3.8142194,46.1845452],[3.8141522,46.2244234],[3.8336864,46.2244392],[3.8336634,46.2381001],[3.8528929,46.2381156],[3.8528703,46.2514729],[3.8931424,46.2515054],[3.8931205,46.2644677],[3.9130562,46.2644838],[3.9130335,46.2779317],[3.9518926,46.2779631],[3.9518709,46.2908227],[3.971523,46.2908386],[3.9715012,46.3036947],[4.0105021,46.3037261],[4.0104784,46.3177638],[4.0298278,46.3177794],[4.029783,46.3442827],[4.0116018,46.344268],[4.0114647,46.4253437],[4.031532,46.4253598],[4.0314635,46.4657978],[4.0132435,46.4657832],[4.0132204,46.479378],[3.9943703,46.4793629],[3.9943461,46.4936113],[3.9745971,46.4935955],[3.9745735,46.5075278],[3.8775423,46.5074499],[3.8774959,46.5347758],[3.8583577,46.5347605],[3.8583347,46.5483156],[3.8186897,46.5482838],[3.8187114,46.5355316],[3.7992386,46.535516],[3.7992156,46.5490706],[3.7610377,46.5490399],[3.7609226,46.6168059],[3.7423295,46.616791],[3.7422834,46.6439624],[3.7228558,46.6439468],[3.7228098,46.6710357],[3.7038706,46.6710206],[3.7038474,46.6846709],[3.6841096,46.6846551],[3.6840631,46.711998],[3.6648359,46.7119826],[3.6647898,46.7390375],[3.6457623,46.7390222],[3.6457158,46.7663375],[3.6257542,46.7663216],[3.6257314,46.7797093],[3.5672301,46.7796626],[3.5672528,46.7663082],[3.5471462,46.7662922],[3.5471922,46.7392824],[3.5271621,46.7392664],[3.5272308,46.6988967],[3.4877399,46.6988651],[3.4877618,46.685943],[3.4679636,46.6859272],[3.4679407,46.6994059],[3.4679179,46.7127907],[3.4486497,46.7127753],[3.4486258,46.7267878],[3.350433,46.7267092],[3.3504786,46.6999004],[3.3303913,46.6998843],[3.3303448,46.7271984],[3.2327174,46.7271203],[3.2327406,46.7135148],[3.2129042,46.7134989],[3.212927,46.7001302],[3.1735446,46.7000987],[3.173498,46.7275094],[3.1541227,46.7274939],[3.1541002,46.7407271],[3.1147772,46.7406957],[3.114754,46.7542756],[3.0753432,46.7542441],[3.0752971,46.7813548],[3.05597,46.7813394],[3.055924,46.8083069],[2.99704,46.8082598],[2.9970166,46.8219593],[2.9379443,46.8219121],[2.9379675,46.8082604],[2.8986634,46.808229],[2.8986872,46.7942392],[2.878991,46.7942234],[2.8790134,46.7810427],[2.8594188,46.781027],[2.8594415,46.7677056],[2.8400446,46.7676901],[2.8400671,46.754466],[2.7414032,46.7543871],[2.741382,46.7668245],[2.7023351,46.7667932],[2.7023571,46.7538869],[2.6826621,46.7538711],[2.6826849,46.7404752],[2.6634875,46.7404599],[2.6635123,46.7258966],[2.6434164,46.7258805],[2.6434382,46.7130938],[2.6241432,46.7130784],[2.6241658,46.6998093],[2.6039699,46.6997931],[2.6039936,46.6858433],[2.5651245,46.6858122],[2.5651469,46.6726126],[2.5459278,46.6725972],[2.5459966,46.6321534],[2.5659222,46.6321694],[2.565946,46.6181104],[2.5456397,46.6180941],[2.5456862,46.5907192],[2.5664225,46.5907358],[2.5664449,46.5775417],[2.5854963,46.577557],[2.5855181,46.5647199],[2.5661318,46.5647044],[2.5661557,46.5506246],[2.468279,46.5505461],[2.4683039,46.5358205],[2.3321246,46.5357112],[2.3321701,46.5088566],[2.3126474,46.5088409],[2.3126703,46.4953444],[2.2928767,46.4953285],[2.2928996,46.4818182],[2.2748687,46.4818037],[2.2749151,46.4544154],[2.2553921,46.4543997],[2.255529,46.3734888],[2.275948,46.3735052],[2.276037,46.3208741],[2.3145615,46.3209052],[2.3145849,46.3070421],[2.3537075,46.3070737],[2.3537313,46.2929669],[2.3938428,46.2929992],[2.3938862,46.2672854],[2.4515727,46.267332],[2.451596,46.2534921],[2.4709353,46.2535077],[2.4709807,46.2265552],[2.4915062,46.2265718],[2.4915521,46.199329],[2.5108806,46.1993446],[2.5109254,46.1727799],[2.5311728,46.1727963],[2.5313772,46.051352],[2.5516349,46.0513684],[2.5516577,46.0377665],[2.5705635,46.0377818],[2.5706774,45.9699434],[2.5514356,45.9699278],[2.551458,45.9566151],[2.5322621,45.9565995],[2.5322849,45.9430066],[2.5130653,45.942991],[2.513134,45.9020279],[2.4749412,45.9019969],[2.4749633,45.8888235],[2.4361947,45.888792],[2.4362172,45.8753288],[2.417209,45.8753133],[2.4172548,45.8479368],[2.3784736,45.8479053],[2.378497,45.8339746],[2.3595157,45.8339592],[2.3595606,45.8070849],[2.3787254,45.8071005],[2.3787481,45.7935783],[2.3986981,45.7935945],[2.3987203,45.7803477],[2.4182486,45.7803636],[2.4183161,45.7400007],[2.4572171,45.7400324],[2.4572394,45.7266956],[2.4758919,45.7267107],[2.4759144,45.7132391],[2.49533,45.7132549],[2.4954204,45.6591268],[2.4576942,45.659096],[2.4577622,45.618343],[2.4391188,45.6183278],[2.4391866,45.5776619],[2.4585044,45.5776777],[2.4585496,45.5505348],[2.4780887,45.5505508],[2.4781108,45.5372464],[2.4975506,45.5372623],[2.4975949,45.5106757],[2.4785536,45.5106601],[2.4786444,45.4561337],[2.4597798,45.4561183],[2.4598701,45.401757],[2.4224876,45.4017264],[2.4224651,45.4152816],[2.4023154,45.4152651],[2.4022929,45.4288193],[2.3256006,45.4287565],[2.3256684,45.3879609],[2.3456182,45.3879773],[2.3456629,45.3611091],[2.326256,45.3610932],[2.326279,45.3472146],[2.3073819,45.3471991],[2.3074045,45.3335972],[2.2881095,45.3335813],[2.2881307,45.3208191],[2.2696332,45.3208039],[2.2696574,45.306212],[2.2506602,45.3061964],[2.2506828,45.2925147],[2.2316866,45.2924992],[2.2317086,45.2792355],[2.2130009,45.2792202],[2.213046,45.2520355],[2.1937387,45.2520197],[2.1937617,45.2381134],[2.1756091,45.2380985],[2.1757423,45.1576822],[2.1573543,45.157667],[2.1574448,45.1029478],[2.1202408,45.1029172],[2.1202629,45.0895468],[2.1006669,45.0895306],[2.1006902,45.0754441],[2.0824591,45.0754291],[2.082548,45.0215961],[2.1025534,45.0216126],[2.1025982,44.994453],[2.0457406,44.9944061],[2.0458508,44.9275321],[2.0657794,44.9275486],[2.0658912,44.8596881],[2.0856964,44.8597044],[2.0857193,44.8458126],[2.1055593,44.8458291],[2.1056029,44.8193264],[2.124743,44.8193422],[2.1247657,44.805512],[2.1435067,44.8055275],[2.143551,44.778597],[2.1256091,44.7785822],[2.1256984,44.7242739],[2.1066459,44.7242581],[2.1067116,44.6842263],[2.1263414,44.6842426],[2.1263635,44.670735],[2.14598,44.6707513],[2.146069,44.6164441],[2.1839622,44.6164756],[2.183983,44.6037819],[2.2404173,44.6038288],[2.2403728,44.6309515],[2.25948,44.6309674],[2.2594571,44.644934],[2.316678,44.6449815],[2.3167011,44.6308801],[2.3361516,44.6308963],[2.3361734,44.6175824],[2.3724238,44.6176125],[2.3724009,44.6315823],[2.4110495,44.6316144],[2.4110701,44.6190741],[2.4492173,44.6191058],[2.4491956,44.6323197],[2.5048575,44.6323659],[2.5048126,44.6597555],[2.5246119,44.6597719],[2.524567,44.6871739],[2.5422544,44.6871886],[2.5422313,44.70122],[2.5807101,44.701252],[2.5805999,44.7683374],[2.61769,44.7683681],[2.6176235,44.808838],[2.6367564,44.8088539],[2.6366899,44.8492948],[2.6733105,44.8493251],[2.6732888,44.8625164],[2.6933766,44.862533],[2.6933323,44.8894303],[2.7305201,44.8894611],[2.7304757,44.9164461],[2.7499202,44.9164622],[2.7500519,44.8364688],[2.8073346,44.8365162],[2.8073139,44.8491017],[2.8263796,44.8491175],[2.8264007,44.8362845],[2.8457039,44.8363004],[2.8457707,44.7957107],[2.8642166,44.795726],[2.8642611,44.7686452],[2.8839885,44.7686615],[2.8840323,44.7419697],[2.9020315,44.7419846],[2.9021426,44.6743192],[2.9219777,44.6743357],[2.9220221,44.6472986],[2.9400972,44.6473136],[2.9401192,44.6338837]]],"terms_url":"http://wiki.openstreetmap.org/wiki/WikiProject_France/CRAIG","terms_text":"Orthophotographie CRAIG/Sintegra/IGN 2013"},{"id":"Czech_CUZK-KM-tms","name":"Czech CUZK:KM tiles proxy","type":"tms","template":"http://osm-{switch:a,b,c}.zby.cz/tiles_cuzk.php/{zoom}/{x}/{y}.png","scaleExtent":[13,18],"polygon":[[[15.0063684,49.0177392],[15.1559854,49.0013828],[15.190896,48.9424551],[15.3105895,48.9882938],[15.4053469,48.9752013],[15.5400022,48.9162426],[15.7145553,48.8670572],[15.8342488,48.880178],[15.968904,48.8178233],[16.0885976,48.7455261],[16.3978059,48.7455261],[16.4875761,48.8145394],[16.6721036,48.7784014],[16.6820781,48.7356594],[16.9015163,48.7126294],[16.9464014,48.6237005],[17.1159672,48.8375227],[17.2107246,48.880178],[17.4052266,48.8178233],[17.4800351,48.8539329],[17.5299074,48.8178233],[17.7044605,48.8670572],[17.8141796,48.9359033],[17.8840008,48.9359033],[17.9438476,49.0210099],[18.0635412,49.0340903],[18.1184007,49.0994409],[18.1981964,49.3047337],[18.3877112,49.3339917],[18.577226,49.5091747],[18.7567663,49.4994587],[18.8465365,49.5253637],[18.8764598,49.5706645],[18.7966641,49.693412],[18.64206,49.7095399],[18.5872004,49.8351543],[18.6121366,49.8833809],[18.5622643,49.9347695],[18.512392,49.9058702],[18.362775,49.9540261],[18.3278644,49.9219275],[18.2630304,49.9732751],[18.1184007,50.0053395],[18.0635412,50.075806],[17.9139242,49.9796897],[17.779269,50.0309757],[17.714435,50.1237921],[17.6047159,50.1653411],[17.7593201,50.21962],[17.7343839,50.3439092],[17.6396265,50.2802117],[17.3802905,50.2802117],[17.3503671,50.3439092],[17.2805459,50.3375433],[17.1857885,50.4075214],[16.9015163,50.4615247],[16.8666057,50.4138779],[16.9663503,50.3184404],[17.0361715,50.2323826],[16.8366823,50.21962],[16.7120015,50.1046034],[16.5823335,50.1589513],[16.5623846,50.2387626],[16.4327166,50.3375433],[16.3529209,50.3916263],[16.2781124,50.3916263],[16.2082911,50.4456477],[16.3978059,50.5344899],[16.4476782,50.5978464],[16.3529209,50.670601],[16.2382145,50.6769221],[16.2182656,50.6326561],[16.1284954,50.6832425],[16.0486997,50.6073425],[15.988853,50.7021983],[15.8741467,50.6832425],[15.8292616,50.7653291],[15.729517,50.743243],[15.450232,50.8157725],[15.3903852,50.7747914],[15.3804108,50.8598659],[15.2956278,50.8850434],[15.2956278,50.9887568],[15.1709471,51.0201394],[14.9914067,51.0013124],[15.0063684,50.8881896],[14.8417898,50.8756034],[14.7969047,50.8252246],[14.6323261,50.8567177],[14.6622495,50.9353576],[14.5724793,50.9227841],[14.6123772,50.9856174],[14.4976708,51.0483657],[14.4178751,51.0232765],[14.3081561,51.0671736],[14.2532965,51.0044508],[14.4029134,50.9322145],[14.3729901,50.897627],[14.2433221,50.9070625],[14.2084114,50.844123],[14.0338583,50.8126214],[13.9789988,50.8252246],[13.9041903,50.7968626],[13.8742669,50.740087],[13.5351352,50.7243038],[13.530148,50.6579561],[13.4703012,50.6136722],[13.3905055,50.664279],[13.3256715,50.5883483],[13.250863,50.6105074],[13.1960035,50.5059517],[13.0513738,50.5218084],[12.9665909,50.4106997],[12.8269484,50.4710483],[12.7022676,50.4138779],[12.5077656,50.401164],[12.343187,50.2547088],[12.323238,50.1845054],[12.2484296,50.2738373],[12.1736211,50.3311765],[12.0988126,50.33436],[12.1187616,50.25152],[12.2234934,50.1653411],[12.2035445,50.1237921],[12.5027784,49.9732751],[12.4778422,49.9379795],[12.5476634,49.9155052],[12.4678677,49.8029766],[12.408021,49.7611134],[12.4828294,49.6869593],[12.5327017,49.6869593],[12.5177401,49.6288466],[12.6075102,49.5415474],[12.6723442,49.4378793],[12.8119867,49.3469896],[12.9466419,49.3437405],[13.2309141,49.1288206],[13.3256715,49.1059712],[13.4353906,49.0438984],[13.4154417,48.9948387],[13.5002246,48.949006],[13.5650586,48.9882938],[13.6847522,48.8834577],[13.7445989,48.9031312],[13.8243946,48.7751149],[13.8992031,48.7751149],[14.0587945,48.676418],[14.0438328,48.6302932],[14.1435774,48.5907241],[14.3729901,48.5610269],[14.4827091,48.6500662],[14.5774665,48.607215],[14.6273389,48.6335892],[14.7071346,48.5808269],[14.7470324,48.7027561],[14.8118664,48.7389485],[14.8168536,48.794831],[14.9864195,48.7652539],[15.0063684,49.0177392]]],"overlay":true},{"id":"Czech_RUIAN-budovy","name":"Czech RUIAN budovy","type":"tms","template":"http://tile.poloha.net/budovy/{zoom}/{x}/{y}.png","scaleExtent":[12,20],"polygon":[[[15.0063684,49.0177392],[15.1559854,49.0013828],[15.190896,48.9424551],[15.3105895,48.9882938],[15.4053469,48.9752013],[15.5400022,48.9162426],[15.7145553,48.8670572],[15.8342488,48.880178],[15.968904,48.8178233],[16.0885976,48.7455261],[16.3978059,48.7455261],[16.4875761,48.8145394],[16.6721036,48.7784014],[16.6820781,48.7356594],[16.9015163,48.7126294],[16.9464014,48.6237005],[17.1159672,48.8375227],[17.2107246,48.880178],[17.4052266,48.8178233],[17.4800351,48.8539329],[17.5299074,48.8178233],[17.7044605,48.8670572],[17.8141796,48.9359033],[17.8840008,48.9359033],[17.9438476,49.0210099],[18.0635412,49.0340903],[18.1184007,49.0994409],[18.1981964,49.3047337],[18.3877112,49.3339917],[18.577226,49.5091747],[18.7567663,49.4994587],[18.8465365,49.5253637],[18.8764598,49.5706645],[18.7966641,49.693412],[18.64206,49.7095399],[18.5872004,49.8351543],[18.6121366,49.8833809],[18.5622643,49.9347695],[18.512392,49.9058702],[18.362775,49.9540261],[18.3278644,49.9219275],[18.2630304,49.9732751],[18.1184007,50.0053395],[18.0635412,50.075806],[17.9139242,49.9796897],[17.779269,50.0309757],[17.714435,50.1237921],[17.6047159,50.1653411],[17.7593201,50.21962],[17.7343839,50.3439092],[17.6396265,50.2802117],[17.3802905,50.2802117],[17.3503671,50.3439092],[17.2805459,50.3375433],[17.1857885,50.4075214],[16.9015163,50.4615247],[16.8666057,50.4138779],[16.9663503,50.3184404],[17.0361715,50.2323826],[16.8366823,50.21962],[16.7120015,50.1046034],[16.5823335,50.1589513],[16.5623846,50.2387626],[16.4327166,50.3375433],[16.3529209,50.3916263],[16.2781124,50.3916263],[16.2082911,50.4456477],[16.3978059,50.5344899],[16.4476782,50.5978464],[16.3529209,50.670601],[16.2382145,50.6769221],[16.2182656,50.6326561],[16.1284954,50.6832425],[16.0486997,50.6073425],[15.988853,50.7021983],[15.8741467,50.6832425],[15.8292616,50.7653291],[15.729517,50.743243],[15.450232,50.8157725],[15.3903852,50.7747914],[15.3804108,50.8598659],[15.2956278,50.8850434],[15.2956278,50.9887568],[15.1709471,51.0201394],[14.9914067,51.0013124],[15.0063684,50.8881896],[14.8417898,50.8756034],[14.7969047,50.8252246],[14.6323261,50.8567177],[14.6622495,50.9353576],[14.5724793,50.9227841],[14.6123772,50.9856174],[14.4976708,51.0483657],[14.4178751,51.0232765],[14.3081561,51.0671736],[14.2532965,51.0044508],[14.4029134,50.9322145],[14.3729901,50.897627],[14.2433221,50.9070625],[14.2084114,50.844123],[14.0338583,50.8126214],[13.9789988,50.8252246],[13.9041903,50.7968626],[13.8742669,50.740087],[13.5351352,50.7243038],[13.530148,50.6579561],[13.4703012,50.6136722],[13.3905055,50.664279],[13.3256715,50.5883483],[13.250863,50.6105074],[13.1960035,50.5059517],[13.0513738,50.5218084],[12.9665909,50.4106997],[12.8269484,50.4710483],[12.7022676,50.4138779],[12.5077656,50.401164],[12.343187,50.2547088],[12.323238,50.1845054],[12.2484296,50.2738373],[12.1736211,50.3311765],[12.0988126,50.33436],[12.1187616,50.25152],[12.2234934,50.1653411],[12.2035445,50.1237921],[12.5027784,49.9732751],[12.4778422,49.9379795],[12.5476634,49.9155052],[12.4678677,49.8029766],[12.408021,49.7611134],[12.4828294,49.6869593],[12.5327017,49.6869593],[12.5177401,49.6288466],[12.6075102,49.5415474],[12.6723442,49.4378793],[12.8119867,49.3469896],[12.9466419,49.3437405],[13.2309141,49.1288206],[13.3256715,49.1059712],[13.4353906,49.0438984],[13.4154417,48.9948387],[13.5002246,48.949006],[13.5650586,48.9882938],[13.6847522,48.8834577],[13.7445989,48.9031312],[13.8243946,48.7751149],[13.8992031,48.7751149],[14.0587945,48.676418],[14.0438328,48.6302932],[14.1435774,48.5907241],[14.3729901,48.5610269],[14.4827091,48.6500662],[14.5774665,48.607215],[14.6273389,48.6335892],[14.7071346,48.5808269],[14.7470324,48.7027561],[14.8118664,48.7389485],[14.8168536,48.794831],[14.9864195,48.7652539],[15.0063684,49.0177392]]],"terms_url":"http://poloha.net/"},{"id":"Czech_RUIAN-parcely","name":"Czech RUIAN parcely","type":"tms","template":"http://tile.poloha.net/parcely/{zoom}/{x}/{y}.png","scaleExtent":[12,20],"polygon":[[[15.0063684,49.0177392],[15.1559854,49.0013828],[15.190896,48.9424551],[15.3105895,48.9882938],[15.4053469,48.9752013],[15.5400022,48.9162426],[15.7145553,48.8670572],[15.8342488,48.880178],[15.968904,48.8178233],[16.0885976,48.7455261],[16.3978059,48.7455261],[16.4875761,48.8145394],[16.6721036,48.7784014],[16.6820781,48.7356594],[16.9015163,48.7126294],[16.9464014,48.6237005],[17.1159672,48.8375227],[17.2107246,48.880178],[17.4052266,48.8178233],[17.4800351,48.8539329],[17.5299074,48.8178233],[17.7044605,48.8670572],[17.8141796,48.9359033],[17.8840008,48.9359033],[17.9438476,49.0210099],[18.0635412,49.0340903],[18.1184007,49.0994409],[18.1981964,49.3047337],[18.3877112,49.3339917],[18.577226,49.5091747],[18.7567663,49.4994587],[18.8465365,49.5253637],[18.8764598,49.5706645],[18.7966641,49.693412],[18.64206,49.7095399],[18.5872004,49.8351543],[18.6121366,49.8833809],[18.5622643,49.9347695],[18.512392,49.9058702],[18.362775,49.9540261],[18.3278644,49.9219275],[18.2630304,49.9732751],[18.1184007,50.0053395],[18.0635412,50.075806],[17.9139242,49.9796897],[17.779269,50.0309757],[17.714435,50.1237921],[17.6047159,50.1653411],[17.7593201,50.21962],[17.7343839,50.3439092],[17.6396265,50.2802117],[17.3802905,50.2802117],[17.3503671,50.3439092],[17.2805459,50.3375433],[17.1857885,50.4075214],[16.9015163,50.4615247],[16.8666057,50.4138779],[16.9663503,50.3184404],[17.0361715,50.2323826],[16.8366823,50.21962],[16.7120015,50.1046034],[16.5823335,50.1589513],[16.5623846,50.2387626],[16.4327166,50.3375433],[16.3529209,50.3916263],[16.2781124,50.3916263],[16.2082911,50.4456477],[16.3978059,50.5344899],[16.4476782,50.5978464],[16.3529209,50.670601],[16.2382145,50.6769221],[16.2182656,50.6326561],[16.1284954,50.6832425],[16.0486997,50.6073425],[15.988853,50.7021983],[15.8741467,50.6832425],[15.8292616,50.7653291],[15.729517,50.743243],[15.450232,50.8157725],[15.3903852,50.7747914],[15.3804108,50.8598659],[15.2956278,50.8850434],[15.2956278,50.9887568],[15.1709471,51.0201394],[14.9914067,51.0013124],[15.0063684,50.8881896],[14.8417898,50.8756034],[14.7969047,50.8252246],[14.6323261,50.8567177],[14.6622495,50.9353576],[14.5724793,50.9227841],[14.6123772,50.9856174],[14.4976708,51.0483657],[14.4178751,51.0232765],[14.3081561,51.0671736],[14.2532965,51.0044508],[14.4029134,50.9322145],[14.3729901,50.897627],[14.2433221,50.9070625],[14.2084114,50.844123],[14.0338583,50.8126214],[13.9789988,50.8252246],[13.9041903,50.7968626],[13.8742669,50.740087],[13.5351352,50.7243038],[13.530148,50.6579561],[13.4703012,50.6136722],[13.3905055,50.664279],[13.3256715,50.5883483],[13.250863,50.6105074],[13.1960035,50.5059517],[13.0513738,50.5218084],[12.9665909,50.4106997],[12.8269484,50.4710483],[12.7022676,50.4138779],[12.5077656,50.401164],[12.343187,50.2547088],[12.323238,50.1845054],[12.2484296,50.2738373],[12.1736211,50.3311765],[12.0988126,50.33436],[12.1187616,50.25152],[12.2234934,50.1653411],[12.2035445,50.1237921],[12.5027784,49.9732751],[12.4778422,49.9379795],[12.5476634,49.9155052],[12.4678677,49.8029766],[12.408021,49.7611134],[12.4828294,49.6869593],[12.5327017,49.6869593],[12.5177401,49.6288466],[12.6075102,49.5415474],[12.6723442,49.4378793],[12.8119867,49.3469896],[12.9466419,49.3437405],[13.2309141,49.1288206],[13.3256715,49.1059712],[13.4353906,49.0438984],[13.4154417,48.9948387],[13.5002246,48.949006],[13.5650586,48.9882938],[13.6847522,48.8834577],[13.7445989,48.9031312],[13.8243946,48.7751149],[13.8992031,48.7751149],[14.0587945,48.676418],[14.0438328,48.6302932],[14.1435774,48.5907241],[14.3729901,48.5610269],[14.4827091,48.6500662],[14.5774665,48.607215],[14.6273389,48.6335892],[14.7071346,48.5808269],[14.7470324,48.7027561],[14.8118664,48.7389485],[14.8168536,48.794831],[14.9864195,48.7652539],[15.0063684,49.0177392]]],"terms_url":"http://poloha.net/"},{"id":"Duna_2013","name":"Danube flood orthophoto 2013","type":"tms","template":"http://e.tile.openstreetmap.hu/dunai-arviz-2013/{zoom}/{x}/{y}.jpg","scaleExtent":[10,20],"polygon":[[[19.0773152,47.6959718],[19.0779881,47.6959835],[19.0946205,47.6944562],[19.0805603,47.595874],[19.0743376,47.5890907],[19.0795196,47.5888284],[19.07717,47.5724109],[19.0577884,47.5720924],[19.0773152,47.6959718]]],"terms_url":"http://fototerkep.hu/","terms_text":"Fotótérkép.hu"},{"id":"Delaware2012Orthophotography","name":"Delaware 2012 Orthophotography","type":"tms","template":"http://whoots.mapwarper.net/tms/{zoom}/{x}/{y}/0/https://firstmap.delaware.gov/arcgis/services/DE_Imagery/DE_Imagery_2012/ImageServer/WMSServer","description":"This data set consists of 0.3-meter pixel resolution (approximately 1-foot), 4-band true color and near infrared (R, G, B, IR) orthoimages covering New Castle, Kent and Sussex Counties in Delaware.","polygon":[[[-75.01770587603,38.45188674427],[-75.74173524589,38.4499581145],[-75.80699639658,39.73907123636],[-75.75558784863,39.80106251053],[-75.64692187603,39.8563815616],[-75.47114773904,39.84645578141],[-75.37725787603,39.81477822231],[-75.48746302671,39.6718115509],[-75.50901151986,39.43446011595],[-75.39326532808,39.27784018498],[-75.30707135548,39.01666513594],[-75.1931721774,38.82218696272],[-75.05341480753,38.80875503297],[-75.01770587603,38.45188674427]]],"terms_url":"https://firstmap.delaware.gov/arcgis/rest/services/DE_Imagery/DE_Imagery_2012/ImageServer","terms_text":"Digital Aerial Solutions, LLC"},{"id":"DigitalGlobe-Premium","name":"DigitalGlobe Premium Imagery","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/digitalglobe.316c9a2e/{zoom}/{x}/{y}.png?access_token=pk.eyJ1IjoiZGlnaXRhbGdsb2JlIiwiYSI6ImNqMmFxdGp5aTAwOWIzM3M1NDZ2eGU1a2QifQ.JN5adNxCwK_oprEwFEtjjg","scaleExtent":[0,19],"terms_url":"https://wiki.openstreetmap.org/wiki/DigitalGlobe","terms_text":"Terms & Feedback","default":true},{"id":"DigitalGlobe-Standard","name":"DigitalGlobe Standard Imagery","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/digitalglobe.0a8e44ba/{zoom}/{x}/{y}.png?access_token=pk.eyJ1IjoiZGlnaXRhbGdsb2JlIiwiYSI6ImNqMmFxcGJ2MjAwOHEzMm9nZmF2c3luZWkifQ.HsF19zOlj8PeOxo5BhNqyQ","scaleExtent":[0,19],"terms_url":"https://wiki.openstreetmap.org/wiki/DigitalGlobe","terms_text":"Terms & Feedback","default":true},{"id":"maaamet.ee-orto","name":"Estonia Ortho (Maaamet)","type":"tms","template":"http://kaart.maakaart.ee/orto/{zoom}/{x}/{y}.jpeg","scaleExtent":[14,20],"polygon":[[[21.6940073,57.5025466],[21.6940073,59.8274564],[28.2110546,59.8274564],[28.2110546,57.5025466],[21.6940073,57.5025466]]],"terms_text":"Maa-Ameti ortofoto"},{"id":"FOMI_2000","name":"FÖMI orthophoto 2000","type":"tms","template":"http://e.tile.openstreetmap.hu/ortofoto2000/{zoom}/{x}/{y}.jpg","scaleExtent":[0,17],"polygon":[[[16.1139147,46.8691038],[16.1789749,46.90662],[16.2000429,46.9415079],[16.2217547,46.9355441],[16.2462784,46.9463851],[16.2553226,46.9642125],[16.2764694,46.9626082],[16.290583,47.0139849],[16.3016199,46.9992329],[16.3414618,46.9965225],[16.3505162,47.0106313],[16.3734016,46.9985929],[16.412765,47.00475],[16.4332705,46.9927417],[16.4478119,47.003893],[16.479997,46.9941169],[16.5121988,47.0011695],[16.4635584,47.0322699],[16.4478586,47.0227481],[16.439123,47.029663],[16.445673,47.038872],[16.520323,47.056103],[16.473213,47.0736169],[16.4637199,47.09392],[16.500798,47.110058],[16.500035,47.123295],[16.5295349,47.1287419],[16.5171609,47.1496938],[16.454951,47.1425878],[16.4648728,47.1683349],[16.4555643,47.1875584],[16.4305559,47.1847022],[16.4195013,47.1949147],[16.4189215,47.2107114],[16.4371293,47.2097043],[16.4426335,47.2337117],[16.4313127,47.2527554],[16.4671512,47.2531652],[16.4892319,47.2798885],[16.4646338,47.3338455],[16.4337002,47.3528101],[16.458513,47.3670496],[16.4454619,47.4070195],[16.4831657,47.4093628],[16.4963821,47.3892659],[16.5170941,47.4100218],[16.5749054,47.4054243],[16.5807291,47.4191699],[16.661847,47.455595],[16.6706419,47.47422],[16.6523395,47.500342],[16.6895619,47.510161],[16.7147797,47.540199],[16.663545,47.567733],[16.673199,47.6049544],[16.6595343,47.6061018],[16.652758,47.622852],[16.6314207,47.6283176],[16.5739108,47.619667],[16.5147382,47.6461964],[16.4967504,47.6393149],[16.425464,47.6621679],[16.4437449,47.674205],[16.4480507,47.6964725],[16.4746984,47.6811576],[16.4872245,47.6979767],[16.5521729,47.7225519],[16.5363779,47.736785],[16.5479799,47.751544],[16.6095193,47.7603722],[16.6344148,47.7590843],[16.65729,47.7414879],[16.7209405,47.7353565],[16.7534062,47.6828165],[16.8301587,47.681058],[16.8394284,47.7045139],[16.8668943,47.7211462],[16.876679,47.6876452],[17.0937421,47.7077706],[17.0706562,47.7285366],[17.0516019,47.7938499],[17.0749479,47.8084997],[17.047139,47.8285635],[17.0519452,47.8377691],[17.0105513,47.8581765],[17.0163878,47.8673325],[17.0857537,47.8746239],[17.113171,47.9271605],[17.0917133,47.9342916],[17.1183782,47.9601083],[17.094657,47.9708775],[17.2010289,48.019992],[17.241769,48.0224651],[17.257955,47.998655],[17.334651,47.993125],[17.4029929,47.947849],[17.4539199,47.8852579],[17.5267369,47.865509],[17.5675779,47.8151289],[17.608402,47.8218859],[17.7085789,47.756678],[17.7798739,47.739487],[17.8660959,47.74575],[17.9001292,47.7392633],[17.946867,47.744668],[17.9708709,47.7578392],[18.0044103,47.7463402],[18.0380583,47.7576812],[18.2958774,47.7314616],[18.4540681,47.7651226],[18.4931553,47.7527552],[18.5590761,47.7659963],[18.6460866,47.7590921],[18.7260691,47.7890411],[18.7411784,47.8138245],[18.7920013,47.8230869],[18.8485417,47.8167221],[18.855876,47.826077],[18.828014,47.834291],[18.8135749,47.85555],[18.76353,47.8716049],[18.756858,47.896838],[18.776746,47.955092],[18.7552499,47.9763469],[18.8157429,47.993442],[18.819998,48.039676],[18.833268,48.048239],[18.8749364,48.0470707],[18.886674,48.058682],[18.9089819,48.051139],[18.9439039,48.058865],[18.9816099,48.0536009],[19.0148639,48.078179],[19.0585249,48.0573529],[19.0843619,48.072781],[19.107402,48.065596],[19.1352889,48.074146],[19.2413679,48.0536529],[19.2557819,48.0715559],[19.3031119,48.088711],[19.3865969,48.091914],[19.400018,48.082304],[19.454053,48.101436],[19.467354,48.083933],[19.4944199,48.109906],[19.492377,48.1396639],[19.5128219,48.154663],[19.504518,48.173443],[19.528967,48.190358],[19.526044,48.20313],[19.577502,48.2160149],[19.6308263,48.2500725],[19.6445239,48.2391719],[19.669857,48.239212],[19.691219,48.203894],[19.721125,48.201473],[19.74618,48.2165119],[19.7871629,48.19253],[19.7987329,48.19482],[19.8052829,48.183733],[19.782415,48.165039],[19.794812,48.153529],[19.821331,48.169081],[19.8452819,48.162742],[19.8551729,48.178431],[19.8601309,48.169409],[19.898745,48.1663119],[19.9145359,48.146863],[19.898298,48.1249019],[19.937383,48.131118],[19.9743939,48.1660049],[19.988706,48.1621679],[20.029038,48.1776849],[20.049449,48.1671999],[20.0729859,48.179606],[20.0700369,48.1917019],[20.1340909,48.225182],[20.1331879,48.253982],[20.206162,48.250979],[20.2038299,48.261906],[20.228466,48.262779],[20.2349469,48.279933],[20.286858,48.26164],[20.3257109,48.272794],[20.3374649,48.301667],[20.3656579,48.316606],[20.384077,48.3511809],[20.4098349,48.365857],[20.402532,48.382565],[20.4205349,48.403858],[20.416228,48.418536],[20.507929,48.489363],[20.5065069,48.534415],[20.537471,48.527878],[20.5464939,48.544292],[20.586595,48.535759],[20.6538739,48.561413],[20.836359,48.58284],[20.8378,48.57421],[20.8504359,48.5816329],[20.8453301,48.5665046],[20.8681549,48.551818],[20.922323,48.559453],[20.9346349,48.538341],[20.955882,48.533963],[20.9561979,48.521666],[20.9815849,48.5177669],[21.0151139,48.532313],[21.0663209,48.525894],[21.1174479,48.4910549],[21.1608749,48.521499],[21.179634,48.518232],[21.221061,48.537497],[21.305488,48.5222489],[21.313377,48.550841],[21.326875,48.554129],[21.319384,48.561201],[21.4154499,48.558951],[21.4226649,48.578821],[21.4406099,48.585104],[21.514091,48.551065],[21.5420199,48.508395],[21.6139329,48.509416],[21.6201879,48.469826],[21.663549,48.417961],[21.6645609,48.392164],[21.7017409,48.380695],[21.711871,48.357617],[21.8174139,48.332787],[21.8352029,48.3346409],[21.837213,48.363253],[21.8842979,48.356047],[21.8848429,48.367539],[21.897883,48.36256],[21.8997959,48.3702229],[21.9281859,48.3615969],[21.9268059,48.370899],[21.949198,48.378728],[21.994463,48.377323],[22.0213259,48.392749],[22.0546049,48.377528],[22.0764859,48.387241],[22.086743,48.371564],[22.1359089,48.380519],[22.131056,48.3912329],[22.152768,48.3962409],[22.1561913,48.4093076],[22.2125722,48.4256468],[22.2371405,48.4100396],[22.2654858,48.4098675],[22.2398761,48.3870055],[22.2675722,48.3611612],[22.3178106,48.3545437],[22.3132861,48.3250712],[22.3372944,48.3079113],[22.3384267,48.2792074],[22.3847547,48.2339632],[22.4006407,48.249198],[22.4328384,48.2525166],[22.456386,48.2423109],[22.4899029,48.2534237],[22.4972201,48.2395546],[22.5161491,48.237965],[22.5311088,48.2094282],[22.5711442,48.1961428],[22.5616362,48.1816066],[22.5982449,48.144756],[22.5902763,48.1073414],[22.6754492,48.091997],[22.7347192,48.119848],[22.7576242,48.1200599],[22.7703914,48.1090162],[22.772319,48.1218742],[22.8027688,48.1221112],[22.8025285,48.1070813],[22.8254256,48.1175119],[22.8364365,48.080249],[22.8611284,48.0750312],[22.8677955,48.0524256],[22.8820424,48.0548053],[22.8659692,48.0113165],[22.835562,47.9905988],[22.8407599,47.9813636],[22.8725729,47.9752683],[22.8697274,47.9659593],[22.8915652,47.9672446],[22.897435,47.9540629],[22.8473299,47.9077579],[22.7928135,47.8908586],[22.7586924,47.8941446],[22.77775,47.8422508],[22.7136344,47.8360928],[22.6801938,47.7877527],[22.6111171,47.7717455],[22.5490018,47.7722246],[22.4812121,47.8108886],[22.4513078,47.803389],[22.4313319,47.7398119],[22.3566167,47.7486206],[22.3177714,47.7660887],[22.3176236,47.7433657],[22.2851369,47.7292757],[22.264325,47.7310675],[22.2589955,47.6979057],[22.2306796,47.693196],[22.1796501,47.5916115],[22.1289245,47.5978984],[22.0942787,47.5583628],[22.0782587,47.5621299],[22.0534529,47.5474795],[22.0712176,47.5380742],[22.0617872,47.5288029],[22.0451278,47.5398919],[22.0367222,47.5326653],[22.0071886,47.48362],[22.0327909,47.4508372],[22.0238835,47.3908631],[22.0119849,47.3758016],[21.9627373,47.381053],[21.9382461,47.3725317],[21.8777922,47.2857763],[21.8872845,47.2730473],[21.8534909,47.2397622],[21.8580662,47.1873597],[21.8124804,47.1667511],[21.7924092,47.1059751],[21.7268258,47.0983882],[21.6976037,47.057915],[21.6504151,47.0408303],[21.6888701,47.0019977],[21.6678744,46.9712337],[21.6814917,46.9652089],[21.6381964,46.9330487],[21.5984455,46.9274708],[21.6142857,46.8867275],[21.6016694,46.8668202],[21.520328,46.8373749],[21.5186086,46.8000703],[21.4831761,46.7650246],[21.5263389,46.7393249],[21.529369,46.7209721],[21.4923253,46.6859652],[21.4728438,46.6959075],[21.4299047,46.693937],[21.4309553,46.6781367],[21.4546661,46.660863],[21.4162375,46.6426231],[21.4097959,46.6218052],[21.3657038,46.6379501],[21.3300499,46.6318155],[21.3139733,46.617666],[21.3012351,46.5908672],[21.3207905,46.5828562],[21.2743045,46.5407362],[21.2600254,46.5021583],[21.2744188,46.4767333],[21.2964506,46.4762973],[21.3174343,46.4507288],[21.2895176,46.4154784],[21.2963256,46.4069601],[21.2250116,46.4136899],[21.2064214,46.4033825],[21.1992563,46.3479034],[21.1762269,46.3357664],[21.180497,46.3044494],[21.1155437,46.3018529],[21.1030549,46.2624637],[21.0708792,46.2539014],[21.0660827,46.2429394],[21.0366237,46.2480392],[21.0246723,46.2665329],[20.960817,46.2623039],[20.9465849,46.2793024],[20.9250701,46.2766191],[20.9218133,46.2618129],[20.8732713,46.2877555],[20.7756538,46.2759602],[20.7490474,46.2508489],[20.7618619,46.204563],[20.727401,46.2077485],[20.7341052,46.1939355],[20.7140487,46.1660531],[20.6843592,46.1447802],[20.6549178,46.1497739],[20.6394471,46.1267602],[20.5450486,46.1790935],[20.5014839,46.190334],[20.4949436,46.1709908],[20.4592293,46.1428837],[20.3975133,46.1574709],[20.3685325,46.1528554],[20.3557074,46.1696256],[20.2968136,46.1521542],[20.2549024,46.1158522],[20.2484757,46.1300956],[20.2330132,46.1241668],[20.1817362,46.1601137],[20.1364966,46.1449476],[20.1009667,46.1772756],[20.0636156,46.1437275],[20.0346142,46.1458888],[20.0158072,46.1768354],[19.9354075,46.1764243],[19.8533469,46.1500005],[19.8179747,46.1281652],[19.7585403,46.1479754],[19.6982054,46.1879317],[19.6827672,46.1800388],[19.661508,46.1904394],[19.6317396,46.1692993],[19.5676482,46.179106],[19.5604013,46.1665762],[19.5026585,46.1424492],[19.5271208,46.1210269],[19.4645033,46.0953827],[19.4665828,46.0820437],[19.4160037,46.0460453],[19.3803957,46.0358749],[19.3640923,46.0522965],[19.2819012,46.0148048],[19.2965348,45.9881173],[19.2856472,45.9968981],[19.1479857,45.9963445],[19.1338422,46.0370993],[19.104873,46.0401673],[19.0660427,46.0001999],[19.0796791,45.9636376],[19.0059803,45.9590674],[19.0092745,45.9236559],[18.9061334,45.9353801],[18.8794572,45.9166827],[18.8647137,45.9208493],[18.8685629,45.9113361],[18.8276792,45.9051714],[18.8220041,45.9145893],[18.8075092,45.9036055],[18.809247,45.8796189],[18.7956242,45.8784488],[18.7048857,45.9181883],[18.6700246,45.9108439],[18.6596602,45.9168934],[18.6651348,45.899279],[18.6412808,45.8890396],[18.6550179,45.8742393],[18.6277704,45.8733782],[18.6148449,45.8531438],[18.6236656,45.8398531],[18.5732391,45.8137578],[18.5749849,45.8004344],[18.559716,45.8037961],[18.5223504,45.7826858],[18.4906706,45.7947167],[18.4821905,45.7655032],[18.4562828,45.7695229],[18.4450763,45.7605195],[18.446853,45.737128],[18.40763,45.7397119],[18.3918949,45.7616983],[18.3642257,45.7729364],[18.3394214,45.7471605],[18.2968157,45.7612196],[18.2440473,45.7612305],[18.2307311,45.7790328],[18.1908702,45.7878759],[18.1681939,45.7762712],[18.1246514,45.7896277],[18.1068067,45.7708256],[18.0818922,45.7645205],[17.9958808,45.7957311],[17.9302095,45.7863301],[17.9066757,45.7925692],[17.8653145,45.7670064],[17.8262748,45.8099957],[17.8089784,45.8040989],[17.7809054,45.8174884],[17.7603399,45.811923],[17.7408624,45.8295975],[17.6632915,45.8381849],[17.6276211,45.8979446],[17.5700676,45.9358204],[17.4378254,45.9503823],[17.4258964,45.9272681],[17.4108059,45.9399665],[17.392149,45.9302149],[17.3828713,45.9475733],[17.3476208,45.9423413],[17.3438769,45.9605329],[17.3537711,45.9525011],[17.3905375,45.9581914],[17.387423,45.9661823],[17.3583539,45.9642737],[17.3754852,45.9686921],[17.3751895,45.9881054],[17.3635685,45.9915442],[17.3567202,45.9735836],[17.3339583,45.9960781],[17.3319847,45.9728948],[17.3129974,45.9665347],[17.323647,45.9887776],[17.2987653,45.9838652],[17.3041996,46.0021128],[17.2579726,46.0110256],[17.29632,46.0285169],[17.2541514,46.030005],[17.270955,46.0567055],[17.2324767,46.0592034],[17.2525145,46.0664725],[17.2313144,46.0790345],[17.2019916,46.0765488],[17.2331299,46.0989644],[17.2104017,46.1001693],[17.2129734,46.113855],[17.175927,46.1084583],[17.1743424,46.1287608],[17.1865197,46.1332308],[17.1810983,46.1505485],[17.1562307,46.1585819],[17.1592857,46.1696818],[17.1261012,46.1684495],[17.1227409,46.1789791],[17.0752482,46.1889531],[17.0661614,46.2022984],[16.9735401,46.2251982],[16.973954,46.2431113],[16.9504085,46.2415285],[16.8862356,46.2814598],[16.8713682,46.3252767],[16.8802109,46.3356966],[16.8615374,46.3452401],[16.8656232,46.3556489],[16.8521959,46.3517189],[16.8498589,46.3626245],[16.8352859,46.3638195],[16.8376499,46.3748032],[16.8261732,46.3670994],[16.7933444,46.387385],[16.7592072,46.3776563],[16.7298672,46.40149],[16.7182119,46.3898704],[16.6772872,46.4494536],[16.6631785,46.4486958],[16.6663732,46.4582995],[16.6187915,46.4619875],[16.604468,46.4760773],[16.5235997,46.5053761],[16.5325768,46.5314027],[16.5176728,46.5363516],[16.5084107,46.5652692],[16.4829969,46.5660383],[16.4834008,46.5786011],[16.4455713,46.610952],[16.4248583,46.6131645],[16.385941,46.6442485],[16.3915424,46.6637257],[16.4198454,46.6584771],[16.4286335,46.6939737],[16.3689211,46.7040082],[16.3798266,46.7153869],[16.3710856,46.7222945],[16.3570587,46.7142387],[16.3185954,46.7541449],[16.3305417,46.7752119],[16.3121626,46.7780033],[16.3127666,46.797314],[16.3406373,46.8051851],[16.3508404,46.8300552],[16.3403309,46.8468762],[16.3015007,46.8595142],[16.2913867,46.8728341],[16.2332296,46.8766702],[16.1560866,46.8537074],[16.126571,46.8569079],[16.1139147,46.8691038]]],"terms_url":"http://www.fomi.hu/","terms_text":"Földmérési és Távérzékelési Intézet"},{"id":"FOMI_2005","name":"FÖMI orthophoto 2005","type":"tms","template":"http://e.tile.openstreetmap.hu/ortofoto2005/{zoom}/{x}/{y}.jpg","scaleExtent":[0,17],"polygon":[[[16.1139147,46.8691038],[16.1789749,46.90662],[16.2000429,46.9415079],[16.2217547,46.9355441],[16.2462784,46.9463851],[16.2553226,46.9642125],[16.2764694,46.9626082],[16.290583,47.0139849],[16.3016199,46.9992329],[16.3414618,46.9965225],[16.3505162,47.0106313],[16.3734016,46.9985929],[16.412765,47.00475],[16.4332705,46.9927417],[16.4478119,47.003893],[16.479997,46.9941169],[16.5121988,47.0011695],[16.4635584,47.0322699],[16.4478586,47.0227481],[16.439123,47.029663],[16.445673,47.038872],[16.520323,47.056103],[16.473213,47.0736169],[16.4637199,47.09392],[16.500798,47.110058],[16.500035,47.123295],[16.5295349,47.1287419],[16.5171609,47.1496938],[16.454951,47.1425878],[16.4648728,47.1683349],[16.4555643,47.1875584],[16.4305559,47.1847022],[16.4195013,47.1949147],[16.4189215,47.2107114],[16.4371293,47.2097043],[16.4426335,47.2337117],[16.4313127,47.2527554],[16.4671512,47.2531652],[16.4892319,47.2798885],[16.4646338,47.3338455],[16.4337002,47.3528101],[16.458513,47.3670496],[16.4454619,47.4070195],[16.4831657,47.4093628],[16.4963821,47.3892659],[16.5170941,47.4100218],[16.5749054,47.4054243],[16.5807291,47.4191699],[16.661847,47.455595],[16.6706419,47.47422],[16.6523395,47.500342],[16.6895619,47.510161],[16.7147797,47.540199],[16.663545,47.567733],[16.673199,47.6049544],[16.6595343,47.6061018],[16.652758,47.622852],[16.6314207,47.6283176],[16.5739108,47.619667],[16.5147382,47.6461964],[16.4967504,47.6393149],[16.425464,47.6621679],[16.4437449,47.674205],[16.4480507,47.6964725],[16.4746984,47.6811576],[16.4872245,47.6979767],[16.5521729,47.7225519],[16.5363779,47.736785],[16.5479799,47.751544],[16.6095193,47.7603722],[16.6344148,47.7590843],[16.65729,47.7414879],[16.7209405,47.7353565],[16.7534062,47.6828165],[16.8301587,47.681058],[16.8394284,47.7045139],[16.8668943,47.7211462],[16.876679,47.6876452],[17.0937421,47.7077706],[17.0706562,47.7285366],[17.0516019,47.7938499],[17.0749479,47.8084997],[17.047139,47.8285635],[17.0519452,47.8377691],[17.0105513,47.8581765],[17.0163878,47.8673325],[17.0857537,47.8746239],[17.113171,47.9271605],[17.0917133,47.9342916],[17.1183782,47.9601083],[17.094657,47.9708775],[17.2010289,48.019992],[17.241769,48.0224651],[17.257955,47.998655],[17.334651,47.993125],[17.4029929,47.947849],[17.4539199,47.8852579],[17.5267369,47.865509],[17.5675779,47.8151289],[17.608402,47.8218859],[17.7085789,47.756678],[17.7798739,47.739487],[17.8660959,47.74575],[17.9001292,47.7392633],[17.946867,47.744668],[17.9708709,47.7578392],[18.0044103,47.7463402],[18.0380583,47.7576812],[18.2958774,47.7314616],[18.4540681,47.7651226],[18.4931553,47.7527552],[18.5590761,47.7659963],[18.6460866,47.7590921],[18.7260691,47.7890411],[18.7411784,47.8138245],[18.7920013,47.8230869],[18.8485417,47.8167221],[18.855876,47.826077],[18.828014,47.834291],[18.8135749,47.85555],[18.76353,47.8716049],[18.756858,47.896838],[18.776746,47.955092],[18.7552499,47.9763469],[18.8157429,47.993442],[18.819998,48.039676],[18.833268,48.048239],[18.8749364,48.0470707],[18.886674,48.058682],[18.9089819,48.051139],[18.9439039,48.058865],[18.9816099,48.0536009],[19.0148639,48.078179],[19.0585249,48.0573529],[19.0843619,48.072781],[19.107402,48.065596],[19.1352889,48.074146],[19.2413679,48.0536529],[19.2557819,48.0715559],[19.3031119,48.088711],[19.3865969,48.091914],[19.400018,48.082304],[19.454053,48.101436],[19.467354,48.083933],[19.4944199,48.109906],[19.492377,48.1396639],[19.5128219,48.154663],[19.504518,48.173443],[19.528967,48.190358],[19.526044,48.20313],[19.577502,48.2160149],[19.6308263,48.2500725],[19.6445239,48.2391719],[19.669857,48.239212],[19.691219,48.203894],[19.721125,48.201473],[19.74618,48.2165119],[19.7871629,48.19253],[19.7987329,48.19482],[19.8052829,48.183733],[19.782415,48.165039],[19.794812,48.153529],[19.821331,48.169081],[19.8452819,48.162742],[19.8551729,48.178431],[19.8601309,48.169409],[19.898745,48.1663119],[19.9145359,48.146863],[19.898298,48.1249019],[19.937383,48.131118],[19.9743939,48.1660049],[19.988706,48.1621679],[20.029038,48.1776849],[20.049449,48.1671999],[20.0729859,48.179606],[20.0700369,48.1917019],[20.1340909,48.225182],[20.1331879,48.253982],[20.206162,48.250979],[20.2038299,48.261906],[20.228466,48.262779],[20.2349469,48.279933],[20.286858,48.26164],[20.3257109,48.272794],[20.3374649,48.301667],[20.3656579,48.316606],[20.384077,48.3511809],[20.4098349,48.365857],[20.402532,48.382565],[20.4205349,48.403858],[20.416228,48.418536],[20.507929,48.489363],[20.5065069,48.534415],[20.537471,48.527878],[20.5464939,48.544292],[20.586595,48.535759],[20.6538739,48.561413],[20.836359,48.58284],[20.8378,48.57421],[20.8504359,48.5816329],[20.8453301,48.5665046],[20.8681549,48.551818],[20.922323,48.559453],[20.9346349,48.538341],[20.955882,48.533963],[20.9561979,48.521666],[20.9815849,48.5177669],[21.0151139,48.532313],[21.0663209,48.525894],[21.1174479,48.4910549],[21.1608749,48.521499],[21.179634,48.518232],[21.221061,48.537497],[21.305488,48.5222489],[21.313377,48.550841],[21.326875,48.554129],[21.319384,48.561201],[21.4154499,48.558951],[21.4226649,48.578821],[21.4406099,48.585104],[21.514091,48.551065],[21.5420199,48.508395],[21.6139329,48.509416],[21.6201879,48.469826],[21.663549,48.417961],[21.6645609,48.392164],[21.7017409,48.380695],[21.711871,48.357617],[21.8174139,48.332787],[21.8352029,48.3346409],[21.837213,48.363253],[21.8842979,48.356047],[21.8848429,48.367539],[21.897883,48.36256],[21.8997959,48.3702229],[21.9281859,48.3615969],[21.9268059,48.370899],[21.949198,48.378728],[21.994463,48.377323],[22.0213259,48.392749],[22.0546049,48.377528],[22.0764859,48.387241],[22.086743,48.371564],[22.1359089,48.380519],[22.131056,48.3912329],[22.152768,48.3962409],[22.1561913,48.4093076],[22.2125722,48.4256468],[22.2371405,48.4100396],[22.2654858,48.4098675],[22.2398761,48.3870055],[22.2675722,48.3611612],[22.3178106,48.3545437],[22.3132861,48.3250712],[22.3372944,48.3079113],[22.3384267,48.2792074],[22.3847547,48.2339632],[22.4006407,48.249198],[22.4328384,48.2525166],[22.456386,48.2423109],[22.4899029,48.2534237],[22.4972201,48.2395546],[22.5161491,48.237965],[22.5311088,48.2094282],[22.5711442,48.1961428],[22.5616362,48.1816066],[22.5982449,48.144756],[22.5902763,48.1073414],[22.6754492,48.091997],[22.7347192,48.119848],[22.7576242,48.1200599],[22.7703914,48.1090162],[22.772319,48.1218742],[22.8027688,48.1221112],[22.8025285,48.1070813],[22.8254256,48.1175119],[22.8364365,48.080249],[22.8611284,48.0750312],[22.8677955,48.0524256],[22.8820424,48.0548053],[22.8659692,48.0113165],[22.835562,47.9905988],[22.8407599,47.9813636],[22.8725729,47.9752683],[22.8697274,47.9659593],[22.8915652,47.9672446],[22.897435,47.9540629],[22.8473299,47.9077579],[22.7928135,47.8908586],[22.7586924,47.8941446],[22.77775,47.8422508],[22.7136344,47.8360928],[22.6801938,47.7877527],[22.6111171,47.7717455],[22.5490018,47.7722246],[22.4812121,47.8108886],[22.4513078,47.803389],[22.4313319,47.7398119],[22.3566167,47.7486206],[22.3177714,47.7660887],[22.3176236,47.7433657],[22.2851369,47.7292757],[22.264325,47.7310675],[22.2589955,47.6979057],[22.2306796,47.693196],[22.1796501,47.5916115],[22.1289245,47.5978984],[22.0942787,47.5583628],[22.0782587,47.5621299],[22.0534529,47.5474795],[22.0712176,47.5380742],[22.0617872,47.5288029],[22.0451278,47.5398919],[22.0367222,47.5326653],[22.0071886,47.48362],[22.0327909,47.4508372],[22.0238835,47.3908631],[22.0119849,47.3758016],[21.9627373,47.381053],[21.9382461,47.3725317],[21.8777922,47.2857763],[21.8872845,47.2730473],[21.8534909,47.2397622],[21.8580662,47.1873597],[21.8124804,47.1667511],[21.7924092,47.1059751],[21.7268258,47.0983882],[21.6976037,47.057915],[21.6504151,47.0408303],[21.6888701,47.0019977],[21.6678744,46.9712337],[21.6814917,46.9652089],[21.6381964,46.9330487],[21.5984455,46.9274708],[21.6142857,46.8867275],[21.6016694,46.8668202],[21.520328,46.8373749],[21.5186086,46.8000703],[21.4831761,46.7650246],[21.5263389,46.7393249],[21.529369,46.7209721],[21.4923253,46.6859652],[21.4728438,46.6959075],[21.4299047,46.693937],[21.4309553,46.6781367],[21.4546661,46.660863],[21.4162375,46.6426231],[21.4097959,46.6218052],[21.3657038,46.6379501],[21.3300499,46.6318155],[21.3139733,46.617666],[21.3012351,46.5908672],[21.3207905,46.5828562],[21.2743045,46.5407362],[21.2600254,46.5021583],[21.2744188,46.4767333],[21.2964506,46.4762973],[21.3174343,46.4507288],[21.2895176,46.4154784],[21.2963256,46.4069601],[21.2250116,46.4136899],[21.2064214,46.4033825],[21.1992563,46.3479034],[21.1762269,46.3357664],[21.180497,46.3044494],[21.1155437,46.3018529],[21.1030549,46.2624637],[21.0708792,46.2539014],[21.0660827,46.2429394],[21.0366237,46.2480392],[21.0246723,46.2665329],[20.960817,46.2623039],[20.9465849,46.2793024],[20.9250701,46.2766191],[20.9218133,46.2618129],[20.8732713,46.2877555],[20.7756538,46.2759602],[20.7490474,46.2508489],[20.7618619,46.204563],[20.727401,46.2077485],[20.7341052,46.1939355],[20.7140487,46.1660531],[20.6843592,46.1447802],[20.6549178,46.1497739],[20.6394471,46.1267602],[20.5450486,46.1790935],[20.5014839,46.190334],[20.4949436,46.1709908],[20.4592293,46.1428837],[20.3975133,46.1574709],[20.3685325,46.1528554],[20.3557074,46.1696256],[20.2968136,46.1521542],[20.2549024,46.1158522],[20.2484757,46.1300956],[20.2330132,46.1241668],[20.1817362,46.1601137],[20.1364966,46.1449476],[20.1009667,46.1772756],[20.0636156,46.1437275],[20.0346142,46.1458888],[20.0158072,46.1768354],[19.9354075,46.1764243],[19.8533469,46.1500005],[19.8179747,46.1281652],[19.7585403,46.1479754],[19.6982054,46.1879317],[19.6827672,46.1800388],[19.661508,46.1904394],[19.6317396,46.1692993],[19.5676482,46.179106],[19.5604013,46.1665762],[19.5026585,46.1424492],[19.5271208,46.1210269],[19.4645033,46.0953827],[19.4665828,46.0820437],[19.4160037,46.0460453],[19.3803957,46.0358749],[19.3640923,46.0522965],[19.2819012,46.0148048],[19.2965348,45.9881173],[19.2856472,45.9968981],[19.1479857,45.9963445],[19.1338422,46.0370993],[19.104873,46.0401673],[19.0660427,46.0001999],[19.0796791,45.9636376],[19.0059803,45.9590674],[19.0092745,45.9236559],[18.9061334,45.9353801],[18.8794572,45.9166827],[18.8647137,45.9208493],[18.8685629,45.9113361],[18.8276792,45.9051714],[18.8220041,45.9145893],[18.8075092,45.9036055],[18.809247,45.8796189],[18.7956242,45.8784488],[18.7048857,45.9181883],[18.6700246,45.9108439],[18.6596602,45.9168934],[18.6651348,45.899279],[18.6412808,45.8890396],[18.6550179,45.8742393],[18.6277704,45.8733782],[18.6148449,45.8531438],[18.6236656,45.8398531],[18.5732391,45.8137578],[18.5749849,45.8004344],[18.559716,45.8037961],[18.5223504,45.7826858],[18.4906706,45.7947167],[18.4821905,45.7655032],[18.4562828,45.7695229],[18.4450763,45.7605195],[18.446853,45.737128],[18.40763,45.7397119],[18.3918949,45.7616983],[18.3642257,45.7729364],[18.3394214,45.7471605],[18.2968157,45.7612196],[18.2440473,45.7612305],[18.2307311,45.7790328],[18.1908702,45.7878759],[18.1681939,45.7762712],[18.1246514,45.7896277],[18.1068067,45.7708256],[18.0818922,45.7645205],[17.9958808,45.7957311],[17.9302095,45.7863301],[17.9066757,45.7925692],[17.8653145,45.7670064],[17.8262748,45.8099957],[17.8089784,45.8040989],[17.7809054,45.8174884],[17.7603399,45.811923],[17.7408624,45.8295975],[17.6632915,45.8381849],[17.6276211,45.8979446],[17.5700676,45.9358204],[17.4378254,45.9503823],[17.4258964,45.9272681],[17.4108059,45.9399665],[17.392149,45.9302149],[17.3828713,45.9475733],[17.3476208,45.9423413],[17.3438769,45.9605329],[17.3537711,45.9525011],[17.3905375,45.9581914],[17.387423,45.9661823],[17.3583539,45.9642737],[17.3754852,45.9686921],[17.3751895,45.9881054],[17.3635685,45.9915442],[17.3567202,45.9735836],[17.3339583,45.9960781],[17.3319847,45.9728948],[17.3129974,45.9665347],[17.323647,45.9887776],[17.2987653,45.9838652],[17.3041996,46.0021128],[17.2579726,46.0110256],[17.29632,46.0285169],[17.2541514,46.030005],[17.270955,46.0567055],[17.2324767,46.0592034],[17.2525145,46.0664725],[17.2313144,46.0790345],[17.2019916,46.0765488],[17.2331299,46.0989644],[17.2104017,46.1001693],[17.2129734,46.113855],[17.175927,46.1084583],[17.1743424,46.1287608],[17.1865197,46.1332308],[17.1810983,46.1505485],[17.1562307,46.1585819],[17.1592857,46.1696818],[17.1261012,46.1684495],[17.1227409,46.1789791],[17.0752482,46.1889531],[17.0661614,46.2022984],[16.9735401,46.2251982],[16.973954,46.2431113],[16.9504085,46.2415285],[16.8862356,46.2814598],[16.8713682,46.3252767],[16.8802109,46.3356966],[16.8615374,46.3452401],[16.8656232,46.3556489],[16.8521959,46.3517189],[16.8498589,46.3626245],[16.8352859,46.3638195],[16.8376499,46.3748032],[16.8261732,46.3670994],[16.7933444,46.387385],[16.7592072,46.3776563],[16.7298672,46.40149],[16.7182119,46.3898704],[16.6772872,46.4494536],[16.6631785,46.4486958],[16.6663732,46.4582995],[16.6187915,46.4619875],[16.604468,46.4760773],[16.5235997,46.5053761],[16.5325768,46.5314027],[16.5176728,46.5363516],[16.5084107,46.5652692],[16.4829969,46.5660383],[16.4834008,46.5786011],[16.4455713,46.610952],[16.4248583,46.6131645],[16.385941,46.6442485],[16.3915424,46.6637257],[16.4198454,46.6584771],[16.4286335,46.6939737],[16.3689211,46.7040082],[16.3798266,46.7153869],[16.3710856,46.7222945],[16.3570587,46.7142387],[16.3185954,46.7541449],[16.3305417,46.7752119],[16.3121626,46.7780033],[16.3127666,46.797314],[16.3406373,46.8051851],[16.3508404,46.8300552],[16.3403309,46.8468762],[16.3015007,46.8595142],[16.2913867,46.8728341],[16.2332296,46.8766702],[16.1560866,46.8537074],[16.126571,46.8569079],[16.1139147,46.8691038]]],"terms_url":"http://www.fomi.hu/","terms_text":"Földmérési és Távérzékelési Intézet"},{"id":"FR-BAN","name":"FR-BAN","type":"tms","template":"http://{switch:a,b,c}.layers.openstreetmap.fr/bano/{zoom}/{x}/{y}.png","description":"French address registry or Base Adresses Nationale","scaleExtent":[12,20],"polygon":[[[8.3247852,49.0891892],[6.1566882,49.6167369],[4.8666714,50.2126152],[2.4937064,51.1761675],[1.3121526,50.9324682],[1.2659981,50.1877492],[0.1121369,49.8258592],[-0.3494075,49.4312336],[-1.0232625,49.4852345],[-1.3278818,49.7901162],[-2.1032765,49.7901162],[-1.6232703,48.7420657],[-3.1002126,48.9728514],[-5.1125465,48.6811558],[-5.3525496,48.4367783],[-4.5984193,47.7194959],[-2.555398,47.0232784],[-2.4738077,46.6638823],[-1.6676954,46.1055717],[-1.334807,45.5141125],[-1.4914604,44.1627003],[-1.9940567,43.3708146],[-0.956228,42.7364747],[2.2029487,42.2841894],[3.2342502,42.5444129],[3.2407774,43.1140543],[4.0436261,43.3280964],[6.4325902,42.808345],[7.6270723,43.5934102],[7.8163619,44.1720643],[7.0396221,44.41967],[7.268075,45.4958141],[7.1244761,46.2140775],[6.5631347,46.771283],[7.6571492,47.59128],[7.6527839,47.5941813],[7.6224698,47.5776739],[7.6047297,47.578221],[7.5877054,47.5901532],[7.521558,47.65161],[7.503992,47.70235],[7.520958,47.77685],[7.557124,47.84839],[7.549463,47.879205],[7.574615,47.93028],[7.613179,47.96804],[7.611904,47.9871],[7.5612401,48.0383618],[7.574915,48.1258],[7.595338,48.15977],[7.633047,48.19717],[7.662748,48.22473],[7.684659,48.30305],[7.763463,48.49158],[7.8004602,48.5125977],[7.799582,48.5878],[7.834088,48.64439],[7.9121073,48.6889897],[7.9672295,48.7571585],[8.020692,48.78879],[8.043024,48.7956],[8.0864658,48.8130551],[8.1364418,48.8978239],[8.1970586,48.96021],[8.2816129,48.9948995],[8.2996723,49.025966],[8.3124269,49.0599642],[8.3247852,49.0891892]],[[9.3609615,43.1345098],[8.4393174,42.48439],[8.4836272,41.8175373],[8.8469677,41.3768281],[9.2058772,41.3136241],[9.48946,41.5461776],[9.6356823,42.1994563],[9.6046655,42.901254],[9.3609615,43.1345098]]],"terms_url":"https://wiki.openstreetmap.org/wiki/WikiProject_France/WikiProject_Base_Adresses_Nationale_Ouverte_(BANO)","terms_text":"Tiles © cquest@Openstreetmap France, data © OpenStreetMap contributors, ODBL"},{"id":"FR-Cadastre","name":"FR-Cadastre","type":"tms","template":"http://tms.cadastre.openstreetmap.fr/*/tout/{zoom}/{x}/{y}.png","description":"French land registry","scaleExtent":[12,20],"polygon":[[[8.3247852,49.0891892],[6.1566882,49.6167369],[4.8666714,50.2126152],[2.4937064,51.1761675],[1.3121526,50.9324682],[1.2659981,50.1877492],[0.1121369,49.8258592],[-0.3494075,49.4312336],[-1.0232625,49.4852345],[-1.3278818,49.7901162],[-2.1032765,49.7901162],[-1.6232703,48.7420657],[-3.1002126,48.9728514],[-5.1125465,48.6811558],[-5.3525496,48.4367783],[-4.5984193,47.7194959],[-2.555398,47.0232784],[-2.4738077,46.6638823],[-1.6676954,46.1055717],[-1.334807,45.5141125],[-1.4914604,44.1627003],[-1.9940567,43.3708146],[-0.956228,42.7364747],[2.2029487,42.2841894],[3.2342502,42.5444129],[3.2407774,43.1140543],[4.0436261,43.3280964],[6.4325902,42.808345],[7.6270723,43.5934102],[7.8163619,44.1720643],[7.0396221,44.41967],[7.268075,45.4958141],[7.1244761,46.2140775],[6.5631347,46.771283],[7.6571492,47.59128],[7.6527839,47.5941813],[7.6224698,47.5776739],[7.6047297,47.578221],[7.5877054,47.5901532],[7.521558,47.65161],[7.503992,47.70235],[7.520958,47.77685],[7.557124,47.84839],[7.549463,47.879205],[7.574615,47.93028],[7.613179,47.96804],[7.611904,47.9871],[7.5612401,48.0383618],[7.574915,48.1258],[7.595338,48.15977],[7.633047,48.19717],[7.662748,48.22473],[7.684659,48.30305],[7.763463,48.49158],[7.8004602,48.5125977],[7.799582,48.5878],[7.834088,48.64439],[7.9121073,48.6889897],[7.9672295,48.7571585],[8.020692,48.78879],[8.043024,48.7956],[8.0864658,48.8130551],[8.1364418,48.8978239],[8.1970586,48.96021],[8.2816129,48.9948995],[8.2996723,49.025966],[8.3124269,49.0599642],[8.3247852,49.0891892]],[[9.3609615,43.1345098],[8.4393174,42.48439],[8.4836272,41.8175373],[8.8469677,41.3768281],[9.2058772,41.3136241],[9.48946,41.5461776],[9.6356823,42.1994563],[9.6046655,42.901254],[9.3609615,43.1345098]]],"terms_url":"http://wiki.openstreetmap.org/wiki/WikiProject_Cadastre_Fran%C3%A7ais/Conditions_d%27utilisation","terms_text":"cadastre-dgi-fr source : Direction Générale des Impôts - Cadastre. Mise à jour : 2015"},{"id":"Freemap.sk-Car","name":"Freemap.sk Car","type":"tms","template":"http://t{switch:1,2,3,4}.freemap.sk/A/{zoom}/{x}/{y}.jpeg","scaleExtent":[8,16],"polygon":[[[19.83682,49.25529],[19.80075,49.42385],[19.60437,49.48058],[19.49179,49.63961],[19.21831,49.52604],[19.16778,49.42521],[19.00308,49.42236],[18.97611,49.5308],[18.54685,49.51425],[18.31432,49.33818],[18.15913,49.2961],[18.05564,49.11134],[17.56396,48.84938],[17.17929,48.88816],[17.058,48.81105],[16.90426,48.61947],[16.79685,48.38561],[17.06762,48.01116],[17.32787,47.97749],[17.51699,47.82535],[17.74776,47.73093],[18.29515,47.72075],[18.67959,47.75541],[18.89755,47.81203],[18.79463,47.88245],[18.84318,48.04046],[19.46212,48.05333],[19.62064,48.22938],[19.89585,48.09387],[20.33766,48.2643],[20.55395,48.52358],[20.82335,48.55714],[21.10271,48.47096],[21.45863,48.55513],[21.74536,48.31435],[22.15293,48.37179],[22.61255,49.08914],[22.09997,49.23814],[21.9686,49.36363],[21.6244,49.46989],[21.06873,49.46402],[20.94336,49.31088],[20.73052,49.44006],[20.22804,49.41714],[20.05234,49.23052],[19.83682,49.25529]]],"terms_text":"Copyright ©2007-2012 Freemap Slovakia (www.freemap.sk). Some rights reserved."},{"id":"Freemap.sk-Cyclo","name":"Freemap.sk Cyclo","type":"tms","template":"http://t{switch:1,2,3,4}.freemap.sk/C/{zoom}/{x}/{y}.jpeg","scaleExtent":[8,16],"polygon":[[[19.83682,49.25529],[19.80075,49.42385],[19.60437,49.48058],[19.49179,49.63961],[19.21831,49.52604],[19.16778,49.42521],[19.00308,49.42236],[18.97611,49.5308],[18.54685,49.51425],[18.31432,49.33818],[18.15913,49.2961],[18.05564,49.11134],[17.56396,48.84938],[17.17929,48.88816],[17.058,48.81105],[16.90426,48.61947],[16.79685,48.38561],[17.06762,48.01116],[17.32787,47.97749],[17.51699,47.82535],[17.74776,47.73093],[18.29515,47.72075],[18.67959,47.75541],[18.89755,47.81203],[18.79463,47.88245],[18.84318,48.04046],[19.46212,48.05333],[19.62064,48.22938],[19.89585,48.09387],[20.33766,48.2643],[20.55395,48.52358],[20.82335,48.55714],[21.10271,48.47096],[21.45863,48.55513],[21.74536,48.31435],[22.15293,48.37179],[22.61255,49.08914],[22.09997,49.23814],[21.9686,49.36363],[21.6244,49.46989],[21.06873,49.46402],[20.94336,49.31088],[20.73052,49.44006],[20.22804,49.41714],[20.05234,49.23052],[19.83682,49.25529]]],"terms_text":"Copyright ©2007-2012 Freemap Slovakia (www.freemap.sk). Some rights reserved."},{"id":"Freemap.sk-Hiking","name":"Freemap.sk Hiking","type":"tms","template":"http://t{switch:1,2,3,4}.freemap.sk/T/{zoom}/{x}/{y}.jpeg","scaleExtent":[8,16],"polygon":[[[19.83682,49.25529],[19.80075,49.42385],[19.60437,49.48058],[19.49179,49.63961],[19.21831,49.52604],[19.16778,49.42521],[19.00308,49.42236],[18.97611,49.5308],[18.54685,49.51425],[18.31432,49.33818],[18.15913,49.2961],[18.05564,49.11134],[17.56396,48.84938],[17.17929,48.88816],[17.058,48.81105],[16.90426,48.61947],[16.79685,48.38561],[17.06762,48.01116],[17.32787,47.97749],[17.51699,47.82535],[17.74776,47.73093],[18.29515,47.72075],[18.67959,47.75541],[18.89755,47.81203],[18.79463,47.88245],[18.84318,48.04046],[19.46212,48.05333],[19.62064,48.22938],[19.89585,48.09387],[20.33766,48.2643],[20.55395,48.52358],[20.82335,48.55714],[21.10271,48.47096],[21.45863,48.55513],[21.74536,48.31435],[22.15293,48.37179],[22.61255,49.08914],[22.09997,49.23814],[21.9686,49.36363],[21.6244,49.46989],[21.06873,49.46402],[20.94336,49.31088],[20.73052,49.44006],[20.22804,49.41714],[20.05234,49.23052],[19.83682,49.25529]]],"terms_text":"Copyright ©2007-2012 Freemap Slovakia (www.freemap.sk). Some rights reserved."},{"id":"Freemap.sk-Ski","name":"Freemap.sk Ski","type":"tms","template":"http://t{switch:1,2,3,4}.freemap.sk/K/{zoom}/{x}/{y}.jpeg","scaleExtent":[8,16],"polygon":[[[19.83682,49.25529],[19.80075,49.42385],[19.60437,49.48058],[19.49179,49.63961],[19.21831,49.52604],[19.16778,49.42521],[19.00308,49.42236],[18.97611,49.5308],[18.54685,49.51425],[18.31432,49.33818],[18.15913,49.2961],[18.05564,49.11134],[17.56396,48.84938],[17.17929,48.88816],[17.058,48.81105],[16.90426,48.61947],[16.79685,48.38561],[17.06762,48.01116],[17.32787,47.97749],[17.51699,47.82535],[17.74776,47.73093],[18.29515,47.72075],[18.67959,47.75541],[18.89755,47.81203],[18.79463,47.88245],[18.84318,48.04046],[19.46212,48.05333],[19.62064,48.22938],[19.89585,48.09387],[20.33766,48.2643],[20.55395,48.52358],[20.82335,48.55714],[21.10271,48.47096],[21.45863,48.55513],[21.74536,48.31435],[22.15293,48.37179],[22.61255,49.08914],[22.09997,49.23814],[21.9686,49.36363],[21.6244,49.46989],[21.06873,49.46402],[20.94336,49.31088],[20.73052,49.44006],[20.22804,49.41714],[20.05234,49.23052],[19.83682,49.25529]]],"terms_text":"Copyright ©2007-2012 Freemap Slovakia (www.freemap.sk). Some rights reserved."},{"id":"Geodatastyrelsen_Denmark","name":"Geodatastyrelsen (Denmark)","type":"tms","template":"http://osmtools.septima.dk/mapproxy/tiles/1.0.0/kortforsyningen_ortoforaar/EPSG3857/{zoom}/{x}/{y}.jpeg","scaleExtent":[0,21],"polygon":[[[8.3743941,54.9551655],[8.3683809,55.4042149],[8.2103997,55.4039795],[8.2087314,55.4937345],[8.0502655,55.4924731],[8.0185123,56.7501399],[8.1819161,56.7509948],[8.1763274,57.0208898],[8.3413329,57.0219872],[8.3392467,57.1119574],[8.5054433,57.1123212],[8.5033923,57.2020499],[9.3316304,57.2027636],[9.3319079,57.2924835],[9.4978864,57.2919578],[9.4988593,57.3820608],[9.6649749,57.3811615],[9.6687295,57.5605591],[9.8351961,57.5596265],[9.8374896,57.6493322],[10.1725726,57.6462818],[10.1754245,57.7367768],[10.5118282,57.7330269],[10.5152095,57.8228945],[10.6834853,57.8207722],[10.6751613,57.6412021],[10.5077045,57.6433097],[10.5039992,57.5535088],[10.671038,57.5514113],[10.6507805,57.1024538],[10.4857673,57.1045138],[10.4786236,56.9249051],[10.3143981,56.9267573],[10.3112341,56.8369269],[10.4750295,56.83509],[10.4649016,56.5656681],[10.9524239,56.5589761],[10.9479249,56.4692243],[11.1099335,56.4664675],[11.1052639,56.376833],[10.9429901,56.3795284],[10.9341235,56.1994768],[10.7719685,56.2020244],[10.7694751,56.1120103],[10.6079695,56.1150259],[10.4466742,56.116717],[10.2865948,56.118675],[10.2831527,56.0281851],[10.4439274,56.0270388],[10.4417713,55.7579243],[10.4334961,55.6693533],[10.743814,55.6646861],[10.743814,55.5712253],[10.8969041,55.5712253],[10.9051793,55.3953852],[11.0613726,55.3812841],[11.0593038,55.1124061],[11.0458567,55.0318621],[11.2030844,55.0247474],[11.2030844,55.117139],[11.0593038,55.1124061],[11.0613726,55.3812841],[11.0789572,55.5712253],[10.8969041,55.5712253],[10.9258671,55.6670198],[10.743814,55.6646861],[10.7562267,55.7579243],[10.4417713,55.7579243],[10.4439274,56.0270388],[10.4466742,56.116717],[10.6079695,56.1150259],[10.6052053,56.0247462],[10.9258671,56.0201215],[10.9197132,55.9309388],[11.0802782,55.92792],[11.0858066,56.0178284],[11.7265047,56.005058],[11.7319981,56.0952142],[12.0540333,56.0871256],[12.0608477,56.1762576],[12.7023469,56.1594405],[12.6611131,55.7114318],[12.9792318,55.7014026],[12.9612912,55.5217294],[12.3268659,55.5412096],[12.3206071,55.4513655],[12.4778226,55.447067],[12.4702432,55.3570479],[12.6269738,55.3523837],[12.6200898,55.2632576],[12.4627339,55.26722],[12.4552949,55.1778223],[12.2987046,55.1822303],[12.2897344,55.0923641],[12.6048608,55.0832904],[12.5872011,54.9036285],[12.2766618,54.9119031],[12.2610181,54.7331602],[12.1070691,54.7378161],[12.0858621,54.4681655],[11.7794953,54.4753579],[11.7837381,54.5654783],[11.1658525,54.5782155],[11.1706443,54.6686508],[10.8617173,54.6733956],[10.8651245,54.7634667],[10.7713646,54.7643888],[10.7707276,54.7372807],[10.7551428,54.7375776],[10.7544039,54.7195666],[10.7389074,54.7197588],[10.7384368,54.7108482],[10.7074486,54.7113045],[10.7041094,54.6756741],[10.5510973,54.6781698],[10.5547184,54.7670245],[10.2423994,54.7705935],[10.2459845,54.8604673],[10.0902268,54.8622134],[10.0873731,54.7723851],[9.1555798,54.7769557],[9.1562752,54.8675369],[8.5321973,54.8663765],[8.531432,54.95516],[8.3743941,54.9551655]],[[11.4577738,56.819554],[11.7849181,56.8127385],[11.7716715,56.6332796],[11.4459621,56.6401087],[11.4577738,56.819554]],[[11.3274736,57.3612962],[11.3161808,57.1818004],[11.1508692,57.1847276],[11.1456628,57.094962],[10.8157703,57.1001693],[10.8290599,57.3695272],[11.3274736,57.3612962]],[[11.5843266,56.2777928],[11.5782882,56.1880397],[11.7392309,56.1845765],[11.7456428,56.2743186],[11.5843266,56.2777928]],[[14.6825922,55.3639405],[14.8395247,55.3565231],[14.8263755,55.2671261],[15.1393406,55.2517359],[15.1532015,55.3410836],[15.309925,55.3330556],[15.295719,55.2437356],[15.1393406,55.2517359],[15.1255631,55.1623802],[15.2815819,55.1544167],[15.2535578,54.9757646],[14.6317464,55.0062496],[14.6825922,55.3639405]]],"terms_url":"http://download.kortforsyningen.dk/content/vilkaar-og-betingelser","terms_text":"Geodatastyrelsen og Danske Kommuner","best":true},{"id":"Geoportal-PL-aerial_image","name":"Geoportal.gov.pl (Orthophotomap)","type":"tms","template":"http://wms.misek.pl/geoportal.orto/tms/{zoom}/{x}/{y}","scaleExtent":[6,24],"polygon":[[[15.9751041,54.3709213],[16.311164,54.5561775],[17.1391878,54.7845723],[18.3448458,54.9022727],[19.6613689,54.4737213],[20.2815206,54.4213456],[21.4663914,54.3406369],[22.7759855,54.3769755],[22.8625989,54.4233613],[23.2956657,54.2678633],[23.5347186,54.0955258],[23.5208604,53.9775182],[23.7183389,53.4629603],[23.9296755,53.1856735],[23.9296755,52.6887269],[23.732197,52.6067497],[23.5658994,52.5878101],[23.2090523,52.3302642],[23.1951942,52.2370089],[23.5035377,52.1860596],[23.6906226,52.0030113],[23.5970802,51.739903],[23.6629063,51.3888562],[23.9366046,50.9827781],[24.1687284,50.8604752],[24.0197534,50.8035823],[24.1098313,50.6610467],[24.0578633,50.4188439],[23.6178674,50.3083403],[22.6824431,49.5163532],[22.7378756,49.2094935],[22.9041733,49.0780441],[22.8625989,48.9940062],[22.6096878,49.0371785],[22.0761495,49.2004392],[21.8474902,49.3721872],[21.3763135,49.4488281],[21.1026153,49.3721872],[20.9120659,49.3022043],[20.6452967,49.3902311],[20.1845136,49.3315641],[20.1186875,49.2004392],[19.9419962,49.1302123],[19.765305,49.2117568],[19.7479823,49.3992506],[19.6024718,49.4150307],[19.5089294,49.5815389],[19.4292451,49.5905232],[19.2317666,49.4150307],[18.9961783,49.387976],[18.9338167,49.4916048],[18.8368097,49.4938552],[18.8021643,49.6623381],[18.6427958,49.7094091],[18.521537,49.8994693],[18.0815412,50.0109209],[17.8875272,49.9886512],[17.7385522,50.0687739],[17.6068999,50.1709584],[17.7454813,50.2153184],[17.710836,50.3017019],[17.4163505,50.2640668],[16.9486384,50.4453265],[16.8932058,50.4033889],[17.0006064,50.3105529],[17.017929,50.2241854],[16.8135215,50.186489],[16.6402948,50.0976742],[16.4324227,50.2862087],[16.1968344,50.4276731],[16.4220291,50.5885165],[16.3388803,50.6632429],[16.2280152,50.6368824],[16.0547884,50.6127057],[15.5732181,50.7641544],[15.2683391,50.8976368],[15.2440873,50.980597],[15.0292862,51.0133036],[15.0015699,50.8582883],[14.8110205,50.8735944],[14.956531,51.0721176],[15.0188926,51.2914636],[14.9392083,51.4601459],[14.7209426,51.5571799],[14.7521234,51.6260562],[14.5996839,51.8427626],[14.70362,52.0733396],[14.5581095,52.2497371],[14.5165351,52.425436],[14.6031485,52.5878101],[14.1146491,52.8208272],[14.152759,52.9733951],[14.3502374,53.0734212],[14.4229927,53.2665624],[14.1977979,53.8734759],[14.2220497,53.9958517],[15.9751041,54.3709213]]],"terms_text":"Copyright © Główny Urząd Geodezji i Kartografii.","best":true},{"id":"IBGE_DF_Addresses","name":"IBGE Distrito Federal","type":"tms","template":"https://api.mapbox.com/styles/v1/wille/cirnnxni1000jg8nfppc8g7pm/tiles/256/{zoom}/{x}/{y}?access_token=pk.eyJ1Ijoid2lsbGUiLCJhIjoicFNVWk5VWSJ9.hluCd0YGvYHNlFi_utWe2g","description":"Addresses data from IBGE","scaleExtent":[0,19],"polygon":[[[-48.2444,-16.0508],[-48.2444,-15.5005],[-47.5695,-15.5005],[-47.5695,-16.0508],[-48.2444,-16.0508]]],"overlay":true},{"id":"IBGE_Setores_Rurais","name":"IBGE Mapa de Setores Rurais","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/tmpsantos.i00mo1kj/{zoom}/{x}/{y}.png?access_token=pk.eyJ1Ijoib3BlbnN0cmVldG1hcCIsImEiOiJncjlmd0t3In0.DmZsIeOW-3x-C5eX-wAqTw","scaleExtent":[0,14],"polygon":[[[-29.3325,2.335959],[-28.72472,2.031551],[-27.76041,-8.937033],[-27.67249,-22.20839],[-51.11495,-35.46552],[-53.39394,-33.85064],[-53.62553,-33.72493],[-53.62503,-33.15428],[-53.24498,-32.73392],[-53.65747,-32.51873],[-53.8329,-32.16592],[-54.64174,-31.55507],[-55.29638,-31.3429],[-55.57371,-30.99691],[-56.06384,-31.16749],[-56.10468,-30.86436],[-56.86862,-30.20752],[-57.39671,-30.40464],[-57.74384,-30.22142],[-55.83724,-28.16598],[-54.86969,-27.44994],[-53.9016,-27.02998],[-53.74972,-26.25781],[-53.97158,-25.74513],[-54.44723,-25.79609],[-54.67802,-25.64668],[-54.36097,-24.35145],[-54.41679,-24.06527],[-54.64355,-23.94107],[-55.22163,-24.11355],[-55.49138,-24.02797],[-55.71734,-22.68488],[-55.90555,-22.39886],[-56.45255,-22.21731],[-56.8256,-22.4002],[-57.34109,-22.34351],[-58.08472,-22.13075],[-57.95766,-20.99818],[-58.26551,-20.24147],[-58.03577,-19.95871],[-58.23083,-19.75211],[-57.64739,-18.19828],[-57.89356,-17.57377],[-58.16997,-17.53519],[-58.48825,-17.21961],[-58.57691,-16.81466],[-58.45563,-16.42158],[-60.2541,-16.32571],[-60.33481,-15.51483],[-60.67423,-15.1122],[-60.34999,-14.99707],[-60.63603,-13.84119],[-61.07283,-13.62569],[-61.9025,-13.62647],[-62.21395,-13.25048],[-62.80185,-13.10905],[-63.17194,-12.76568],[-63.74229,-12.54071],[-64.32845,-12.59578],[-65.10261,-12.0682],[-65.45781,-11.27865],[-65.41641,-9.838943],[-66.52331,-9.985873],[-67.66452,-10.80093],[-67.99778,-10.75991],[-68.52286,-11.20807],[-69.88988,-11.02776],[-70.30957,-11.1699],[-70.71896,-11.02003],[-70.68128,-9.669083],[-71.27536,-10.08971],[-72.18053,-10.09967],[-72.41623,-9.587397],[-73.29207,-9.454149],[-73.0625,-9.017267],[-73.61432,-8.40982],[-74.09056,-7.527548],[-74.03652,-7.27885],[-73.84718,-7.238285],[-73.78618,-6.774872],[-73.22362,-6.430106],[-73.33719,-6.029736],[-72.93016,-5.038711],[-71.93973,-4.425027],[-70.96802,-4.248294],[-70.79598,-4.064931],[-70.02393,-4.167345],[-69.51025,-1.134089],[-69.70776,-0.567619],[-70.13645,-0.226161],[-70.14083,0.5844],[-69.26594,0.806502],[-69.34226,0.968924],[-69.92481,1.015705],[-69.92343,1.773851],[-68.38511,1.82943],[-68.24848,2.119808],[-67.94571,1.948424],[-67.37696,2.327468],[-67.05751,1.858336],[-67.00579,1.291603],[-66.79967,1.314684],[-66.28683,0.857709],[-65.67671,1.111146],[-65.42494,0.966549],[-65.15671,1.24203],[-64.27483,1.601591],[-64.0486,2.065137],[-63.47236,2.279358],[-64.13446,2.433909],[-64.10005,2.723778],[-64.32628,3.118275],[-64.28142,3.541983],[-64.88451,4.117671],[-64.88064,4.342461],[-64.13653,4.223152],[-63.95465,4.021316],[-63.17706,4.048301],[-62.96093,3.763658],[-62.82024,4.106019],[-62.49922,4.270815],[-61.91181,4.26284],[-61.35393,4.630097],[-61.04904,4.623115],[-60.70452,4.969851],[-60.78709,5.296764],[-60.22457,5.371207],[-59.89857,5.107541],[-59.97549,4.603025],[-59.59676,4.439875],[-59.41942,3.96994],[-59.71017,3.542008],[-59.88955,2.72301],[-59.63006,2.316332],[-59.63382,1.966581],[-59.18812,1.478079],[-58.80545,1.320732],[-58.35933,1.689932],[-57.6,1.803907],[-57.39854,2.065119],[-57.12392,2.128758],[-56.02925,1.949445],[-56.23884,2.263348],[-55.98195,2.628657],[-55.64816,2.519953],[-54.93958,2.682515],[-54.24988,2.25056],[-53.73937,2.473731],[-52.98578,2.280494],[-52.65712,2.564069],[-52.41739,3.22121],[-51.73983,4.119158],[-51.7246,4.556867],[-51.0112,5.522895],[-43.48209,5.335832],[-29.3325,2.335959]]]},{"id":"IBGE_Setores_Urbanos","name":"IBGE Mapa de Setores Urbanos","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/tmpsantos.hgda0m6h/{zoom}/{x}/{y}.png?access_token=pk.eyJ1Ijoib3BlbnN0cmVldG1hcCIsImEiOiJncjlmd0t3In0.DmZsIeOW-3x-C5eX-wAqTw","scaleExtent":[0,19],"polygon":[[[-29.3325,2.335959],[-28.72472,2.031551],[-27.76041,-8.937033],[-27.67249,-22.20839],[-51.11495,-35.46552],[-53.39394,-33.85064],[-53.62553,-33.72493],[-53.62503,-33.15428],[-53.24498,-32.73392],[-53.65747,-32.51873],[-53.8329,-32.16592],[-54.64174,-31.55507],[-55.29638,-31.3429],[-55.57371,-30.99691],[-56.06384,-31.16749],[-56.10468,-30.86436],[-56.86862,-30.20752],[-57.39671,-30.40464],[-57.74384,-30.22142],[-55.83724,-28.16598],[-54.86969,-27.44994],[-53.9016,-27.02998],[-53.74972,-26.25781],[-53.97158,-25.74513],[-54.44723,-25.79609],[-54.67802,-25.64668],[-54.36097,-24.35145],[-54.41679,-24.06527],[-54.64355,-23.94107],[-55.22163,-24.11355],[-55.49138,-24.02797],[-55.71734,-22.68488],[-55.90555,-22.39886],[-56.45255,-22.21731],[-56.8256,-22.4002],[-57.34109,-22.34351],[-58.08472,-22.13075],[-57.95766,-20.99818],[-58.26551,-20.24147],[-58.03577,-19.95871],[-58.23083,-19.75211],[-57.64739,-18.19828],[-57.89356,-17.57377],[-58.16997,-17.53519],[-58.48825,-17.21961],[-58.57691,-16.81466],[-58.45563,-16.42158],[-60.2541,-16.32571],[-60.33481,-15.51483],[-60.67423,-15.1122],[-60.34999,-14.99707],[-60.63603,-13.84119],[-61.07283,-13.62569],[-61.9025,-13.62647],[-62.21395,-13.25048],[-62.80185,-13.10905],[-63.17194,-12.76568],[-63.74229,-12.54071],[-64.32845,-12.59578],[-65.10261,-12.0682],[-65.45781,-11.27865],[-65.41641,-9.838943],[-66.52331,-9.985873],[-67.66452,-10.80093],[-67.99778,-10.75991],[-68.52286,-11.20807],[-69.88988,-11.02776],[-70.30957,-11.1699],[-70.71896,-11.02003],[-70.68128,-9.669083],[-71.27536,-10.08971],[-72.18053,-10.09967],[-72.41623,-9.587397],[-73.29207,-9.454149],[-73.0625,-9.017267],[-73.61432,-8.40982],[-74.09056,-7.527548],[-74.03652,-7.27885],[-73.84718,-7.238285],[-73.78618,-6.774872],[-73.22362,-6.430106],[-73.33719,-6.029736],[-72.93016,-5.038711],[-71.93973,-4.425027],[-70.96802,-4.248294],[-70.79598,-4.064931],[-70.02393,-4.167345],[-69.51025,-1.134089],[-69.70776,-0.567619],[-70.13645,-0.226161],[-70.14083,0.5844],[-69.26594,0.806502],[-69.34226,0.968924],[-69.92481,1.015705],[-69.92343,1.773851],[-68.38511,1.82943],[-68.24848,2.119808],[-67.94571,1.948424],[-67.37696,2.327468],[-67.05751,1.858336],[-67.00579,1.291603],[-66.79967,1.314684],[-66.28683,0.857709],[-65.67671,1.111146],[-65.42494,0.966549],[-65.15671,1.24203],[-64.27483,1.601591],[-64.0486,2.065137],[-63.47236,2.279358],[-64.13446,2.433909],[-64.10005,2.723778],[-64.32628,3.118275],[-64.28142,3.541983],[-64.88451,4.117671],[-64.88064,4.342461],[-64.13653,4.223152],[-63.95465,4.021316],[-63.17706,4.048301],[-62.96093,3.763658],[-62.82024,4.106019],[-62.49922,4.270815],[-61.91181,4.26284],[-61.35393,4.630097],[-61.04904,4.623115],[-60.70452,4.969851],[-60.78709,5.296764],[-60.22457,5.371207],[-59.89857,5.107541],[-59.97549,4.603025],[-59.59676,4.439875],[-59.41942,3.96994],[-59.71017,3.542008],[-59.88955,2.72301],[-59.63006,2.316332],[-59.63382,1.966581],[-59.18812,1.478079],[-58.80545,1.320732],[-58.35933,1.689932],[-57.6,1.803907],[-57.39854,2.065119],[-57.12392,2.128758],[-56.02925,1.949445],[-56.23884,2.263348],[-55.98195,2.628657],[-55.64816,2.519953],[-54.93958,2.682515],[-54.24988,2.25056],[-53.73937,2.473731],[-52.98578,2.280494],[-52.65712,2.564069],[-52.41739,3.22121],[-51.73983,4.119158],[-51.7246,4.556867],[-51.0112,5.522895],[-43.48209,5.335832],[-29.3325,2.335959]]]},{"id":"Haiti-Drone","name":"Imagerie Drone (Haiti)","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/iomhaiti/{zoom}/{x}/{y}","polygon":[[[-72.1547401,19.6878969],[-72.162234,19.689011],[-72.164995,19.6932445],[-72.1657838,19.6979977],[-72.161603,19.7035677],[-72.1487449,19.7028993],[-72.1477194,19.7026765],[-72.1485082,19.7001514],[-72.1436963,19.7011169],[-72.1410143,19.7000029],[-72.139476,19.6973664],[-72.1382533,19.6927617],[-72.1386872,19.6923161],[-72.1380561,19.6896423],[-72.1385294,19.6894938],[-72.1388055,19.6901251],[-72.1388844,19.6876741],[-72.1378195,19.6872656],[-72.13778,19.6850003],[-72.1369517,19.6855945],[-72.136794,19.6840719],[-72.135729,19.6835148],[-72.1355713,19.6740817],[-72.1366362,19.6708133],[-72.1487843,19.6710733],[-72.1534779,19.6763843],[-72.1530835,19.6769414],[-72.1533251,19.6769768],[-72.1532807,19.6796525],[-72.1523834,19.6797175],[-72.1522749,19.6803488],[-72.1519101,19.6803395],[-72.1518608,19.6805067],[-72.1528173,19.6806552],[-72.1522299,19.6833011],[-72.1507801,19.6831499],[-72.1504457,19.6847862],[-72.1508591,19.6843492],[-72.1530087,19.6849898],[-72.1546258,19.6854354],[-72.1543103,19.6870694],[-72.1547244,19.6868466],[-72.1548501,19.6877564],[-72.1545814,19.6877982],[-72.1547401,19.6878969]],[[-72.1310601,19.6718929],[-72.1259842,19.6772765],[-72.1255379,19.6776179],[-72.1216891,19.6776442],[-72.1149677,19.672602],[-72.1152745,19.6687152],[-72.1198205,19.6627535],[-72.1227768,19.6625696],[-72.1248965,19.662701],[-72.1285779,19.6645394],[-72.1308091,19.6661677],[-72.1316737,19.668794],[-72.1315621,19.671],[-72.1310601,19.6718929]],[[-71.845795,19.6709758],[-71.8429354,19.6759525],[-71.8410027,19.6759525],[-71.8380249,19.6755254],[-71.8378671,19.6745041],[-71.8390504,19.6743927],[-71.8390109,19.6741141],[-71.8398392,19.673947],[-71.8389123,19.6736127],[-71.8380249,19.67209],[-71.8380052,19.6726285],[-71.8376699,19.6727214],[-71.8376305,19.672545],[-71.8354414,19.6732135],[-71.835333,19.6729999],[-71.8331242,19.6734642],[-71.8326706,19.6716815],[-71.8321579,19.67209],[-71.8307183,19.6694902],[-71.8306009,19.6697594],[-71.8302174,19.6698907],[-71.8291833,19.6672095],[-71.8290749,19.6672095],[-71.8289122,19.6667916],[-71.8289516,19.6666199],[-71.8288333,19.6663506],[-71.8285572,19.6664759],[-71.8288678,19.6672466],[-71.8287593,19.6674138],[-71.8277979,19.6678177],[-71.8277112,19.6678586],[-71.8278263,19.6679637],[-71.8271831,19.6681212],[-71.8271761,19.6680917],[-71.8264405,19.6683921],[-71.8264074,19.6683231],[-71.8261954,19.6684253],[-71.8261806,19.6683556],[-71.8258946,19.6684206],[-71.8258897,19.6686574],[-71.8251551,19.6687549],[-71.8254509,19.6691588],[-71.8229332,19.6695739],[-71.822713,19.6696658],[-71.8227688,19.6697577],[-71.8201751,19.6709855],[-71.8198474,19.6704537],[-71.8197985,19.6706014],[-71.8194674,19.6707557],[-71.8182472,19.6713433],[-71.8181426,19.6711431],[-71.8175813,19.6714254],[-71.816959,19.6707672],[-71.8176388,19.6718965],[-71.8171403,19.6720376],[-71.8158225,19.6718045],[-71.8138354,19.6711874],[-71.8123259,19.6706982],[-71.8121759,19.6704258],[-71.8124304,19.6701467],[-71.8119184,19.6700141],[-71.8118765,19.6705828],[-71.811169,19.6703483],[-71.8095938,19.6698516],[-71.8077992,19.6692829],[-71.8056028,19.668612],[-71.8051443,19.6668942],[-71.8051196,19.6652322],[-71.8052315,19.661979],[-71.8065603,19.6523921],[-71.8073412,19.6482946],[-71.8099686,19.6468292],[-71.8147517,19.6454502],[-71.8147726,19.6455619],[-71.8150027,19.6455093],[-71.8149469,19.6453846],[-71.8159928,19.6450234],[-71.8158882,19.6448855],[-71.8165854,19.6446097],[-71.8190119,19.643802],[-71.8211524,19.643454],[-71.8221564,19.6433292],[-71.8269046,19.643211],[-71.8280481,19.6432241],[-71.8304466,19.6440778],[-71.8306419,19.6448592],[-71.8295263,19.6450365],[-71.8296064,19.6456111],[-71.8299411,19.6455651],[-71.8303699,19.6451744],[-71.830471,19.6453452],[-71.8308092,19.6451974],[-71.8310184,19.6451088],[-71.8312519,19.6458541],[-71.8311125,19.6458245],[-71.831367,19.6465862],[-71.8328939,19.646189],[-71.8344566,19.6457062],[-71.8344664,19.6463052],[-71.834215,19.6461938],[-71.8342002,19.6465513],[-71.8346702,19.6463],[-71.8349118,19.6463905],[-71.8347984,19.6462187],[-71.8354393,19.6458496],[-71.8355034,19.6458032],[-71.8364747,19.6461328],[-71.8376382,19.6472658],[-71.8379143,19.647888],[-71.8390483,19.6508039],[-71.8456942,19.6696203],[-71.845795,19.6709758]],[[-72.098878,18.54843],[-72.096993,18.5501994],[-72.0972888,18.5503209],[-72.0968451,18.5503489],[-72.0955632,18.551854],[-72.0956428,18.5526742],[-72.0959914,18.5533748],[-72.0962145,18.553203],[-72.0962842,18.5535665],[-72.0964446,18.5535533],[-72.0965352,18.5539764],[-72.0965056,18.554173],[-72.0966085,18.5541747],[-72.0965178,18.5542127],[-72.0968769,18.5546588],[-72.0979018,18.5552141],[-72.1006211,18.5555875],[-72.1014926,18.5556206],[-72.1024339,18.5555016],[-72.103417,18.5543515],[-72.1034798,18.5516215],[-72.1030789,18.5516149],[-72.1033752,18.5515224],[-72.1035042,18.5515224],[-72.1035239,18.5502417],[-72.1028701,18.5503062],[-72.1029015,18.55025],[-72.1028457,18.5501773],[-72.1035081,18.5500252],[-72.103491,18.5497396],[-72.1035181,18.5497361],[-72.1035398,18.5489039],[-72.1034317,18.5487056],[-72.102717,18.5481437],[-72.1025601,18.5481536],[-72.10229,18.5482751],[-72.1022891,18.5482569],[-72.1025201,18.5481396],[-72.1023388,18.5481321],[-72.0999082,18.5480901],[-72.09907,18.5483799],[-72.098878,18.54843]],[[-72.2542503,18.568262],[-72.2560252,18.5717765],[-72.2557886,18.5748049],[-72.2535009,18.5755526],[-72.2522782,18.5755526],[-72.2499906,18.5740945],[-72.2473874,18.5698323],[-72.2460069,18.566729],[-72.2458492,18.5629527],[-72.2479396,18.5625414],[-72.2501483,18.5628031],[-72.2519232,18.5650839],[-72.2542503,18.568262]],[[-72.303145,18.5332749],[-72.3031275,18.5331799],[-72.3048311,18.5311081],[-72.3097397,18.5311081],[-72.3164332,18.5324302],[-72.3234056,18.5366083],[-72.3261388,18.5387765],[-72.3261946,18.5426371],[-72.3170468,18.5540596],[-72.3130864,18.5540596],[-72.2987511,18.5453342],[-72.2988627,18.5407333],[-72.2962969,18.5404689],[-72.2954602,18.5395169],[-72.2961853,18.5338582],[-72.2971893,18.5332235],[-72.3007034,18.5332764],[-72.3022652,18.5342284],[-72.3028486,18.5335189],[-72.303104,18.5333361],[-72.303181,18.5334007],[-72.3035793,18.5335614],[-72.3030793,18.5346463],[-72.303715,18.5339873],[-72.3045286,18.5344052],[-72.3044015,18.5345097],[-72.3062747,18.5352571],[-72.3063107,18.5352741],[-72.3061219,18.5357628],[-72.3061219,18.5358196],[-72.30637,18.5358928],[-72.3062726,18.5354869],[-72.3066688,18.5350891],[-72.3061963,18.5349706],[-72.3058869,18.5349385],[-72.3055373,18.5346833],[-72.3054864,18.534613],[-72.3055585,18.5345065],[-72.3046749,18.5342293],[-72.3047617,18.5338817],[-72.3043252,18.5337511],[-72.3042595,18.5336346],[-72.303145,18.5332749]],[[-72.2981405,18.477502],[-72.2935652,18.4948587],[-72.2922242,18.4964297],[-72.2931708,18.4972526],[-72.2892266,18.5057058],[-72.2878067,18.5080996],[-72.2850458,18.5119893],[-72.2840203,18.5113161],[-72.2808649,18.515879],[-72.2773151,18.5175994],[-72.2723454,18.5175246],[-72.2662714,18.5144578],[-72.2665869,18.5066783],[-72.2692643,18.5046154],[-72.2661965,18.5029756],[-72.2688181,18.4965222],[-72.2691528,18.4959403],[-72.2702684,18.4961519],[-72.2702684,18.4955964],[-72.2690691,18.49557],[-72.2692922,18.4937714],[-72.2736988,18.4859951],[-72.2746749,18.4850429],[-72.2751769,18.483403],[-72.2765435,18.4813398],[-72.2773523,18.4814985],[-72.2783006,18.4809694],[-72.2778544,18.4807049],[-72.2771013,18.480123],[-72.2789978,18.4775836],[-72.279723,18.4772927],[-72.2806433,18.4776365],[-72.2813685,18.4771604],[-72.2808386,18.4769752],[-72.2812848,18.4758378],[-72.2823167,18.4751765],[-72.2851615,18.4750971],[-72.2849941,18.4763668],[-72.2854404,18.4769752],[-72.286277,18.4756262],[-72.2869325,18.4754675],[-72.2865978,18.4751897],[-72.2865978,18.4750046],[-72.2909765,18.4747268],[-72.2946579,18.4749384],[-72.2973911,18.476843],[-72.2981405,18.477502]],[[-72.3466657,18.5222375],[-72.346833,18.5244325],[-72.3475303,18.5277645],[-72.3455501,18.5291131],[-72.3403069,18.5292189],[-72.3383267,18.5280289],[-72.3369043,18.530118],[-72.3338086,18.5296684],[-72.3289279,18.5270769],[-72.328649,18.5253316],[-72.3292068,18.5232689],[-72.330406,18.5220524],[-72.3321631,18.5221847],[-72.3322467,18.5191963],[-72.3369183,18.5183633],[-72.3382012,18.5184691],[-72.3381454,18.5181782],[-72.3411993,18.5177947],[-72.3454943,18.5171997],[-72.3492595,18.517279],[-72.3504308,18.5188922],[-72.3503472,18.5206112],[-72.3496778,18.5220392],[-72.3466657,18.5222375]],[[-72.3303078,18.5486462],[-72.3429687,18.5508149],[-72.3433236,18.5530585],[-72.3413121,18.5614341],[-72.3390639,18.5613593],[-72.3384723,18.5638271],[-72.3375257,18.5654348],[-72.3348436,18.5650609],[-72.3311755,18.5638271],[-72.3312149,18.5616211],[-72.3232082,18.5606863],[-72.3212361,18.559602],[-72.3208023,18.5587046],[-72.3208811,18.557882],[-72.3259493,18.5580274],[-72.3266186,18.5581993],[-72.3259214,18.5577498],[-72.3250986,18.5573797],[-72.3233767,18.552263],[-72.3245994,18.5478507],[-72.3288986,18.5483742],[-72.329979,18.5489548],[-72.3303078,18.5486462]],[[-72.3231383,18.5269828],[-72.3223434,18.528067],[-72.3209629,18.5279745],[-72.3207816,18.5271282],[-72.3208513,18.5253697],[-72.3214649,18.5249598],[-72.3225666,18.5248937],[-72.3228454,18.52533],[-72.3232359,18.5264804],[-72.3231383,18.5269828]],[[-72.2160832,18.6457752],[-72.2159649,18.6553795],[-72.2030279,18.6558279],[-72.1947057,18.6553421],[-72.1922208,18.6545573],[-72.1920631,18.6521283],[-72.193483,18.6477559],[-72.201253,18.6385249],[-72.2069327,18.6388239],[-72.2120996,18.6424117],[-72.2118068,18.6430591],[-72.2121693,18.6426892],[-72.2127968,18.6427552],[-72.2134662,18.6431252],[-72.2135638,18.6437462],[-72.2154176,18.6443947],[-72.2158909,18.6450301],[-72.2160832,18.6457752]],[[-72.2867654,18.6482017],[-72.2900977,18.6527446],[-72.28981,18.6536532],[-72.2900738,18.6542664],[-72.290721,18.6537667],[-72.2910327,18.6544709],[-72.2912485,18.654221],[-72.29168,18.6558905],[-72.2912245,18.656606],[-72.2922673,18.65597],[-72.2926869,18.6567536],[-72.2930705,18.6567309],[-72.2941253,18.6581846],[-72.2960192,18.6608421],[-72.2959713,18.6619096],[-72.2932862,18.664567],[-72.2906731,18.6659979],[-72.2895943,18.6661342],[-72.2895943,18.6665657],[-72.2877004,18.6664749],[-72.2875805,18.6676559],[-72.2831214,18.6697227],[-72.2796453,18.6696546],[-72.2784311,18.6690787],[-72.2783972,18.6687736],[-72.277736,18.6691671],[-72.2774394,18.669143],[-72.2770071,18.6683159],[-72.2765575,18.6681125],[-72.2765385,18.6680583],[-72.2752319,18.6685239],[-72.2749292,18.6674649],[-72.2746416,18.6674309],[-72.2734668,18.6682145],[-72.2732271,18.6682712],[-72.2726757,18.6671583],[-72.2719147,18.6674288],[-72.2718808,18.6673405],[-72.2688149,18.6681868],[-72.2688269,18.6671761],[-72.2690786,18.6668241],[-72.2688149,18.66679],[-72.2681077,18.6670739],[-72.2676282,18.6673805],[-72.2675563,18.6666878],[-72.266861,18.666949],[-72.2655904,18.6673578],[-72.2654466,18.6670058],[-72.2647514,18.6674146],[-72.2629893,18.6681868],[-72.2628455,18.6681754],[-72.2626537,18.6676076],[-72.2623001,18.6677098],[-72.2624799,18.6679199],[-72.2624799,18.6682322],[-72.262306,18.6682606],[-72.2620963,18.6679654],[-72.2622761,18.6689193],[-72.2601484,18.6688966],[-72.2542749,18.6687944],[-72.2505388,18.6683476],[-72.2504371,18.669536],[-72.2477926,18.6698893],[-72.2415204,18.669793],[-72.2414187,18.6741933],[-72.2389167,18.6739759],[-72.2387249,18.6734649],[-72.2383653,18.6733059],[-72.2387009,18.6739532],[-72.2375502,18.6738964],[-72.2374183,18.6735103],[-72.237742,18.67334],[-72.2375142,18.6732605],[-72.236843,18.6734876],[-72.2364354,18.6724088],[-72.2355124,18.6726019],[-72.2354045,18.6724202],[-72.2353027,18.6729028],[-72.2345475,18.6726871],[-72.2343077,18.6724599],[-72.2342358,18.6734706],[-72.2334087,18.6734592],[-72.2332889,18.6733003],[-72.2327375,18.6732889],[-72.2327135,18.6735047],[-72.227703,18.6725281],[-72.2265283,18.6716537],[-72.226804,18.6715742],[-72.2274993,18.6715855],[-72.2274873,18.6714493],[-72.2272899,18.6714623],[-72.2272814,18.6712977],[-72.2272094,18.671358],[-72.2261785,18.6713693],[-72.2256032,18.670881],[-72.2255073,18.6694502],[-72.2261066,18.6696886],[-72.2261785,18.6695949],[-72.2259837,18.6695495],[-72.225777,18.6691379],[-72.2253335,18.6694643],[-72.2249739,18.66947],[-72.2245783,18.6678802],[-72.2235525,18.6677046],[-72.2235907,18.6675921],[-72.2224634,18.6676283],[-72.2223659,18.667022],[-72.2223277,18.6670943],[-72.2219209,18.667026],[-72.2208105,18.6669015],[-72.220809,18.6665325],[-72.2208705,18.6663593],[-72.2206023,18.6668107],[-72.2203895,18.6666361],[-72.2184341,18.6650535],[-72.21829,18.6640979],[-72.2183493,18.6608376],[-72.2187223,18.6606541],[-72.2186894,18.660603],[-72.2187253,18.6604525],[-72.2189771,18.6603247],[-72.2187823,18.6601998],[-72.2186984,18.6602367],[-72.2185815,18.6600352],[-72.2186085,18.6600039],[-72.2187823,18.6601345],[-72.218995,18.6600181],[-72.2189111,18.6599131],[-72.2189681,18.6597938],[-72.2183807,18.6595837],[-72.2184728,18.6539662],[-72.2201001,18.6511554],[-72.225796,18.6469472],[-72.2283048,18.6457265],[-72.2379335,18.645855],[-72.237764,18.6446985],[-72.2400355,18.6432529],[-72.2455958,18.6433493],[-72.2482742,18.6450358],[-72.2487488,18.6436705],[-72.2511067,18.6429775],[-72.2512385,18.6433409],[-72.2512625,18.6431592],[-72.2514843,18.6431365],[-72.2513284,18.6429718],[-72.2533602,18.6423471],[-72.253516,18.6426765],[-72.2539535,18.6425402],[-72.2541453,18.642932],[-72.2543851,18.6428696],[-72.2543791,18.6427503],[-72.2564168,18.6423244],[-72.2566925,18.6431365],[-72.2568783,18.6428582],[-72.2568184,18.6425288],[-72.258843,18.6420991],[-72.258885,18.6422467],[-72.2592626,18.6422297],[-72.2596461,18.6424057],[-72.2592206,18.6406907],[-72.2599545,18.6404815],[-72.2601156,18.6406341],[-72.2601156,18.6399393],[-72.2615268,18.6394669],[-72.2626056,18.6391034],[-72.2654465,18.6387286],[-72.2719433,18.6386832],[-72.272201,18.6388649],[-72.2730341,18.6394158],[-72.273166,18.6412558],[-72.2738732,18.6410286],[-72.2742208,18.6416079],[-72.2752187,18.6416987],[-72.2754524,18.6415738],[-72.2755513,18.6416874],[-72.2755394,18.6417527],[-72.2764713,18.6418634],[-72.276753,18.6418975],[-72.2762953,18.6426002],[-72.2774226,18.6429978],[-72.277982,18.6427247],[-72.2785796,18.6431303],[-72.2785669,18.6432307],[-72.2789017,18.6433471],[-72.279851,18.6439655],[-72.2858703,18.6469651],[-72.2867654,18.6482017]],[[-72.5557247,18.5305893],[-72.5555866,18.5367036],[-72.554995,18.537975],[-72.5488026,18.537919],[-72.5486646,18.5372832],[-72.548842,18.5306267],[-72.5493745,18.5301031],[-72.555133,18.5301218],[-72.5557247,18.5305893]],[[-72.6235278,18.5079877],[-72.6234441,18.5095217],[-72.6226074,18.5104341],[-72.6204878,18.511849],[-72.6183403,18.5107514],[-72.6162207,18.5083183],[-72.6162625,18.506467],[-72.618661,18.5044438],[-72.6204041,18.5044967],[-72.6228305,18.506996],[-72.6235278,18.5079877]]]},{"id":"osmim-imagicode-S2A_R119_N09_20160327T050917","name":"imagico.de OSM images for mapping: Adams Bridge","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R119_N09_20160327T050917&z={zoom}&x={x}&y={-y}","description":"Supplementing incomplete coverage in other sources (true color)","scaleExtent":[0,14],"polygon":[[[79.01779174804685,8.827572266651268],[79.01401519775389,9.64678471986339],[80.17642021179198,9.650423231331946],[80.17727851867674,8.831304063493132],[79.01779174804685,8.827572266651268]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC80700162014211LGN00","name":"imagico.de OSM images for mapping: Alaska Range","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC80700162014211LGN00&z={zoom}&x={x}&y={-y}","description":"Recent summer image of the Alaska Range for mapping natural features (true color)","scaleExtent":[0,12],"polygon":[[[-152.70872943147867,62.30357443926811],[-152.70838610872474,62.58153176976553],[-152.00835101350992,63.54645538851267],[-148.99432055696695,63.53329945446586],[-148.99432055696695,62.30357443926811],[-152.70872943147867,62.30357443926811]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81190582014075LGN00","name":"imagico.de OSM images for mapping: Bakun Reservoir","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81190582014075LGN00&z={zoom}&x={x}&y={-y}","description":"Missing in older pre-2011 images (true color)","scaleExtent":[0,13],"polygon":[[[114.35999506049737,2.028456548619032],[113.5344754987298,2.030000532161949],[113.53619211249934,3.070767124420059],[114.76511591010677,3.067510236472651],[114.76254098945248,2.088156161702156],[114.35999506049737,2.028456548619032]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81250592016107LGN00","name":"imagico.de OSM images for mapping: Batam","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81250592016107LGN00&z={zoom}&x={x}&y={-y}","description":"Missing Islands in OSM (true color)","scaleExtent":[0,13],"polygon":[[[104.00154570197358,-0.000078769115171],[104.00137404059662,1.45099139170518],[104.91014937018647,1.451162998032411],[104.91014937018647,-0.000078769115171],[104.00154570197358,-0.000078769115171]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81800982013291LGN00","name":"imagico.de OSM images for mapping: Bouvet Island","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81800982013291LGN00&z={zoom}&x={x}&y={-y}","description":"For more accurate coastline and glacier mapping (true color)","scaleExtent":[0,13],"polygon":[[[3.246529403113632,-54.47046993167111],[3.246529403113632,-54.375391687979096],[3.463852706336288,-54.375391687979096],[3.463852706336288,-54.47046993167111],[3.246529403113632,-54.47046993167111]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping","best":true},{"id":"osmim-imagicode-S2A_R065_N47_20160929T102022","name":"imagico.de OSM images for mapping: Cental Alps in late September 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R065_N47_20160929T102022&z={zoom}&x={x}&y={-y}","description":"Up-to-date image for glacier mapping - beware of some fresh snow at higher altitudes (true color)","scaleExtent":[0,13],"polygon":[[[10.559062957763668,45.95484945195885],[7.473964691162107,45.95532682303484],[7.555847167968747,46.27080015119853],[8.05469512939453,47.66469371011084],[11.752452850341793,47.664809318453564],[11.752452850341793,46.813336457338615],[11.38423919677734,45.955088138010865],[10.559062957763668,45.95484945195885]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC82050982015344LGN00","name":"imagico.de OSM images for mapping: Clerke Rocks","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC82050982015344LGN00&z={zoom}&x={x}&y={-y}","description":"Missing in other image sources (true color)","scaleExtent":[0,13],"polygon":[[[-34.17701089820909,-55.29692751183208],[-35.19599283180284,-55.282851769908206],[-35.16663873634385,-54.7209735214882],[-34.12516916236925,-54.73465315976587],[-34.14010370216417,-55.29692751183208],[-34.17701089820909,-55.29692751183208]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-EO1A0040712016264110KF","name":"imagico.de OSM images for mapping: Coropuna","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=EO1A0040712016264110KF&z={zoom}&x={x}&y={-y}","description":"Up-to-date image for glacier mapping (true color)","scaleExtent":[0,14],"polygon":[[[-72.7594470977783,-15.68684010813036],[-72.7594470977783,-15.49570157136026],[-72.74434089660643,-15.426295586903299],[-72.41286277770995,-15.426295586903299],[-72.41286277770995,-15.652957427428944],[-72.42410659790038,-15.686674840407827],[-72.7594470977783,-15.68684010813036]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R022_N06_20151221T103009","name":"imagico.de OSM images for mapping: Cotonou","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R022_N06_20151221T103009&z={zoom}&x={x}&y={-y}","description":"Patchy and partly cloudy coverage in usual sources (true color)","scaleExtent":[0,14],"polygon":[[[1.839749701876779,6.257803795151386],[1.839749701876779,7.114271792431897],[2.549397834200998,7.114271792431897],[2.549397834200998,6.489052510574106],[2.497813590426584,6.258059752887941],[1.839749701876779,6.257803795151386]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R040_N01_20160311T164128","name":"imagico.de OSM images for mapping: Darwin and Wolf islands, Galapagos","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R040_N01_20160311T164128&z={zoom}&x={x}&y={-y}","description":"Recent image, only old and poor images in other sources currently (true color)","scaleExtent":[0,14],"polygon":[[[-92.05216379429558,1.321295617717369],[-92.05216379429558,1.72181118585353],[-91.74849481846549,1.72181118585353],[-91.74849481846549,1.321295617717369],[-92.05216379429558,1.321295617717369]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC80360072014245LGN00","name":"imagico.de OSM images for mapping: Eastern Devon Island coast","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC80360072014245LGN00&z={zoom}&x={x}&y={-y}","description":"Coastline mostly mapped meanwhile (false color IR)","scaleExtent":[0,11],"polygon":[[[-84.34798733886554,74.38945823827667],[-84.34798733886554,75.89030323920836],[-79.14870755370929,75.89030323920836],[-79.14870755370929,74.38945823827667],[-84.34798733886554,74.38945823827667]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC82160152013239LGN00","name":"imagico.de OSM images for mapping: Eastern Iceland","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC82160152013239LGN00&z={zoom}&x={x}&y={-y}","description":"Missing islets and inaccurate coast (true color)","scaleExtent":[0,12],"polygon":[[[-13.047005598725303,64.2110895294821],[-15.164963667572959,64.22408122727819],[-15.168053572358117,64.81572800422087],[-13.043572371186242,64.80359943673454],[-13.047005598725303,64.2110895294821]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-AST_L1T_00302052007154424_20150518041444_91492","name":"imagico.de OSM images for mapping: El Altar","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=AST_L1T_00302052007154424_20150518041444_91492&z={zoom}&x={x}&y={-y}","description":"2007 ASTER image offering better glacier coverage than common sources (true color with estimated blue)","scaleExtent":[0,14],"polygon":[[[-78.531997745432,-1.805085317123331],[-78.531997745432,-1.608105565001241],[-78.33561713019762,-1.608105565001241],[-78.33561713019762,-1.805085317123331],[-78.531997745432,-1.805085317123331]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R009_S61_20160109","name":"imagico.de OSM images for mapping: Elephant Island/Clarence Island","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R009_S61_20160109&z={zoom}&x={x}&y={-y}","description":"Fairly clear up-to-date image for updating glacier edges (true color)","scaleExtent":[0,13],"polygon":[[[-56.13476090727487,-61.63471600102006],[-56.13476090727487,-61.199363166283845],[-55.83263688383738,-60.84015069906498],[-53.72343354521433,-60.83981613078141],[-53.72343354521433,-61.63471600102006],[-56.13476090727487,-61.63471600102006]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-enderby","name":"imagico.de OSM images for mapping: Enderby Land and Kemp Coast","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=enderby&z={zoom}&x={x}&y={-y}","description":"Sentinel-2 images of Enderby Land and Kemp Coast (true color)","scaleExtent":[0,13],"polygon":[[[45.4547,-68.5091],[45.4547,-67.5724],[49.7155,-65.7176],[59.2693,-65.7176],[67.3735,-67.3449],[67.3735,-68.2581],[67.088,-68.5091],[45.4547,-68.5091]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC82100502015347LGN00","name":"imagico.de OSM images for mapping: Fogo, Cape Verde","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC82100502015347LGN00&z={zoom}&x={x}&y={-y}","description":"Image from after the 2014/2015 eruption (true color)","scaleExtent":[0,14],"polygon":[[[-24.758781955967567,14.748140156641956],[-24.758781955967567,15.092493544965103],[-24.267057941685337,15.092493544965103],[-24.267057941685337,14.748140156641956],[-24.758781955967567,14.748140156641956]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-greenland","name":"imagico.de OSM images for mapping: Greenland mosaic","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=greenland&z={zoom}&x={x}&y={-y}","description":"Landsat mosaic of Greenland (true color)","scaleExtent":[0,12],"polygon":[[[-43.9774,59.7171],[-44.545,59.7302],[-44.9203,59.7672],[-45.3587,59.8218],[-45.763,59.8848],[-46.0859,59.9827],[-46.3381,60.119],[-46.577,60.2652],[-46.8114,60.4418],[-47.2635,60.5314],[-47.6937,60.5549],[-48.1457,60.6192],[-48.5771,60.7015],[-48.8689,60.8506],[-49.0578,61.0555],[-49.396,61.2957],[-49.7601,61.4934],[-50.2064,61.7324],[-50.4699,61.9539],[-50.8647,62.1596],[-51.0631,62.3869],[-51.2121,62.6001],[-51.3005,62.8389],[-51.4238,62.9979],[-51.6767,63.1944],[-51.9465,63.4079],[-52.0253,63.6377],[-52.2255,63.8378],[-52.3658,64.0705],[-52.4829,64.3792],[-52.4988,64.6788],[-52.789,64.9063],[-53.2046,65.1321],[-53.6649,65.4753],[-53.9977,65.8019],[-54.1348,66.1568],[-54.1441,66.5235],[-54.2285,66.8319],[-54.4519,67.303],[-54.5141,67.7648],[-54.604,68.2021],[-54.568,68.5698],[-54.598,68.8347],[-54.7606,69.1207],[-55.0028,69.4125],[-55.2735,69.6187],[-55.3808,69.8283],[-55.3945,70.0838],[-55.3094,70.2573],[-55.4307,70.479],[-55.5501,70.6707],[-55.7654,70.861],[-56.2489,71.2343],[-56.5018,71.5429],[-56.5867,71.9015],[-56.5189,72.2355],[-56.5085,72.5258],[-56.8923,72.8144],[-57.4027,73.1054],[-57.8066,73.4566],[-58.1461,73.7696],[-58.3554,74.0972],[-58.5125,74.3783],[-58.7336,74.6328],[-59.3551,74.8869],[-60.1412,75.102],[-61.0067,75.2763],[-61.911,75.3886],[-62.4706,75.5595],[-62.9776,75.7454],[-64.1463,75.779],[-65.4481,75.7235],[-66.7068,75.6792],[-67.8379,75.6525],[-69.0456,75.6195],[-70.055,75.5344],[-71.0898,75.4705],[-72.1119,75.4476],[-74.2311,76.4102],[-74.5601,76.5328],[-74.5601,82.6959],[-14.4462,82.6959],[-14.3994,82.5997],[-13.5339,82.4379],[-12.0312,82.3426],[-10.7796,82.3196],[-10.7796,80.1902],[-11.2123,80.069],[-11.136,79.8103],[-10.7796,79.5176],[-10.7796,79.0441],[-11.2626,78.7128],[-12.2579,78.3558],[-13.2398,78.1272],[-13.7649,77.9279],[-14.1169,77.6779],[-14.7129,77.5278],[-15.5507,77.3655],[-16.0936,77.0771],[-16.0586,76.5548],[-15.838,75.9611],[-15.6879,75.4726],[-16.253,75.058],[-17.0427,74.6425],[-18.3155,74.2702],[-19.4463,73.9378],[-19.8329,73.632],[-20.2938,73.3524],[-20.7831,73.0446],[-21.01,72.6766],[-20.8774,72.2926],[-20.7672,71.8726],[-20.7765,71.4304],[-20.9411,70.9802],[-21.219,70.6126],[-21.5326,70.3001],[-21.8039,70.0911],[-22.166,69.8947],[-22.4831,69.7539],[-22.9027,69.6585],[-23.3545,69.544],[-23.9177,69.4036],[-24.1794,69.3088],[-24.6745,69.1084],[-25.1222,68.9555],[-25.6659,68.7995],[-26.0994,68.583],[-26.6316,68.4043],[-27.7638,68.2813],[-28.4575,68.0023],[-29.353,67.8135],[-30.6456,67.4911],[-31.7673,67.0005],[-32.9783,66.2596],[-33.9313,66.0156],[-34.8956,65.7403],[-35.5914,65.5208],[-36.1483,65.372],[-36.7532,65.2559],[-37.1858,65.1349],[-37.6032,64.9727],[-38.0624,64.4901],[-38.5304,64.1244],[-39.0545,63.7213],[-39.3131,63.4405],[-39.5739,62.7506],[-39.9532,62.2739],[-40.2757,61.8547],[-40.714,61.3365],[-41.2091,60.8495],[-41.821,60.5526],[-42.4368,60.3264],[-42.8643,60.0299],[-43.1131,59.9147],[-43.3282,59.83],[-43.5459,59.7695],[-43.797,59.7284],[-43.9774,59.7171]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R047_S54_20160411T044330","name":"imagico.de OSM images for mapping: Heard Island coast","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R047_S54_20160411T044330&z={zoom}&x={x}&y={-y}","description":"Recent image of Heard island with interior mostly cloud covered but mostly well visible coast (true color)","scaleExtent":[0,13],"polygon":[[[73.06896521028185,-53.270590689700434],[73.06896521028185,-52.875489636268725],[73.67338491853381,-52.87673289134188],[74.08863378938341,-52.94950473139763],[74.08863378938341,-53.270590689700434],[73.06896521028185,-53.270590689700434]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC82280982013259LGN00","name":"imagico.de OSM images for mapping: Isla Londonderry","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC82280982013259LGN00&z={zoom}&x={x}&y={-y}","description":"A lot of very coarse coastlines could be improved here, much snow cover though so no use for glacier mapping (false color IR)","scaleExtent":[0,12],"polygon":[[[-69.85679747431641,-55.55949231551995],[-72.26520659296875,-55.149427383391455],[-72.26520659296875,-54.51089432315929],[-72.08530546992188,-54.17909103768387],[-69.49115874140625,-54.17889010631196],[-69.49150206416016,-55.28378528847367],[-69.62230803339844,-55.55910398108892],[-69.85679747431641,-55.55949231551995]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R021_N44_20160807T083013","name":"imagico.de OSM images for mapping: Kerch Strait","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R021_N44_20160807T083013&z={zoom}&x={x}&y={-y}","description":"State of bridge construction in August 2016 (true color)","scaleExtent":[0,14],"polygon":[[[35.932588577270494,44.96236872935039],[35.932588577270494,45.559256426515695],[37.369909286499016,45.559256426515695],[37.369909286499016,44.96236872935039],[35.932588577270494,44.96236872935039]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-ls_polar2","name":"imagico.de OSM images for mapping: Landsat off-nadir July 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=ls_polar2&z={zoom}&x={x}&y={-y}","description":"Latest images north of the regular Landsat limit (true color)","scaleExtent":[0,10],"polygon":[[[-79.05174500251786,81.91484289044183],[-79.05174500251786,83.43338556749623],[-73.60389956385866,83.80224987787145],[-26.424486898081835,83.80224987787145],[-21.492998879371186,83.50352415480617],[-16.888354121159868,83.15094632775453],[-16.888354121159868,81.91484289044183],[-79.05174500251786,81.91484289044183]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-AST_L1T_00311162013112731_20150618142416_109190","name":"imagico.de OSM images for mapping: Leskov Island ASTER","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=AST_L1T_00311162013112731_20150618142416_109190&z={zoom}&x={x}&y={-y}","description":"Missing in other image sources (true color with estimated blue)","scaleExtent":[0,13],"polygon":[[[-28.210747081406492,-56.72108048139938],[-28.210747081406492,-56.624975043089115],[-27.96956284678735,-56.624975043089115],[-27.96956284678735,-56.72108048139938],[-28.210747081406492,-56.72108048139938]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81991002015286LGN00","name":"imagico.de OSM images for mapping: Leskov Island Landsat","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81991002015286LGN00&z={zoom}&x={x}&y={-y}","description":"Missing in other image sources (true color)","scaleExtent":[0,13],"polygon":[[[-27.992928409215843,-56.73479060902333],[-28.227761172887714,-56.732624892496354],[-28.2241562839717,-56.600752537318456],[-27.969754123327167,-56.60283135691063],[-27.97318735086623,-56.73479060902333],[-27.992928409215843,-56.73479060902333]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-ls_polar","name":"imagico.de OSM images for mapping: May 2013 off-nadir Landsat","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=ls_polar&z={zoom}&x={x}&y={-y}","description":"First available image north of the regular Landsat limit, mostly with seasonal snow cover so difficult to interpret (true color)","scaleExtent":[0,10],"polygon":[[[-85.76109385682587,81.39333391115835],[-89.83015512094161,82.14951616258433],[-89.83152841195212,82.24404688557661],[-84.99342418195555,82.73098798225534],[-79.95207288240479,83.13107965605444],[-74.55641250214465,83.46266728201661],[-69.35850602739671,83.70450775086888],[-28.207840897721187,83.70450775086888],[-23.06623935440381,83.46532469372944],[-17.96583654140148,83.15518123848051],[-17.96720983241198,82.72386035102944],[-22.781968115230015,81.44190408358111],[-85.76109385682587,81.39333391115835]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R092_S02_20160613T075613","name":"imagico.de OSM images for mapping: Mount Kenya 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R092_S02_20160613T075613&z={zoom}&x={x}&y={-y}","description":"Up-to-date image for glacier mapping (true color)","scaleExtent":[0,14],"polygon":[[[37.20665931701659,-0.266846645776291],[37.20665931701659,-0.011930465612033],[37.5655174255371,-0.011930465612033],[37.5655174255371,-0.266846645776291],[37.20665931701659,-0.266846645776291]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R092_S05_20160802T075556","name":"imagico.de OSM images for mapping: Mount Kilimanjaro 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R092_S05_20160802T075556&z={zoom}&x={x}&y={-y}","description":"Up-to-date image for glacier mapping (true color)","scaleExtent":[0,14],"polygon":[[[37.24768638610839,-3.229213650135676],[37.24768638610839,-2.968155849006605],[37.61581420898436,-2.968155849006605],[37.61581420898436,-3.229213650135676],[37.24768638610839,-3.229213650135676]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC80940622015159LGN00","name":"imagico.de OSM images for mapping: New Ireland","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC80940622015159LGN00&z={zoom}&x={x}&y={-y}","description":"Many missing islands in OSM (mostly mapped meanwhile) (true color)","scaleExtent":[0,14],"polygon":[[[150.38853376619625,-2.800534349432724],[150.38853376619625,-2.383396178206425],[150.83348005525875,-2.383396178206425],[150.83348005525875,-2.800534349432724],[150.38853376619625,-2.800534349432724]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-northsea_s2_2016","name":"imagico.de OSM images for mapping: North Sea Coast 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=northsea_s2_2016&z={zoom}&x={x}&y={-y}","description":"Up-to-date low tide imagery of the coast for updating mapping of tidalflats and shoals (true color)","scaleExtent":[0,13],"polygon":[[[5.1562,52.8755],[5.1615,53.0325],[6.4155,55.7379],[9.8813,55.7459],[9.8813,53.2428],[9.6846,52.8877],[5.1562,52.8755]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-ural_s2_2016","name":"imagico.de OSM images for mapping: Northern and Polar Ural mountains August 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=ural_s2_2016&z={zoom}&x={x}&y={-y}","description":"Up-to-date late summer imagery with few clouds - caution: not all visible snow is glaciers (true color)","scaleExtent":[0,13],"polygon":[[[59.198977223476454,64.8920468958533],[59.198977223476454,66.91656046303187],[60.733286610683486,68.44289182710118],[67.7329509173241,68.44327026354412],[67.7329509173241,67.748828729217],[64.21646761043934,64.9195663902952],[59.198977223476454,64.8920468958533]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-nellesmere_ast","name":"imagico.de OSM images for mapping: Northern Ellesmere Island","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=nellesmere_ast&z={zoom}&x={x}&y={-y}","description":"Assembled from July 2012 ASTER imagery (true color with estimated blue)","scaleExtent":[0,10],"polygon":[[[-81.62923243782096,82.45969864814401],[-83.03136255954291,82.47985512217643],[-83.03136255954291,83.05876272004272],[-72.80309111332822,83.09567468670448],[-65.65785798568925,83.03232446260982],[-65.8116665788654,82.45969864814401],[-81.62923243782096,82.45969864814401]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-nellesmere_ast_2016","name":"imagico.de OSM images for mapping: Northern Ellesmere Island July 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=nellesmere_ast_2016&z={zoom}&x={x}&y={-y}","description":"Assembled from July 2016 ASTER imagery (true color with estimated blue)","scaleExtent":[0,10],"polygon":[[[-78.89729497133754,82.17577067162792],[-82.64500613899595,82.19425721404356],[-82.64500613899595,83.08067098163464],[-66.58986093522367,83.08497116318647],[-63.78010752773773,82.98907949583335],[-63.78010752773773,82.72198178031782],[-65.0092029821365,82.17577067162792],[-78.89729497133754,82.17577067162792]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81960222015233LGN00vis","name":"imagico.de OSM images for mapping: Northern German west coast tidalflats","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81960222015233LGN00vis&z={zoom}&x={x}&y={-y}","description":"Up-to-date low tide imagery of the coast for updating mapping of tidalflats and shoals (true color)","scaleExtent":[0,12],"polygon":[[[7.63567991501593,53.28027339774928],[7.63567991501593,53.66770140276793],[8.49433012253546,55.502457780526],[9.207754805152648,55.48106268908912],[9.207754805152648,53.28027339774928],[7.63567991501593,53.28027339774928]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81960222015233LGN00ir","name":"imagico.de OSM images for mapping: Northern German west coast tidalflats (infrared)","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81960222015233LGN00ir&z={zoom}&x={x}&y={-y}","description":"Up-to-date low tide imagery of the coast for updating mapping of tidalflats and shoals (false color IR)","scaleExtent":[0,12],"polygon":[[[7.63567991501593,53.28027339774928],[7.63567991501593,53.66810821588294],[8.49433012253546,55.502457780526],[9.207754805152648,55.48106268908912],[9.207754805152648,53.28027339774928],[7.63567991501593,53.28027339774928]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-ngreenland_ast","name":"imagico.de OSM images for mapping: Northern Greenland ASTER","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=ngreenland_ast&z={zoom}&x={x}&y={-y}","description":"Assembled from mostly 2012 ASTER imagery, some 2005 images mainly in the northeast (true color with estimated blue)","scaleExtent":[0,10],"polygon":[[[-52.49221819430999,82.48971755550389],[-52.49221819430999,82.94294978186194],[-49.28695697579964,83.47311821807558],[-44.52850362441216,83.7321400994933],[-29.525299334683975,83.7321400994933],[-25.263977329098022,83.58271128961059],[-21.183929736898254,83.39775984253468],[-21.183929736898254,82.74312310369845],[-23.404541300879075,82.48971755550389],[-52.49221819430999,82.48971755550389]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-EO1A1350972013086110KF","name":"imagico.de OSM images for mapping: Northwest Heard Island","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=EO1A1350972013086110KF&z={zoom}&x={x}&y={-y}","description":"Glaciers of Northwest Heard Island (mapped meanwhile) (false color IR)","scaleExtent":[0,13],"polygon":[[[73.22790413350113,-53.20333324999222],[73.22790413350113,-53.01072925838941],[73.2594898268605,-52.94943913810479],[73.78992348164566,-52.94943913810479],[73.78992348164566,-53.06048282358537],[73.71782570332533,-53.20333324999222],[73.22790413350113,-53.20333324999222]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R111_N09_20160604T154554","name":"imagico.de OSM images for mapping: Panama Canal","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R111_N09_20160604T154554&z={zoom}&x={x}&y={-y}","description":"Images of the new locks (but partly cloudy) (true color)","scaleExtent":[0,14],"polygon":[[[-80.01653561766223,8.848981570244637],[-80.01653561766223,9.41480707574399],[-79.46859250242785,9.41480707574399],[-79.46859250242785,8.848981570244637],[-80.01653561766223,8.848981570244637]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-EO1A0120532016364110KF","name":"imagico.de OSM images for mapping: Panama Canal - Pacific side","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=EO1A0120532016364110KF&z={zoom}&x={x}&y={-y}","description":"New locks with less clouds than in the Sentinel-2 image - make sure to check image alignment (true color)","scaleExtent":[0,14],"polygon":[[[-79.62538719177245,8.770827350748924],[-79.68684196472167,8.821974500616129],[-79.6866703033447,8.93705081902936],[-79.65362548828124,9.0929436313527],[-79.268159866333,9.0929436313527],[-79.32832717895505,8.770827350748924],[-79.62538719177245,8.770827350748924]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R078_N68_20160930T081002","name":"imagico.de OSM images for mapping: Pechora Sea Coast","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R078_N68_20160930T081002&z={zoom}&x={x}&y={-y}","description":"Sentinel-2 image of the Pechora Sea coast in autumn 2016 (true color)","scaleExtent":[0,13],"polygon":[[[53.1802,67.5344],[53.1821,68.414],[54.2107,69.3367],[55.3584,70.2786],[59.004,70.2786],[60.6947,69.977],[61.9837,69.7161],[61.9823,68.9395],[59.9153,67.5344],[53.1802,67.5344]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81511242016033LGN00","name":"imagico.de OSM images for mapping: Pensacola Mountains","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81511242016033LGN00&z={zoom}&x={x}&y={-y}","description":"Outside regular Landsat coverage and therefore not in LIMA and Bing/Mapbox (true color)","scaleExtent":[0,10],"polygon":[[[-53.20921946177197,-84.12524693598144],[-60.615377881406225,-83.78609327915953],[-60.615377881406225,-82.29968785439104],[-48.72405102147429,-82.29987186164387],[-44.52178052933989,-82.43683433550413],[-44.51354078327688,-84.12524693598144],[-53.20921946177197,-84.12524693598144]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R136_N41_20150831T093006","name":"imagico.de OSM images for mapping: Prokletije Mountains","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R136_N41_20150831T093006&z={zoom}&x={x}&y={-y}","description":"Late summer imagery where usual sources are severely limited by clouds and snow (true color)","scaleExtent":[0,14],"polygon":[[[19.112325688609005,42.1531576323006],[19.08425905347717,43.08073531915633],[20.63298799634826,43.09602978090892],[20.637880345591427,42.167791043253985],[19.112325688609005,42.1531576323006]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-DMS_1142622_03746_20110415_17533956","name":"imagico.de OSM images for mapping: Qasigiannguit","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=DMS_1142622_03746_20110415_17533956&z={zoom}&x={x}&y={-y}","description":"Icebridge DMS image of the settlement - alignment might be poor","scaleExtent":[0,15],"polygon":[[[-51.238571767352376,68.79971882076842],[-51.243335370562825,68.85302612951142],[-51.151668195269856,68.85302612951142],[-51.14038145973519,68.80116208175376],[-51.238571767352376,68.79971882076842]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81510432015030LGN00","name":"imagico.de OSM images for mapping: Rann of Kutch","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81510432015030LGN00&z={zoom}&x={x}&y={-y}","description":"Land/water distinction difficult to properly map based on Bing/Mapbox images (false color IR)","scaleExtent":[0,12],"polygon":[[[67.96839858817646,22.36264542957619],[67.86231185721942,22.38391650007107],[67.86231185721942,24.886930816927297],[71.48986007499286,24.886930816927297],[71.48986007499286,22.36264542957619],[67.96839858817646,22.36264542957619]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R093_N41_20150828T092005","name":"imagico.de OSM images for mapping: Rila and Pirin Mountains","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R093_N41_20150828T092005&z={zoom}&x={x}&y={-y}","description":"Late summer imagery where usual sources are severely limited by clouds and snow (true color)","scaleExtent":[0,14],"polygon":[[[23.808114560320394,41.584878805945024],[22.992379697039144,41.6019534981177],[23.011863263323328,42.29983747360261],[23.99402383156063,42.283393175568236],[23.965613873674886,41.584878805945024],[23.808114560320394,41.584878805945024]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81730602015040LGN00","name":"imagico.de OSM images for mapping: Rwenzori Mountains","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81730602015040LGN00&z={zoom}&x={x}&y={-y}","description":"Recent image of most of the remaining Rwenzori Mountains glaciers (false color IR)","scaleExtent":[0,13],"polygon":[[[29.766296776846374,0.206886934953159],[29.766296776846374,0.509176367154027],[30.034603509024116,0.509176367154027],[30.034603509024116,0.206886934953159],[29.766296776846374,0.206886934953159]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R078_N01_20160702T082522","name":"imagico.de OSM images for mapping: Rwenzori Mountains 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R078_N01_20160702T082522&z={zoom}&x={x}&y={-y}","description":"Up-to-date image for glacier mapping (true color)","scaleExtent":[0,14],"polygon":[[[29.8051357269287,0.235862065771959],[29.8051357269287,0.467085433008179],[30.02503395080565,0.467085433008179],[30.02503395080565,0.235862065771959],[29.8051357269287,0.235862065771959]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC80611072014036LGN00","name":"imagico.de OSM images for mapping: Scott Island","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC80611072014036LGN00&z={zoom}&x={x}&y={-y}","description":"Missing in other image sources (true color)","scaleExtent":[0,13],"polygon":[[[-180,-67.4263452007858],[-180,-67.32544337276457],[-179.8247337341308,-67.3253771978419],[-179.8247337341308,-67.4263452007858],[-180,-67.4263452007858]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC82100972015347LGN00","name":"imagico.de OSM images for mapping: Shag Rocks","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC82100972015347LGN00&z={zoom}&x={x}&y={-y}","description":"Missing in other image sources (true color)","scaleExtent":[0,13],"polygon":[[[-42.12874872458635,-53.72050213468143],[-42.14625818503558,-53.45782244664258],[-41.67573435080706,-53.445862233424414],[-41.6558216310805,-53.70871763480476],[-42.12874872458635,-53.72050213468143]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81130622013270LGN00","name":"imagico.de OSM images for mapping: Southeastern Sulawesi","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81130622013270LGN00&z={zoom}&x={x}&y={-y}","description":"Missing islands and coarse coastline due to cloud cover in Bing, lakes could also use additional detail (true color)","scaleExtent":[0,13],"polygon":[[[120.84382442048364,-3.595452324350203],[120.84382442048364,-3.159848173206955],[120.98184016755395,-2.514681686347053],[122.62618449738794,-2.514681686347053],[122.62618449738794,-3.002148034113534],[122.5007000308352,-3.595452324350203],[120.84382442048364,-3.595452324350203]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC80281222016035LGN00","name":"imagico.de OSM images for mapping: Southern Transantarctic Mountains","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC80281222016035LGN00&z={zoom}&x={x}&y={-y}","description":"Outside regular Landsat coverage and therefore not in LIMA and Bing/Mapbox (true color)","scaleExtent":[0,10],"polygon":[[[156.96951345925345,-84.50097988272655],[154.50857596843485,-84.46255082580927],[154.50857596843485,-82.60681485793681],[175.46774337070775,-82.58504749645738],[177.00582930246938,-83.52806548607914],[177.00582930246938,-84.19262083779002],[171.93838547371908,-84.34632646581997],[166.83798266071676,-84.44370142483508],[161.67028858819987,-84.50045345467909],[156.96951345925345,-84.50097988272655]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-s2sval","name":"imagico.de OSM images for mapping: Svalbard mosaic","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=s2sval&z={zoom}&x={x}&y={-y}","description":"Sentinel-2 mosaic of Svalbard (true color)","scaleExtent":[0,13],"polygon":[[[16.6108,76.4137],[16.4731,76.4268],[16.3788,76.4589],[14.4124,77.1324],[14.0784,77.2536],[10.9875,78.4054],[10.631,78.5605],[10.2314,78.8392],[10.3952,79.6074],[10.516,79.7731],[10.9632,79.8707],[20.2294,80.849],[20.4702,80.8493],[25.1752,80.6817],[33.4391,80.3438],[33.7809,80.3016],[34.0395,80.239],[33.977,80.1527],[25.5722,76.5917],[25.2739,76.481],[25.1416,76.4327],[24.937,76.4176],[16.6108,76.4137]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-DMS_1142636_160xx_20110507_1822xxxx","name":"imagico.de OSM images for mapping: Thule Air Base","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=DMS_1142636_160xx_20110507_1822xxxx&z={zoom}&x={x}&y={-y}","description":"Icebridge DMS image - alignment might be poor","scaleExtent":[0,15],"polygon":[[[-68.93976917529807,76.51132557714853],[-68.93976917529807,76.54990046497333],[-68.76634826923117,76.55175699880375],[-68.50992908740743,76.55175699880375],[-68.50743999744161,76.51611959755911],[-68.67897262836203,76.51193618208278],[-68.93976917529807,76.51132557714853]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-dms_thule2_2015.09.25","name":"imagico.de OSM images for mapping: Thule Airbase DMS low altitude overflight September 2015","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=dms_thule2_2015.09.25&z={zoom}&x={x}&y={-y}","description":"Icebridge DMS aerial images from Thule Airbase - alignment might be poor","scaleExtent":[0,17],"polygon":[[[-68.74291885235837,76.52635852412212],[-68.74446380475094,76.52840070669755],[-68.74806869366695,76.54938731810256],[-68.7461482320123,76.56016657973251],[-68.72275936940244,76.56022393334496],[-68.72017371991207,76.5577475347327],[-68.71853220799495,76.5292079974043],[-68.71977675297786,76.52636602351234],[-68.74291885235837,76.52635852412212]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-dms_thule_2015.10.06","name":"imagico.de OSM images for mapping: Thule Airbase DMS overflight October 2015","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=dms_thule_2015.10.06&z={zoom}&x={x}&y={-y}","description":"Icebridge DMS aerial images from Thule Airbase - alignment might be poor","scaleExtent":[0,16],"polygon":[[[-68.81923965911197,76.52510098413808],[-68.82651380996036,76.54176603738404],[-68.77344898680974,76.5439032956252],[-68.7021022270136,76.54544610909097],[-68.59176687697696,76.54560088014632],[-68.59183124999333,76.52793072237704],[-68.65970186690618,76.52510098413808],[-68.81923965911197,76.52510098413808]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-dms_thule_2015.09.25","name":"imagico.de OSM images for mapping: Thule Airbase DMS overflight September 2015","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=dms_thule_2015.09.25&z={zoom}&x={x}&y={-y}","description":"Icebridge DMS aerial images from Thule Airbase - alignment might be poor","scaleExtent":[0,16],"polygon":[[[-68.7777130980429,76.50687742381471],[-68.77661875676482,76.57064446843503],[-68.68115357350676,76.57065443536027],[-68.67630413960784,76.55384487076157],[-68.67619685124725,76.5307435998188],[-68.6852305312094,76.50688243050337],[-68.7777130980429,76.50687742381471]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R094_N79_20160812T105622","name":"imagico.de OSM images for mapping: Ushakov Island August 2016","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R094_N79_20160812T105622&z={zoom}&x={x}&y={-y}","description":"Up-to-date late summer imagery with few clouds (true color)","scaleExtent":[0,12],"polygon":[[[78.45885691499899,80.72643412860921],[78.45885691499899,80.9098976404357],[80.48892435884663,80.9098976404357],[80.48892435884663,80.72643412860921],[78.45885691499899,80.72643412860921]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC80910682014358LGN00","name":"imagico.de OSM images for mapping: Vanatinai","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC80910682014358LGN00&z={zoom}&x={x}&y={-y}","description":"Coarse coastline due to cloud cover in Bing/Mapbox (true color)","scaleExtent":[0,13],"polygon":[[[153.0613810625655,-11.789228234021259],[153.0613810625655,-11.288690822294749],[153.10927458673538,-11.072292520575749],[154.41201277643268,-11.072292520575749],[154.41201277643268,-11.789228234021259],[153.0613810625655,-11.789228234021259]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC82330892016031LGN00","name":"imagico.de OSM images for mapping: Volcán Calbuco","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC82330892016031LGN00&z={zoom}&x={x}&y={-y}","description":"Image from after the 2015 eruption (true color)","scaleExtent":[0,13],"polygon":[[[-72.8669610523419,-41.51741123877955],[-72.8669610523419,-41.045274923011036],[-72.23181395761533,-41.045274923011036],[-71.87510161630674,-41.10829439141359],[-72.00007109872861,-41.51741123877955],[-72.8669610523419,-41.51741123877955]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R089_N52_20160623T024048","name":"imagico.de OSM images for mapping: Vostochny Cosmodrome","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R089_N52_20160623T024048&z={zoom}&x={x}&y={-y}","description":"Recent image showing newest features (true color)","scaleExtent":[0,13],"polygon":[[[126.36143429881301,51.375528375017275],[126.34804471141064,52.33932231282816],[128.60762341624462,52.340895519845674],[128.6117432892915,51.375528375017275],[126.36143429881301,51.375528375017275]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-LC81490352013282LGN00","name":"imagico.de OSM images for mapping: Western Karakoram","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=LC81490352013282LGN00&z={zoom}&x={x}&y={-y}","description":"Represents approximately minimum snow cover so can be well used for glacier mapping (true color)","scaleExtent":[0,13],"polygon":[[[75.98364343730569,34.97850982318471],[73.96164407817483,35.36957188964085],[74.44281091777444,37.09391400468158],[76.50600900737405,36.7026732100855],[75.98364343730569,34.97850982318471]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"osmim-imagicode-S2A_R039_S15_20160510T145731","name":"imagico.de OSM images for mapping: Willkanuta Mountains and Quelccaya Ice Cap","type":"tms","template":"http://imagico.de/map/osmim_tiles.php?layer=S2A_R039_S15_20160510T145731&z={zoom}&x={x}&y={-y}","description":"Poor and outdated imagery in other sources (true color)","scaleExtent":[0,14],"polygon":[[[-71.18070648306262,-14.4978507264954],[-71.17976234548938,-13.710292880050797],[-70.5563740550841,-13.71262765059222],[-70.5563740550841,-14.4978507264954],[-71.18070648306262,-14.4978507264954]]],"terms_url":"http://maps.imagico.de/#osmim","terms_text":"imagico.de OSM images for mapping"},{"id":"IPR-orotofoto-last-tms","name":"IPR ortofoto LAST (tmsproxy)","type":"tms","template":"http://osm-{switch:a,b,c}.zby.cz/tiles_ipr_last.php/{zoom}/{x}/{y}.jpg","scaleExtent":[1,18],"polygon":[[[14.81231552124,49.93089301941],[14.18754582291,49.87687266984],[14.12025456314,50.19881542327],[14.74502426147,50.25247461226],[14.81231552124,49.93089301941]]]},{"id":"IPR-orotofoto-vege-tms","name":"IPR ortofoto Low-Vegetation (tmsproxy)","type":"tms","template":"http://osm-{switch:a,b,c}.zby.cz/tiles_ipr_vege.php/{zoom}/{x}/{y}.jpg","scaleExtent":[1,20],"polygon":[[[14.30454236984,49.99538124382],[14.3160436821,49.94205148763],[14.3499983888,49.94508261663],[14.35383872175,49.92726356386],[14.42385321818,49.93351545169],[14.4200902288,49.95097343212],[14.48865449494,49.95709281879],[14.48479036398,49.9750111737],[14.55385989188,49.98117257481],[14.55011770159,49.99851689993],[14.58455395868,50.0015874108],[14.58829614897,49.98424419323],[14.69168128485,49.99346468175],[14.67633637226,50.06452744171],[14.71278864961,50.06777324036],[14.70115373952,50.12158114828],[14.66470146217,50.11833899243],[14.6610031918,50.13543086714],[14.62755290441,50.13245658485],[14.61965341283,50.16894659259],[14.58542741996,50.16590546732],[14.58162921725,50.18344165464],[14.40776267983,50.167995553],[14.41156088254,50.15045369625],[14.37764851321,50.14743927281],[14.37379555571,50.16523508727],[14.33892816423,50.16213672855],[14.34278112173,50.14433976066],[14.27367931007,50.13819641038],[14.27749028245,50.12058459573],[14.20879964298,50.11447476994],[14.21288816219,50.09557069695],[14.24656290855,50.09856724424],[14.25417384067,50.06335893014],[14.21987061144,50.0603042129],[14.22369648177,50.04259477081],[14.257999711,50.04565061557],[14.26952647673,49.99225864496],[14.30454236984,49.99538124382]]]},{"id":"bartholomew_qi1940","name":"Ireland Bartholomew Quarter-Inch 1940","type":"tms","template":"http://geo.nls.uk/maps/ireland/bartholomew/{zoom}/{x}/{-y}.png","scaleExtent":[5,13],"polygon":[[[-8.8312773,55.3963337],[-7.3221271,55.398605],[-7.2891331,55.4333162],[-7.2368042,55.4530757],[-7.18881,55.4497995],[-7.1528144,55.3968384],[-6.90561,55.394903],[-6.9047153,55.3842114],[-5.8485282,55.3922956],[-5.8378629,55.248676],[-5.3614762,55.2507024],[-5.3899172,53.8466464],[-5.8734141,53.8487436],[-5.8983,52.8256258],[-6.0191742,52.8256258],[-6.0262844,51.7712367],[-8.1131422,51.7712367],[-8.1273627,51.3268839],[-10.6052842,51.3091083],[-10.6271879,52.0328254],[-10.6469845,52.0322454],[-10.6469845,52.0440365],[-10.6271879,52.0448095],[-10.6290733,52.0745627],[-10.6699234,52.0743695],[-10.6702376,52.0876941],[-10.6312729,52.0898179],[-10.6393128,52.4147202],[-10.3137689,52.4185533],[-10.3166401,53.3341342],[-10.3699669,53.3330727],[-10.385965,54.3534472],[-8.8163777,54.3586265],[-8.8173427,54.6595721],[-8.8413398,54.6616284],[-8.8422286,54.6929749],[-8.8315632,54.7145436],[-8.8151208,54.7145436],[-8.8312773,55.3963337]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"GSGS3906","name":"Ireland British War Office 1:25k GSGS 3906","type":"tms","template":"http://mapwarper.net/layers/tile/101/{zoom}/{x}/{y}.png","scaleExtent":[0,18],"polygon":[[[-10.71,51.32],[-10.71,55.46],[-5.37,55.46],[-5.37,51.32],[-10.71,51.32]]],"terms_url":"http://wiki.openstreetmap.org/wiki/WikiProject_Ireland#Trinity_College_Dublin","terms_text":"Glucksman Map Library, Trinity College Dublin"},{"id":"GSGS4136","name":"Ireland British War Office One-Inch 1941-43 GSGS 4136","type":"tms","template":"http://geo.nls.uk/maps/ireland/gsgs4136/{zoom}/{x}/{-y}.png","scaleExtent":[5,15],"polygon":[[[-10.0847426,51.4147902],[-10.0906535,51.5064103],[-10.4564222,51.5003961],[-10.5005905,52.3043019],[-10.0837522,52.312741],[-10.0840973,52.3404698],[-10.055802,52.3408915],[-10.0768509,52.7628238],[-9.7780248,52.7684611],[-9.7818205,52.8577261],[-9.6337877,52.8596012],[-9.6449626,53.1294502],[-10.0919663,53.1227152],[-10.1051422,53.3912913],[-10.4052593,53.3866349],[-10.4530828,54.193502],[-10.2998523,54.1974988],[-10.3149801,54.4669592],[-8.9276095,54.4853897],[-8.9339534,54.7546562],[-8.7773069,54.755501],[-8.7826749,55.0252208],[-8.9402974,55.0238221],[-8.9451773,55.2934155],[-7.528039,55.2970274],[-7.525599,55.3874955],[-7.0541955,55.3841691],[-7.0556595,55.2939712],[-6.3241545,55.2859128],[-6.3217146,55.3253556],[-6.1035807,55.3223016],[-6.1045566,55.2828557],[-5.7985836,55.2772968],[-5.8117595,55.0087135],[-5.656577,55.0056351],[-5.6721928,54.7355021],[-5.3618278,54.729585],[-5.3964755,54.1917889],[-5.855679,54.2017807],[-5.9220464,52.8524504],[-6.070885,52.8551025],[-6.1030927,52.1373337],[-6.8331336,52.1463183],[-6.8355736,52.0578908],[-7.5641506,52.0617913],[-7.5661026,51.7921593],[-8.147305,51.792763],[-8.146329,51.7033331],[-8.2912636,51.7027283],[-8.2897996,51.5227274],[-9.1174397,51.516958],[-9.1179277,51.4625685],[-9.3692452,51.4616564],[-9.3672933,51.4254613],[-10.0847426,51.4147902]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"gsi.go.jp","name":"Japan GSI ortho Imagery","type":"tms","template":"http://cyberjapandata.gsi.go.jp/xyz/ort/{zoom}/{x}/{y}.jpg","scaleExtent":[12,19],"polygon":[[[141.85546875,44.64911632343077],[140.2294921875,43.96909818325174],[138.955078125,41.80407814427237],[139.482421875,40.17887331434696],[138.8671875,38.30718056188316],[136.31835937499997,37.19533058280065],[132.1435546875,35.137879119634185],[128.935546875,33.35806161277885],[129.5068359375,32.47269502206151],[129.77050781249997,31.690781806136822],[130.2099609375,30.90222470517144],[131.220703125,30.78903675126116],[131.66015625,32.32427558887655],[132.71484375,32.879587173066305],[133.76953125,33.17434155100208],[136.7578125,33.87041555094183],[139.306640625,35.06597313798418],[140.888671875,35.17380831799959],[141.15234374999997,36.56260003738548],[142.11914062499997,39.9434364619742],[141.767578125,42.68243539838623],[141.85546875,44.64911632343077]]]},{"id":"Aargau-AGIS-2011","name":"Kanton Aargau 25cm (AGIS 2011)","type":"tms","template":"http://tiles.poole.ch/AGIS/OF2011/{zoom}/{x}/{y}.png","scaleExtent":[14,19],"polygon":[[[7.7,47.12],[7.7,47.63],[8.5,47.63],[8.5,47.12],[7.7,47.12]]],"terms_text":"AGIS OF2011"},{"id":"Aargau-AGIS-2014","name":"Kanton Aargau 25cm (AGIS 2014)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/AGIS2014/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[8,20],"polygon":[[[8.222923278808594,47.604774168947614],[8.244209289550781,47.613569753973955],[8.294334411621094,47.60986653003798],[8.300857543945312,47.58625231278527],[8.329353332519531,47.569808674020344],[8.382568359375,47.56702895728551],[8.398017883300781,47.57490443821351],[8.424797058105469,47.56795554592218],[8.415184020996094,47.54663986006874],[8.389778137207031,47.5262428287156],[8.372268676757812,47.51233121261258],[8.358535766601562,47.503286684046664],[8.36402893066406,47.48078455918],[8.371238708496094,47.481016589036074],[8.373985290527344,47.47011007802331],[8.368148803710938,47.46825342516445],[8.387031555175781,47.44852243794931],[8.380851745605469,47.447593738482304],[8.384284973144531,47.4355191531953],[8.376388549804688,47.431803338643334],[8.377761840820312,47.42808726171425],[8.389434814453125,47.42739046807988],[8.391494750976562,47.41902822496511],[8.380165100097656,47.40462347023052],[8.364715576171875,47.4016026187529],[8.367118835449219,47.39881398671558],[8.380851745605469,47.39788440990287],[8.39424133300781,47.39439835079049],[8.399734497070312,47.372314620566925],[8.40728759765625,47.37068703239024],[8.404197692871094,47.34417352612498],[8.416213989257812,47.33416935720614],[8.414497375488281,47.32602502961836],[8.452606201171875,47.33254059215931],[8.444023132324219,47.31927592106609],[8.427543640136719,47.29925625338924],[8.390121459960938,47.28854494625744],[8.41175079345703,47.247076403108416],[8.393898010253906,47.227728840642065],[8.404884338378906,47.194845099780174],[8.401451110839844,47.17757880776958],[8.409690856933594,47.17314466448546],[8.412437438964844,47.13976002139446],[8.379478454589844,47.13929295458033],[8.361968994140625,47.14559801038333],[8.342742919921875,47.177112073280966],[8.3056640625,47.24987305653909],[8.295021057128906,47.26268916206698],[8.300514221191406,47.26991141830738],[8.278884887695312,47.28225686421767],[8.259315490722656,47.285983225286174],[8.243522644042969,47.280859411143915],[8.240432739257812,47.27130916053537],[8.228759765625,47.27270686584952],[8.219146728515625,47.25336866567523],[8.204727172851562,47.245444953748034],[8.203353881835938,47.22679624955806],[8.180007934570312,47.22143353240336],[8.171768188476562,47.2279619858493],[8.155975341796875,47.23961793870555],[8.175888061523436,47.24218190428504],[8.17657470703125,47.25406775981567],[8.136062622070312,47.24730946320093],[8.12164306640625,47.24218190428504],[8.10791015625,47.2447457457832],[8.097267150878906,47.259427174956194],[8.077354431152344,47.2603591917818],[8.059844970703125,47.25569894358661],[8.062591552734375,47.24614415248379],[8.016586303710938,47.242881146090085],[8.015899658203125,47.258961160390896],[7.997016906738281,47.2796948387185],[7.951698303222655,47.274337475394645],[7.960968017578125,47.25430078914495],[7.933845520019531,47.237053849043896],[7.911529541015624,47.24381345414034],[7.859344482421875,47.23425651880584],[7.83977508544922,47.23425651880584],[7.826042175292968,47.24427960201268],[7.828102111816407,47.25966018070071],[7.82398223876953,47.26548499105541],[7.8408050537109375,47.273405704663965],[7.848701477050781,47.28551744450745],[7.860374450683594,47.30461109337307],[7.871704101562499,47.31136207506936],[7.8888702392578125,47.31136207506936],[7.897453308105469,47.31904317780638],[7.895393371582031,47.327653995607086],[7.908439636230469,47.340451266106996],[7.9259490966796875,47.332773275955894],[7.94757843017578,47.331609846720866],[7.94757843017578,47.316715688820764],[8.007316589355467,47.33905535093827],[8.004913330078125,47.34533667855891],[8.011093139648438,47.35719936945847],[8.024139404296875,47.36719917429931],[8.032722473144531,47.38393878966209],[8.026885986328125,47.39602520707679],[8.010749816894531,47.3955603961201],[8.004570007324219,47.40671472747142],[7.975730895996094,47.41507892620099],[7.9657745361328125,47.42181578692778],[7.985343933105469,47.425764580393924],[7.971954345703124,47.46105827584221],[7.957534790039062,47.457344265054225],[7.940711975097656,47.46221885041022],[7.946891784667968,47.48403288391224],[7.907066345214844,47.48588897929538],[7.8936767578125,47.50653361720931],[7.873420715332031,47.51325876844644],[7.875480651855468,47.52253342509336],[7.865180969238281,47.51975120023913],[7.856254577636718,47.533660849056794],[7.833251953125,47.5325018525392],[7.834281921386719,47.51465007145751],[7.789649963378906,47.49377665301097],[7.789649963378906,47.518128167602484],[7.7515411376953125,47.52461999690649],[7.731285095214843,47.53203824675999],[7.708969116210937,47.54015075619555],[7.740898132324219,47.54362716173679],[7.761497497558593,47.54895720250044],[7.781410217285156,47.55289644950155],[7.797546386718749,47.55915229204993],[7.805442810058593,47.56563904359584],[7.814369201660155,47.575136052077276],[7.819175720214843,47.58648387645128],[7.8325653076171875,47.586715439092906],[7.843208312988281,47.581620824334166],[7.859344482421875,47.58602074809481],[7.8847503662109375,47.58764167941513],[7.903633117675781,47.58092606572345],[7.911872863769532,47.56749225365282],[7.90740966796875,47.55776216936179],[7.917709350585938,47.545712894408624],[7.929382324218749,47.54640812019053],[7.941741943359374,47.54432241518175],[7.9520416259765625,47.54965238525127],[7.9561614990234375,47.55683540041267],[7.9767608642578125,47.55544521625339],[7.997360229492187,47.556603705614094],[8.019676208496094,47.54965238525127],[8.049888610839844,47.55637200979099],[8.058815002441406,47.56285910557121],[8.072891235351562,47.56355410390809],[8.086967468261719,47.557067094186735],[8.100700378417969,47.56216409801383],[8.105506896972656,47.57976811421671],[8.113059997558594,47.583473468887405],[8.133659362792969,47.58301031389572],[8.138809204101562,47.59042030203756],[8.15185546875,47.59551406038282],[8.166275024414062,47.5941249027327],[8.177261352539062,47.6017648134425],[8.193740844726562,47.616346999837226],[8.2012939453125,47.62120682516921],[8.219490051269531,47.61958693358351],[8.223953247070312,47.61102381568743],[8.222923278808594,47.604774168947614]]],"terms_text":"AGIS OF2014"},{"id":"Aargau-AGIS-2016","name":"Kanton Aargau 25cm (AGIS 2016)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/AGIS2016/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[8,20],"polygon":[[[8.222923278808594,47.604774168947614],[8.244209289550781,47.613569753973955],[8.294334411621094,47.60986653003798],[8.300857543945312,47.58625231278527],[8.329353332519531,47.569808674020344],[8.382568359375,47.56702895728551],[8.398017883300781,47.57490443821351],[8.424797058105469,47.56795554592218],[8.415184020996094,47.54663986006874],[8.389778137207031,47.5262428287156],[8.372268676757812,47.51233121261258],[8.358535766601562,47.503286684046664],[8.36402893066406,47.48078455918],[8.371238708496094,47.481016589036074],[8.373985290527344,47.47011007802331],[8.368148803710938,47.46825342516445],[8.387031555175781,47.44852243794931],[8.380851745605469,47.447593738482304],[8.384284973144531,47.4355191531953],[8.376388549804688,47.431803338643334],[8.377761840820312,47.42808726171425],[8.389434814453125,47.42739046807988],[8.391494750976562,47.41902822496511],[8.380165100097656,47.40462347023052],[8.364715576171875,47.4016026187529],[8.367118835449219,47.39881398671558],[8.380851745605469,47.39788440990287],[8.39424133300781,47.39439835079049],[8.399734497070312,47.372314620566925],[8.40728759765625,47.37068703239024],[8.404197692871094,47.34417352612498],[8.416213989257812,47.33416935720614],[8.414497375488281,47.32602502961836],[8.452606201171875,47.33254059215931],[8.444023132324219,47.31927592106609],[8.427543640136719,47.29925625338924],[8.390121459960938,47.28854494625744],[8.41175079345703,47.247076403108416],[8.393898010253906,47.227728840642065],[8.404884338378906,47.194845099780174],[8.401451110839844,47.17757880776958],[8.409690856933594,47.17314466448546],[8.412437438964844,47.13976002139446],[8.379478454589844,47.13929295458033],[8.361968994140625,47.14559801038333],[8.342742919921875,47.177112073280966],[8.3056640625,47.24987305653909],[8.295021057128906,47.26268916206698],[8.300514221191406,47.26991141830738],[8.278884887695312,47.28225686421767],[8.259315490722656,47.285983225286174],[8.243522644042969,47.280859411143915],[8.240432739257812,47.27130916053537],[8.228759765625,47.27270686584952],[8.219146728515625,47.25336866567523],[8.204727172851562,47.245444953748034],[8.203353881835938,47.22679624955806],[8.180007934570312,47.22143353240336],[8.171768188476562,47.2279619858493],[8.155975341796875,47.23961793870555],[8.175888061523436,47.24218190428504],[8.17657470703125,47.25406775981567],[8.136062622070312,47.24730946320093],[8.12164306640625,47.24218190428504],[8.10791015625,47.2447457457832],[8.097267150878906,47.259427174956194],[8.077354431152344,47.2603591917818],[8.059844970703125,47.25569894358661],[8.062591552734375,47.24614415248379],[8.016586303710938,47.242881146090085],[8.015899658203125,47.258961160390896],[7.997016906738281,47.2796948387185],[7.951698303222655,47.274337475394645],[7.960968017578125,47.25430078914495],[7.933845520019531,47.237053849043896],[7.911529541015624,47.24381345414034],[7.859344482421875,47.23425651880584],[7.83977508544922,47.23425651880584],[7.826042175292968,47.24427960201268],[7.828102111816407,47.25966018070071],[7.82398223876953,47.26548499105541],[7.8408050537109375,47.273405704663965],[7.848701477050781,47.28551744450745],[7.860374450683594,47.30461109337307],[7.871704101562499,47.31136207506936],[7.8888702392578125,47.31136207506936],[7.897453308105469,47.31904317780638],[7.895393371582031,47.327653995607086],[7.908439636230469,47.340451266106996],[7.9259490966796875,47.332773275955894],[7.94757843017578,47.331609846720866],[7.94757843017578,47.316715688820764],[8.007316589355467,47.33905535093827],[8.004913330078125,47.34533667855891],[8.011093139648438,47.35719936945847],[8.024139404296875,47.36719917429931],[8.032722473144531,47.38393878966209],[8.026885986328125,47.39602520707679],[8.010749816894531,47.3955603961201],[8.004570007324219,47.40671472747142],[7.975730895996094,47.41507892620099],[7.9657745361328125,47.42181578692778],[7.985343933105469,47.425764580393924],[7.971954345703124,47.46105827584221],[7.957534790039062,47.457344265054225],[7.940711975097656,47.46221885041022],[7.946891784667968,47.48403288391224],[7.907066345214844,47.48588897929538],[7.8936767578125,47.50653361720931],[7.873420715332031,47.51325876844644],[7.875480651855468,47.52253342509336],[7.865180969238281,47.51975120023913],[7.856254577636718,47.533660849056794],[7.833251953125,47.5325018525392],[7.834281921386719,47.51465007145751],[7.789649963378906,47.49377665301097],[7.789649963378906,47.518128167602484],[7.7515411376953125,47.52461999690649],[7.731285095214843,47.53203824675999],[7.708969116210937,47.54015075619555],[7.740898132324219,47.54362716173679],[7.761497497558593,47.54895720250044],[7.781410217285156,47.55289644950155],[7.797546386718749,47.55915229204993],[7.805442810058593,47.56563904359584],[7.814369201660155,47.575136052077276],[7.819175720214843,47.58648387645128],[7.8325653076171875,47.586715439092906],[7.843208312988281,47.581620824334166],[7.859344482421875,47.58602074809481],[7.8847503662109375,47.58764167941513],[7.903633117675781,47.58092606572345],[7.911872863769532,47.56749225365282],[7.90740966796875,47.55776216936179],[7.917709350585938,47.545712894408624],[7.929382324218749,47.54640812019053],[7.941741943359374,47.54432241518175],[7.9520416259765625,47.54965238525127],[7.9561614990234375,47.55683540041267],[7.9767608642578125,47.55544521625339],[7.997360229492187,47.556603705614094],[8.019676208496094,47.54965238525127],[8.049888610839844,47.55637200979099],[8.058815002441406,47.56285910557121],[8.072891235351562,47.56355410390809],[8.086967468261719,47.557067094186735],[8.100700378417969,47.56216409801383],[8.105506896972656,47.57976811421671],[8.113059997558594,47.583473468887405],[8.133659362792969,47.58301031389572],[8.138809204101562,47.59042030203756],[8.15185546875,47.59551406038282],[8.166275024414062,47.5941249027327],[8.177261352539062,47.6017648134425],[8.193740844726562,47.616346999837226],[8.2012939453125,47.62120682516921],[8.219490051269531,47.61958693358351],[8.223953247070312,47.61102381568743],[8.222923278808594,47.604774168947614]]],"terms_text":"AGIS OF2016","best":true},{"id":"Basel-Landschaft-2015","name":"Kanton Basel-Landschaft 10cm (2015)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/KTBASELLANDSCHAFT2015/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[18,21],"polygon":[[[7.370281219482422,47.413684985326796],[7.357578277587891,47.41507892620101],[7.357921600341797,47.41827323486739],[7.353544235229492,47.4196089792119],[7.344875335693359,47.42402250214274],[7.339725494384765,47.42971307765559],[7.332687377929687,47.430235650685475],[7.32685089111328,47.4319194618196],[7.325280543317693,47.43489176778178],[7.33050406703179,47.44175856152086],[7.338990092194756,47.44109169292469],[7.344964876980962,47.43607806019703],[7.352656881264292,47.43435807026775],[7.38119797480828,47.432081698142134],[7.375988960266113,47.414309359238985],[7.378145456314087,47.41399717320828],[7.382040023803711,47.41330745332341],[7.388391494750976,47.41397539271845],[7.413708184603623,47.410929293287566],[7.420743520414262,47.411098781635985],[7.427483310496426,47.41448047082256],[7.438105529405026,47.412739349590474],[7.448396898794484,47.41507114537187],[7.455576414208223,47.42792319548619],[7.45061852232364,47.43534476535272],[7.437842682352891,47.446323188615104],[7.425422575234655,47.443283894442736],[7.420904049355535,47.44594415975335],[7.422417620777747,47.45071647996838],[7.428795928789581,47.45387944195848],[7.430028776685507,47.459491697398036],[7.445765194338128,47.46197276972992],[7.44717015944249,47.456958090215814],[7.456512189239691,47.44925575541638],[7.492356675875099,47.458972279610066],[7.530679075390223,47.46118857622267],[7.527445320030451,47.473906165741866],[7.536326693749955,47.48383279861684],[7.536231113003725,47.49105266753894],[7.532603895549507,47.490968962664795],[7.531789123586811,47.49739885661967],[7.520038351186771,47.49678264400428],[7.512226152318425,47.49891674929323],[7.509348758631863,47.508884893812876],[7.499082452238831,47.51627805213703],[7.497870355425969,47.52124757864722],[7.502278119030558,47.514906577969604],[7.517459288006065,47.51728104695845],[7.522200236749534,47.514091442409054],[7.530955756497733,47.52904526885427],[7.519353655277215,47.53471778813415],[7.510751927105658,47.528989768842564],[7.50229842095598,47.52840455858729],[7.4980383403841,47.536152181750076],[7.505454651706732,47.54438188661593],[7.516758242758337,47.545408295649786],[7.527317399933993,47.552778846515565],[7.554658254426867,47.564368052237306],[7.5645783501094,47.55703599040843],[7.561243624111692,47.55172275211291],[7.558752685660356,47.55235329499035],[7.555882119169953,47.54433555917895],[7.564785321950861,47.54568625396918],[7.587263056821628,47.54190064304111],[7.582688476068778,47.53246814131337],[7.589482524394103,47.5279230654027],[7.590248428005343,47.51978966346127],[7.594781326929009,47.51929395578897],[7.613780785019665,47.53925099543145],[7.622303281783164,47.53977428916004],[7.622854488041502,47.550040256825795],[7.617740918118178,47.554366555487356],[7.617617220103555,47.558648485827725],[7.632727781497729,47.5614887674157],[7.639973682410965,47.55816478484801],[7.648995462809379,47.548295861439875],[7.661308760240334,47.544832242956765],[7.665860164458853,47.53745814872834],[7.674674254363578,47.5337535789565],[7.694938989531916,47.532496041115465],[7.71346844906592,47.53978344629896],[7.715956243413761,47.53582195507857],[7.723622825374551,47.536754165368905],[7.727157067196862,47.53293048764033],[7.733221863174538,47.53275465944404],[7.737974130690588,47.52732498381306],[7.749022330706917,47.5249849998809],[7.757861753102653,47.52605097450287],[7.787633628417415,47.52011695778467],[7.790143521321244,47.51864117486466],[7.788870069574476,47.50682929074843],[7.792799480290271,47.500684271209245],[7.786625359342518,47.49312139201968],[7.798890147748131,47.49565149600841],[7.798162871694108,47.49939947973339],[7.799400121334925,47.497477088945935],[7.807418124234862,47.4971384859743],[7.814709929059118,47.504801278976316],[7.831976267472122,47.51473657456054],[7.833207588232065,47.53382387257594],[7.846527268275818,47.53266095290337],[7.852330295179702,47.53523506225097],[7.862569292788096,47.52692027402488],[7.86395674074442,47.519309183202445],[7.876658649367283,47.52269034821798],[7.87567113137545,47.51319304945735],[7.893993798731052,47.50605656803392],[7.904769180395594,47.49217505264052],[7.904821911502771,47.48490926161113],[7.93328835504665,47.48140776210853],[7.947015241408695,47.48488995686335],[7.940027875634228,47.462021295570224],[7.948854362289874,47.46377967418039],[7.957614193951437,47.45880646812721],[7.957849013566705,47.451279351685564],[7.946784554043733,47.44319336966537],[7.950032053627354,47.431716361052416],[7.96183169437885,47.421834282667845],[7.956570351591289,47.41968057428149],[7.955037646053525,47.415605646331336],[7.948388855309641,47.4162657867356],[7.934927870271696,47.41176694218953],[7.936722434714782,47.408057452805856],[7.932661510641391,47.40527495151619],[7.909737672400531,47.398520997340924],[7.890221593189976,47.407141074214024],[7.883331964118422,47.40609724771633],[7.883443085719068,47.4012049891245],[7.877702761222016,47.401257097623],[7.869136696167237,47.3955142728722],[7.879434713089799,47.38799354849815],[7.878812180597903,47.38351047538804],[7.862650230995195,47.38198499163919],[7.840119046365023,47.374763282921705],[7.830547227518145,47.36512144155488],[7.80216648325237,47.36109584064414],[7.796366151294341,47.3534705803715],[7.793560892325092,47.33905227137494],[7.78528803737905,47.3378822997136],[7.768963133383802,47.33891408469915],[7.766419194330703,47.342734660857005],[7.751518928544542,47.3443274446774],[7.734153146629586,47.35776074638933],[7.727913718160677,47.36885889855421],[7.701953574259492,47.37244716296033],[7.644203220263186,47.36720838530677],[7.641761060331779,47.38046937860509],[7.635580022356337,47.38059279713257],[7.633316986492583,47.38291397270416],[7.633305398225418,47.38533959871929],[7.637251158279386,47.38606854199808],[7.63272275093214,47.41003108104519],[7.664054730400831,47.41001995588381],[7.679802017668389,47.41751395224505],[7.686578998003315,47.43366406703297],[7.682972441800632,47.43872228466388],[7.684853783500164,47.447843589969715],[7.692273418589347,47.45421309996921],[7.698831030331891,47.45585888435835],[7.699930658071183,47.46190517358485],[7.709877972706822,47.469384739707586],[7.699760966314013,47.48063247960835],[7.668326578902932,47.48634665620256],[7.666120855554305,47.49686816039971],[7.65217109717027,47.49581439933043],[7.648646287658441,47.49183004211102],[7.655389581170213,47.49020559719241],[7.650513795302598,47.48826095607083],[7.655925875394832,47.48739459757455],[7.644422678687097,47.485637798180356],[7.640965961473804,47.482734093980326],[7.607299799570857,47.48939839412024],[7.608850381582776,47.48352506892989],[7.605631268762133,47.47935909729055],[7.608148977008936,47.475213682276376],[7.604494899927722,47.47044546774548],[7.618872436050056,47.4674530520825],[7.626072253389216,47.462913883669614],[7.62217338539308,47.46195224188912],[7.616464591762502,47.445234574416695],[7.615798850305441,47.432747890966844],[7.592069133423196,47.43271179535717],[7.581206884670679,47.42878068945942],[7.578423275099778,47.434906655087865],[7.568904367023134,47.43689695884281],[7.56829539909203,47.42233486107083],[7.58074128785892,47.414703988151935],[7.525235194936931,47.41163289737562],[7.531172340312734,47.40352507464003],[7.518616677418122,47.38822295597742],[7.511295677347134,47.38974369796625],[7.502255661148456,47.384806980223004],[7.492327480628366,47.385231761698726],[7.478410241257615,47.39055778320416],[7.47746817801916,47.401277162725364],[7.464484018734026,47.40251498235377],[7.460919593518167,47.40068414452088],[7.450020783333588,47.40392739156406],[7.44951323519806,47.39975827367453],[7.443401098004909,47.40231427489849],[7.441311347159463,47.40017886074712],[7.443566657511773,47.38890284041263],[7.437324174770898,47.3808884773088],[7.411692544769116,47.38057235919037],[7.416276198506335,47.384788794341716],[7.414494030814171,47.39429988358522],[7.398935569419335,47.39683906243558],[7.395920463999715,47.40338304393273],[7.388693876865087,47.403019088497395],[7.384054886906365,47.4123601395877],[7.379679679870605,47.4128137535428],[7.375844120979309,47.41401169352981],[7.370281219482422,47.413684985326796]]],"terms_url":"http://www.geo.bl.ch/fileadmin/user_upload/Geodaten/Nutzungsbedingungen_GBD_BL_V3p1.pdf","terms_text":"Geodaten des Kantons Basel-Landschaft 2015","best":true},{"id":"KTBASELSTADT2015","name":"Kanton Basel-Stadt 2015","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/KTBASELSTADT2015/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[8,21],"polygon":[[[7.492,47.4817],[7.492,47.6342],[7.784,47.6342],[7.784,47.4817],[7.492,47.4817]]],"terms_text":"Kanton Basel-Stadt OF 2015"},{"id":"Solothurn-sogis2014-tms","name":"Kanton Solothurn 25cm (SOGIS 2014-2015)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/sogis2014/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[15,19],"polygon":[[[7.3404127,47.2175697],[7.4154818,47.2402115],[7.4173645,47.2537956],[7.4658424,47.2646513],[7.4946766,47.2882287],[7.5328638,47.294534],[7.5483333,47.3163566],[7.5709479,47.3263111],[7.5604584,47.342492],[7.5388991,47.3476266],[7.5396485,47.3601134],[7.5217459,47.3651488],[7.5237238,47.3720704],[7.4634937,47.3702566],[7.4361035,47.3781317],[7.4434011,47.4023143],[7.4774682,47.4012772],[7.4792364,47.3897076],[7.5022557,47.384807],[7.5213659,47.3912021],[7.5311724,47.4035251],[7.5252352,47.4116329],[7.5807413,47.414704],[7.5682954,47.4223349],[7.5689044,47.436897],[7.5812069,47.4287807],[7.6157989,47.4327479],[7.6260723,47.4629139],[7.6044949,47.4704455],[7.6072998,47.4893984],[7.640966,47.4827341],[7.6559259,47.4873946],[7.6521711,47.4958144],[7.6661209,47.4968682],[7.6683266,47.4863467],[7.699761,47.4806325],[7.709878,47.4693848],[7.6848538,47.4478436],[7.6798021,47.417514],[7.6327228,47.4100311],[7.633317,47.382914],[7.6417611,47.3804694],[7.6442033,47.3672084],[7.7279138,47.3688589],[7.751519,47.3443275],[7.7935609,47.3390523],[7.8021665,47.3610959],[7.8788122,47.3835105],[7.8691367,47.3955143],[7.883332,47.4060973],[7.9097377,47.398521],[7.9550377,47.4156057],[7.9618317,47.4218343],[7.9467846,47.4431934],[7.9682836,47.4628082],[7.9872707,47.4287435],[7.9854653,47.4227641],[7.9827035,47.4283325],[7.9631993,47.4223547],[8.0072617,47.4065858],[8.0100022,47.395418],[8.0265612,47.3956224],[8.0313669,47.3836856],[8.0038366,47.3453146],[8.0051906,47.3367516],[7.9479701,47.3171432],[7.9478307,47.3325169],[7.9192088,47.3339507],[7.9078055,47.341719],[7.889098,47.3114878],[7.8611018,47.3061239],[7.8418057,47.2744707],[7.8166423,47.2616706],[7.8028241,47.2684079],[7.7861469,47.256098],[7.7746009,47.267869],[7.7568187,47.258095],[7.7326672,47.2591133],[7.684769,47.2939919],[7.6482742,47.2819898],[7.5801066,47.2763483],[7.5936981,47.2662199],[7.5959384,47.245569],[7.6261802,47.2263143],[7.6405558,47.2297944],[7.6484666,47.2189525],[7.6472258,47.2017823],[7.6715278,47.1949714],[7.6711002,47.1845216],[7.6779881,47.1819259],[7.6728612,47.1683945],[7.6600808,47.1684026],[7.6451021,47.1489207],[7.6155322,47.1565739],[7.5861404,47.1475453],[7.5810534,47.16013],[7.5634674,47.1683541],[7.5257686,47.162205],[7.5203336,47.1588879],[7.5297508,47.1487369],[7.5097234,47.1255457],[7.4613252,47.1082327],[7.4750945,47.0867101],[7.454461,47.074927],[7.4354156,47.0801664],[7.4340002,47.1005003],[7.3820271,47.0957398],[7.3704914,47.1209312],[7.4401788,47.1237276],[7.4217922,47.1358605],[7.447783,47.1550805],[7.4728074,47.1525609],[7.4970383,47.1700873],[7.4804964,47.171738],[7.4708545,47.181324],[7.4757226,47.1906485],[7.4497638,47.1895691],[7.4476258,47.1810839],[7.4332849,47.1847269],[7.4118135,47.1624212],[7.3842442,47.1601249],[7.3821749,47.1651186],[7.391911,47.1662739],[7.3835137,47.1803011],[7.3654609,47.1944525],[7.3544799,47.1915316],[7.3404127,47.2175697]],[[7.420816,47.4803666],[7.4349836,47.4981011],[7.4707584,47.480734],[7.487277,47.4820136],[7.5116652,47.5026958],[7.5317892,47.4973989],[7.5366964,47.4850517],[7.5274454,47.4739062],[7.5306791,47.4611886],[7.4565122,47.4492558],[7.445214,47.4623781],[7.4557367,47.4733767],[7.420816,47.4803666]],[[7.3759458,47.4140995],[7.3821514,47.4330266],[7.4209041,47.4459442],[7.4378427,47.4463232],[7.4555765,47.4279232],[7.4437574,47.413444],[7.3759458,47.4140995]],[[7.6744234,47.1539707],[7.6853662,47.1662986],[7.7007985,47.1617746],[7.6901531,47.1525567],[7.6744234,47.1539707]]],"terms_text":"Orthofoto WMS Solothurn","best":true},{"id":"KTZUERICH2015","name":"Kanton Zürich 2015  10cm","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/KTZUERICH2015/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[8,21],"polygon":[[[8.807601928710938,47.66608099332474],[8.808631896972656,47.65475043477393],[8.830604553222656,47.648506014952225],[8.805885314941406,47.597597727711346],[8.749580383300781,47.61565270219988],[8.751983642578125,47.59505101193038],[8.807945251464844,47.585789182379905],[8.811721801757812,47.57467282332527],[8.840904235839844,47.57467282332527],[8.854637145996094,47.56216409801383],[8.8330078125,47.55382328811835],[8.845024108886719,47.53458802782819],[8.899612426757812,47.52786561031842],[8.895835876464844,47.491224888201955],[8.902702331542969,47.48588897929538],[8.887252807617188,47.475911695481756],[8.911285400390625,47.43969913094723],[8.934288024902344,47.43807362350206],[8.935317993164062,47.43017758727173],[8.917121887207031,47.42808726171425],[8.909912109375,47.404855836246135],[8.944587707519531,47.38905261221537],[8.945274353027344,47.379521907289295],[8.963127136230469,47.357664518690434],[8.973083496093748,47.35580389715929],[8.989906311035156,47.31857768821123],[8.973426818847656,47.30367985581531],[8.9593505859375,47.300653220457775],[8.941154479980469,47.2873805430142],[8.950080871582031,47.28458587064588],[8.940467834472656,47.259194168186234],[8.876266479492188,47.24847474828181],[8.876609802246092,47.243114224640834],[8.850173950195312,47.23961793870555],[8.849830627441406,47.247076403108416],[8.825111389160156,47.24824169331652],[8.800048828125,47.24031721435106],[8.804855346679688,47.23425651880584],[8.815155029296875,47.217702626593784],[8.793525695800781,47.21886856286133],[8.71490478515625,47.20021050593422],[8.685722351074219,47.18154588528182],[8.697395324707031,47.163108130899104],[8.660659790039062,47.15633823511178],[8.6572265625,47.16684287656919],[8.618087768554688,47.172444502751944],[8.622550964355469,47.17991241867412],[8.607101440429688,47.201376826785406],[8.595085144042969,47.19834433924206],[8.575859069824219,47.21513747655813],[8.541183471679688,47.2186353776589],[8.471488952636719,47.2053421258966],[8.441619873046875,47.22120035848172],[8.417243957519531,47.22120035848172],[8.383941650390625,47.292270864380086],[8.422050476074219,47.302282968719936],[8.442306518554688,47.32439601339355],[8.413810729980469,47.32299967378833],[8.408660888671875,47.33067908487908],[8.378448486328125,47.39718721653071],[8.360939025878906,47.39695481668995],[8.359222412109375,47.4053205652024],[8.379135131835938,47.40764414848437],[8.377418518066406,47.41624051540972],[8.384284973144531,47.42274494145051],[8.372611999511719,47.42808726171425],[8.372955322265625,47.437376962080776],[8.379478454589844,47.45037978769006],[8.36402893066406,47.46198673754625],[8.352012634277344,47.5079250985124],[8.373985290527344,47.517200697839414],[8.392181396484375,47.5366741201253],[8.417587280273436,47.56610235225701],[8.430290222167967,47.5693453981427],[8.491744995117188,47.581620824334166],[8.487625122070312,47.58648387645128],[8.463935852050781,47.58301031389572],[8.453292846679688,47.60315376826432],[8.479385375976562,47.617504142079596],[8.505821228027344,47.61958693358351],[8.513717651367188,47.635783590864854],[8.542213439941406,47.632776019724375],[8.545646667480469,47.627685889602006],[8.564186096191406,47.6256034207548],[8.566932678222656,47.61935551640258],[8.576202392578125,47.613569753973955],[8.564872741699219,47.60037582174319],[8.535346984863281,47.586715439092906],[8.550109863281248,47.5714301073211],[8.555259704589844,47.55498181333744],[8.581008911132812,47.59551406038282],[8.598861694335936,47.61449551898437],[8.59130859375,47.64642437575518],[8.609848022460938,47.65521295468833],[8.620834350585938,47.646886969413],[8.618431091308594,47.65660048985082],[8.602981567382812,47.666312203609145],[8.610877990722656,47.67856488312544],[8.62323760986328,47.67856488312544],[8.621864318847656,47.69312564683551],[8.64898681640625,47.697516190510555],[8.667526245117188,47.68665469810477],[8.671646118164062,47.67602211074509],[8.692245483398438,47.65197522925437],[8.734817504882812,47.64526787368664],[8.777389526367188,47.65313158281113],[8.785629272460938,47.667930646923494],[8.807601928710938,47.66608099332474]]],"terms_text":"Kanton Zürich OF 2015","best":true},{"id":"kelowna_2012","name":"Kelowna 2012","type":"tms","template":"http://{switch:a,b,c,d}.tile.paulnorman.ca/kelowna2012/{zoom}/{x}/{y}.png","description":"High quality aerial imagery taken for the City of Kelowna","scaleExtent":[9,20],"polygon":[[[-119.5867318,49.7928087],[-119.5465655,49.7928097],[-119.5465661,49.8013837],[-119.5343374,49.8013841],[-119.5343376,49.8047321],[-119.5296211,49.8047322],[-119.5296216,49.8119555],[-119.5104463,49.811956],[-119.5115683,49.8744325],[-119.5108946,49.8744904],[-119.5114111,49.8843312],[-119.5114115,49.9221763],[-119.49386,49.9223477],[-119.4940505,49.9313031],[-119.4803936,49.9317529],[-119.4804572,49.9407474],[-119.4666732,49.9409927],[-119.4692775,49.9913717],[-119.4551337,49.9916078],[-119.4556736,50.0121242],[-119.4416673,50.0123895],[-119.4417308,50.0136345],[-119.4221492,50.0140377],[-119.4221042,50.0119306],[-119.4121303,50.012165],[-119.4126082,50.0216913],[-119.4123387,50.0216913],[-119.4124772,50.0250773],[-119.4120917,50.0250821],[-119.4121954,50.0270769],[-119.4126083,50.0270718],[-119.4128328,50.0321946],[-119.3936313,50.0326418],[-119.393529,50.0307781],[-119.3795727,50.0310116],[-119.3795377,50.0287584],[-119.3735764,50.0288621],[-119.371544,49.9793618],[-119.3573506,49.9793618],[-119.3548353,49.9256081],[-119.3268079,49.9257238],[-119.3256573,49.8804068],[-119.3138893,49.8806528],[-119.3137097,49.8771651],[-119.3132156,49.877223],[-119.3131482,49.8749652],[-119.312452,49.8749073],[-119.3122275,49.87236],[-119.3117558,49.872331],[-119.3115986,49.8696098],[-119.3112169,49.8694217],[-119.3109199,49.8632417],[-119.3103721,49.8632724],[-119.3095139,49.8512388],[-119.3106368,49.8512316],[-119.3103859,49.8462564],[-119.3245344,49.8459957],[-119.3246018,49.8450689],[-119.3367018,49.844875],[-119.3367467,49.8435136],[-119.337937,49.8434702],[-119.3378023,49.8382055],[-119.3383637,49.8381041],[-119.3383749,49.8351202],[-119.3390936,49.8351058],[-119.3388016,49.8321217],[-119.3391497,49.8320565],[-119.3391722,49.8293331],[-119.3394641,49.8293331],[-119.3395879,49.8267878],[-119.3500053,49.8265829],[-119.3493701,49.8180588],[-119.4046964,49.8163785],[-119.4045694,49.8099022],[-119.4101592,49.8099022],[-119.4102862,49.8072787],[-119.4319467,49.8069098],[-119.4322643,49.7907965],[-119.4459847,49.7905504],[-119.445286,49.7820201],[-119.4967376,49.7811587],[-119.4966105,49.7784927],[-119.5418371,49.7775082],[-119.5415892,49.7718277],[-119.5560296,49.7714941],[-119.5561194,49.7718422],[-119.5715704,49.7715086],[-119.5716153,49.7717262],[-119.5819235,49.7714941],[-119.5820133,49.7717697],[-119.5922991,49.7715231],[-119.592344,49.7718132],[-119.6003839,49.7715957],[-119.6011924,49.7839081],[-119.5864365,49.7843863],[-119.5867318,49.7928087]]]},{"id":"kelowna_roads","name":"Kelowna Roads overlay","type":"tms","template":"http://{switch:a,b,c,d}.tile.paulnorman.ca/kelowna_overlay/{zoom}/{x}/{y}.png","scaleExtent":[9,20],"polygon":[[[-119.5867318,49.7928087],[-119.5465655,49.7928097],[-119.5465661,49.8013837],[-119.5343374,49.8013841],[-119.5343376,49.8047321],[-119.5296211,49.8047322],[-119.5296216,49.8119555],[-119.5104463,49.811956],[-119.5115683,49.8744325],[-119.5108946,49.8744904],[-119.5114111,49.8843312],[-119.5114115,49.9221763],[-119.49386,49.9223477],[-119.4940505,49.9313031],[-119.4803936,49.9317529],[-119.4804572,49.9407474],[-119.4666732,49.9409927],[-119.4692775,49.9913717],[-119.4551337,49.9916078],[-119.4556736,50.0121242],[-119.4416673,50.0123895],[-119.4417308,50.0136345],[-119.4221492,50.0140377],[-119.4221042,50.0119306],[-119.4121303,50.012165],[-119.4126082,50.0216913],[-119.4123387,50.0216913],[-119.4124772,50.0250773],[-119.4120917,50.0250821],[-119.4121954,50.0270769],[-119.4126083,50.0270718],[-119.4128328,50.0321946],[-119.3936313,50.0326418],[-119.393529,50.0307781],[-119.3795727,50.0310116],[-119.3795377,50.0287584],[-119.3735764,50.0288621],[-119.371544,49.9793618],[-119.3573506,49.9793618],[-119.3548353,49.9256081],[-119.3268079,49.9257238],[-119.3256573,49.8804068],[-119.3138893,49.8806528],[-119.3137097,49.8771651],[-119.3132156,49.877223],[-119.3131482,49.8749652],[-119.312452,49.8749073],[-119.3122275,49.87236],[-119.3117558,49.872331],[-119.3115986,49.8696098],[-119.3112169,49.8694217],[-119.3109199,49.8632417],[-119.3103721,49.8632724],[-119.3095139,49.8512388],[-119.3106368,49.8512316],[-119.3103859,49.8462564],[-119.3245344,49.8459957],[-119.3246018,49.8450689],[-119.3367018,49.844875],[-119.3367467,49.8435136],[-119.337937,49.8434702],[-119.3378023,49.8382055],[-119.3383637,49.8381041],[-119.3383749,49.8351202],[-119.3390936,49.8351058],[-119.3388016,49.8321217],[-119.3391497,49.8320565],[-119.3391722,49.8293331],[-119.3394641,49.8293331],[-119.3395879,49.8267878],[-119.3500053,49.8265829],[-119.3493701,49.8180588],[-119.4046964,49.8163785],[-119.4045694,49.8099022],[-119.4101592,49.8099022],[-119.4102862,49.8072787],[-119.4319467,49.8069098],[-119.4322643,49.7907965],[-119.4459847,49.7905504],[-119.445286,49.7820201],[-119.4967376,49.7811587],[-119.4966105,49.7784927],[-119.5418371,49.7775082],[-119.5415892,49.7718277],[-119.5560296,49.7714941],[-119.5561194,49.7718422],[-119.5715704,49.7715086],[-119.5716153,49.7717262],[-119.5819235,49.7714941],[-119.5820133,49.7717697],[-119.5922991,49.7715231],[-119.592344,49.7718132],[-119.6003839,49.7715957],[-119.6011924,49.7839081],[-119.5864365,49.7843863],[-119.5867318,49.7928087]]],"overlay":true},{"id":"landsat_233055","name":"Landsat 233055","type":"tms","template":"http://{switch:a,b,c,d}.tile.paulnorman.ca/landsat_233055/{zoom}/{x}/{y}.png","description":"Recent Landsat imagery","scaleExtent":[5,14],"polygon":[[[-60.8550011,6.1765004],[-60.4762612,7.9188291],[-62.161689,8.2778675],[-62.5322549,6.5375488],[-60.8550011,6.1765004]]]},{"id":"landsat_047026","name":"Latest southwest British Columbia Landsat","type":"tms","template":"http://{switch:a,b,c,d}.tile.paulnorman.ca/landsat_047026/{zoom}/{x}/{y}.png","description":"Recent lower-resolution landsat imagery for southwest British Columbia","scaleExtent":[5,13],"polygon":[[[-121.9355512,47.7820648],[-121.5720582,48.6410125],[-121.2015461,49.4846247],[-121.8375516,49.6023246],[-122.4767046,49.7161735],[-123.118912,49.8268824],[-123.760228,49.9335836],[-124.0887706,49.0870469],[-124.4128889,48.2252567],[-123.792772,48.1197334],[-123.1727942,48.0109592],[-122.553553,47.8982299],[-121.9355512,47.7820648]]]},{"id":"ORT10LT","name":"Lithuania - NŽT ORT10LT","type":"tms","template":"http://mapproxy.openmap.lt/ort10lt/g/{zoom}/{x}/{y}.jpeg","scaleExtent":[4,18],"polygon":[[[26.2138385,55.850748],[26.3858298,55.7045315],[26.6303618,55.6806692],[26.6205349,55.5689227],[26.5242191,55.5099228],[26.5541476,55.388833],[26.4399286,55.3479351],[26.7919694,55.3212027],[26.8291304,55.2763488],[26.7434625,55.2539863],[26.6764846,55.158828],[26.4611191,55.1285624],[26.3577434,55.1505399],[26.2296342,55.1073177],[26.2713814,55.0775905],[26.2085126,54.997414],[26.0619117,54.9416094],[25.8578176,54.9276001],[25.7429827,54.8150641],[25.7626083,54.5769013],[25.5319352,54.3418175],[25.6771618,54.3238109],[25.7857293,54.2336242],[25.7858844,54.1550594],[25.5550843,54.1461918],[25.5109462,54.1750267],[25.5896725,54.2285838],[25.5136246,54.3078472],[25.2689287,54.2744706],[25.0705963,54.1336282],[24.9573726,54.1720575],[24.8133801,54.144862],[24.7790172,54.0999054],[24.8712786,54.034904],[24.819568,53.9977218],[24.6845912,53.9621091],[24.697865,54.0171421],[24.6259068,54.0105048],[24.4342619,53.9014424],[24.3520594,53.8967893],[24.2016059,53.9700069],[23.9683341,53.9266977],[23.9130177,53.9696842],[23.7781192,53.8989169],[23.7097655,53.9394502],[23.5370435,53.9430702],[23.4822428,53.9893848],[23.5273356,54.0473482],[23.4858579,54.1532339],[23.3867851,54.224838],[23.0421216,54.3159745],[23.0102115,54.3827959],[22.8546899,54.4104029],[22.7919963,54.3633227],[22.7023421,54.4528985],[22.6838586,54.585972],[22.7489713,54.6319792],[22.7429727,54.7268221],[22.8866837,54.8135001],[22.8204005,54.9119829],[22.6424041,54.9713362],[22.5892361,55.070243],[22.080597,55.0244812],[22.0324081,55.084098],[21.9130671,55.0816838],[21.6491949,55.1808113],[21.5015124,55.1868198],[21.3843708,55.2936996],[21.2709829,55.2450059],[21.0983616,55.2563884],[20.9421741,55.282453],[21.0863466,55.5618266],[21.0399547,55.8363584],[21.0640261,56.0699542],[21.2047804,56.0811668],[21.2307958,56.1623302],[21.5021038,56.2954952],[21.7235874,56.3138211],[21.8356623,56.37162],[21.9695397,56.3766515],[22.0153001,56.4242811],[22.4372717,56.406405],[22.6800028,56.3515884],[22.9191739,56.3790184],[22.9466759,56.4146477],[23.0932498,56.3046383],[23.1703443,56.3667721],[23.3064522,56.3830535],[23.5571715,56.3338187],[23.7647953,56.3733238],[23.7666897,56.3238079],[24.0189971,56.3297615],[24.1214631,56.2488984],[24.2857421,56.3006367],[24.4541496,56.2581579],[24.5794651,56.2882389],[24.6284061,56.3753322],[24.9023767,56.4805317],[25.1277405,56.2059091],[25.5771398,56.182414],[25.6731232,56.1493667],[26.2138385,55.850748]]],"terms_url":"http://www.geoportal.lt","terms_text":"NŽT ORT10LT","best":true},{"id":"mapbox_locator_overlay","name":"Locator Overlay","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/openstreetmap.map-inh76ba2/{zoom}/{x}/{y}.png?access_token=pk.eyJ1Ijoib3BlbnN0cmVldG1hcCIsImEiOiJncjlmd0t3In0.DmZsIeOW-3x-C5eX-wAqTw","description":"Shows major features to help orient you.","scaleExtent":[0,16],"overzoom":false,"terms_url":"http://www.mapbox.com/about/maps/","terms_text":"Terms & Feedback","default":true,"overlay":true},{"id":"londrina2011","name":"Londrina Ortofoto 2011","type":"tms","template":"https://siglon.londrina.pr.gov.br/arcgis/rest/services/Imagens/Ortofotos_2011_Paranacidade/MapServer/WMTS/tile/1.0.0/Imagens_Ortofotos_2011_Paranacidade/default/GoogleMapsCompatible/{zoom}/{y}/{x}","polygon":[[[-51.10903142008701,-23.392750890870328],[-51.110147219037096,-23.39111628244602],[-51.111981850003126,-23.389599820448623],[-51.11358044657587,-23.38976722295012],[-51.120999436701226,-23.38592675938185],[-51.12224934611127,-23.385109415587607],[-51.12483499560139,-23.383504255873166],[-51.12538216624037,-23.38186953335707],[-51.12482426676533,-23.37770385409619],[-51.12445948633935,-23.375054689723584],[-51.124373655650885,-23.372297138974446],[-51.12244246516032,-23.37032742475139],[-51.12302182230749,-23.366427304263887],[-51.128557901713755,-23.36548180323493],[-51.12832186732048,-23.358843408308623],[-51.12477062258506,-23.35475580404945],[-51.12703440699343,-23.35091432623551],[-51.12411616358548,-23.34679692655685],[-51.12025378260435,-23.347811512977742],[-51.1176466754421,-23.33969460448754],[-51.11264703783877,-23.341290443649072],[-51.109396200513004,-23.33488726938344],[-51.10756156954697,-23.334089313725826],[-51.10485790286019,-23.333980949007543],[-51.10252974543546,-23.334187827029368],[-51.09986899409291,-23.331015661953632],[-51.09801290545476,-23.329360589233605],[-51.09998701128955,-23.32830645478855],[-51.10322711977927,-23.325321337105603],[-51.10472915682748,-23.323193291476684],[-51.104664783811145,-23.321291814470847],[-51.10514758143378,-23.318444474199904],[-51.1063599399084,-23.3157547161216],[-51.10660670313775,-23.31467091543279],[-51.11050127062705,-23.311665785493048],[-51.111584883068964,-23.30842411016493],[-51.099504213666904,-23.309468549142686],[-51.09740136179941,-23.308631027972474],[-51.09511611971892,-23.307448636164267],[-51.09201548609798,-23.3049360186679],[-51.09036324534495,-23.3037141796735],[-51.09204767260616,-23.29874787986134],[-51.09269140276969,-23.297496421894902],[-51.09407542262125,-23.292953629109174],[-51.10073802981369,-23.293318240761657],[-51.10101697955121,-23.28870632248831],[-51.10068438563339,-23.28837126237015],[-51.10084531817427,-23.28777997775132],[-51.09937546763423,-23.28663682004102],[-51.09631774935752,-23.277914991984613],[-51.10285161051725,-23.273016720553397],[-51.10835550341534,-23.27033590016574],[-51.11309764895328,-23.268404099092194],[-51.13160489115448,-23.265338785827712],[-51.13188384089201,-23.262007272160396],[-51.1317336371872,-23.255058136908826],[-51.13290308031759,-23.254683563301587],[-51.132956724497895,-23.250750476893938],[-51.13473771128364,-23.2512729236245],[-51.13533852610292,-23.25133206840842],[-51.13516686472599,-23.24359373640034],[-51.13534925493897,-23.24117849627157],[-51.137516479822814,-23.24219388826517],[-51.13884685549409,-23.243495156026544],[-51.14108918223035,-23.24521044413634],[-51.1471724322756,-23.243179698340864],[-51.14761231455401,-23.23828015040167],[-51.149082165094036,-23.235884531292832],[-51.14976881060179,-23.236811236789336],[-51.15138886484666,-23.23853646924079],[-51.15289090189487,-23.238842079520833],[-51.15383503946804,-23.238950521710013],[-51.15820167574391,-23.238142132361276],[-51.16045473131624,-23.238161849232945],[-51.160347442955654,-23.24658068718069],[-51.15912435564498,-23.2478326235554],[-51.16131303820094,-23.247773477219496],[-51.166591625541805,-23.245939927797],[-51.17193458589902,-23.245821633420345],[-51.17205260309565,-23.249557713480034],[-51.174241285651625,-23.248404370116877],[-51.17514250788055,-23.2493211310392],[-51.176859121649926,-23.248157927934038],[-51.179466228812196,-23.251686936561047],[-51.18135450395853,-23.253806268366073],[-51.18273852381009,-23.253628837227893],[-51.18378994974384,-23.253264116924615],[-51.18495939287424,-23.253303546194683],[-51.18626831087339,-23.252150235227905],[-51.18665454897149,-23.247477745146526],[-51.191182117788244,-23.249143693933142],[-51.19141815218154,-23.252859966234126],[-51.19369266542598,-23.252781107419985],[-51.1938428691308,-23.26073575534214],[-51.20096681627374,-23.26054847664639],[-51.20126722368338,-23.24259807127726],[-51.209936123218775,-23.242775517090898],[-51.21090171846407,-23.26988252079656],[-51.21968863519614,-23.27221839365197],[-51.225965004290465,-23.2745345140599],[-51.22934458764894,-23.27860487489667],[-51.234515886629225,-23.28160089636689],[-51.23497722657975,-23.283246708422755],[-51.235073786104266,-23.285444377831148],[-51.23371122392482,-23.285897704227196],[-51.232155542696304,-23.28801649191402],[-51.22870085748543,-23.292293383844925],[-51.227402668322334,-23.294599300809004],[-51.22679112466699,-23.295476327114592],[-51.225600223864475,-23.29657013833941],[-51.22392652543933,-23.297210654251764],[-51.220482569064515,-23.30072850975029],[-51.21863720926242,-23.301300029310937],[-51.21668456109974,-23.30211788923888],[-51.21423838647836,-23.30441378240661],[-51.210966091480465,-23.306965823153238],[-51.22328279527583,-23.318296686707587],[-51.224387865389886,-23.31459209321986],[-51.22521398576639,-23.312887551432937],[-51.22511742624187,-23.312582111000477],[-51.22521398576639,-23.312513140483127],[-51.2255251220121,-23.312532846348883],[-51.22595427545445,-23.312385052284572],[-51.22616885217561,-23.31183328632629],[-51.22935531648505,-23.314887676277397],[-51.22802494081377,-23.31661189768144],[-51.227885465945,-23.31901591762422],[-51.22767088922384,-23.320227763653186],[-51.22723100694544,-23.321508564518947],[-51.2273919394863,-23.322227778055023],[-51.22725246461755,-23.322848466059934],[-51.230331640566384,-23.325577488448165],[-51.23046038659909,-23.326710459617892],[-51.229537706698046,-23.32789268010374],[-51.229162197436,-23.330503379743732],[-51.229290943468705,-23.33178408156439],[-51.22681258233914,-23.334473515196468],[-51.2260186484708,-23.336571826694826],[-51.22473118814376,-23.33839427691611],[-51.22210262330938,-23.340226553005806],[-51.22257469209598,-23.34196029634743],[-51.22380850824271,-23.343388647432523],[-51.22384069475089,-23.345309509145306],[-51.22440932306201,-23.347003784611864],[-51.2245380690947,-23.348294177581966],[-51.22404454263601,-23.34968305981433],[-51.22350810083308,-23.35010661675208],[-51.22381923707877,-23.35076657486812],[-51.22304676088255,-23.35174173085325],[-51.22259614976809,-23.35296312824164],[-51.22586844476598,-23.35480505304304],[-51.22650144609346,-23.36705763453823],[-51.22354028734128,-23.369145582171885],[-51.22366903337377,-23.37968330666716],[-51.220375280703756,-23.381633186264455],[-51.216469984378406,-23.38170212087667],[-51.21416328462579,-23.379949201028825],[-51.2092816642191,-23.37395167630701],[-51.20738266023672,-23.368141007697016],[-51.20628831895872,-23.36723491438801],[-51.20472190889416,-23.366269721227162],[-51.198230963078665,-23.366683376299132],[-51.19297383340994,-23.366506095711998],[-51.18986247095292,-23.3654424072124],[-51.18806002649507,-23.36464463523902],[-51.18718026193825,-23.3645264463904],[-51.18579624208668,-23.363738518041337],[-51.183038931219606,-23.36359078095478],[-51.18071077379488,-23.3637582163071],[-51.179069261877906,-23.361581540240305],[-51.177642326682125,-23.35836078207346],[-51.16683838877106,-23.356262814974126],[-51.166141014427254,-23.358538073547532],[-51.16475699457568,-23.360389770338585],[-51.16076586756186,-23.359217688669915],[-51.15983245882475,-23.36660458495632],[-51.162042599052846,-23.36861374957437],[-51.16276143106877,-23.374158492021696],[-51.158448438973174,-23.37580315788644],[-51.155047397942575,-23.376305417047273],[-51.15396378550066,-23.37903334042617],[-51.15298746141932,-23.381052164536694],[-51.15118501696147,-23.382076336717283],[-51.149167995782435,-23.382509637949354],[-51.14721534761976,-23.382155118864866],[-51.14517686876862,-23.382588419839323],[-51.14410398516276,-23.38376029492248],[-51.14512322458833,-23.388083341091015],[-51.141797285410156,-23.389402876058366],[-51.14030597719799,-23.38880219385971],[-51.14068148646006,-23.391608636504017],[-51.14127157244328,-23.393538646762796],[-51.14093897852546,-23.394434713394368],[-51.140456180902824,-23.39536031431835],[-51.13939402613302,-23.395104297688697],[-51.13738773379004,-23.393154616350518],[-51.13608954462695,-23.389796764546077],[-51.13428710016909,-23.389757375749994],[-51.132162790629465,-23.390072485790583],[-51.13172290835106,-23.39285920758337],[-51.12259266886514,-23.38864463742227],[-51.12228153261944,-23.391657871809155],[-51.11882684740854,-23.393174310244916],[-51.115683298443365,-23.393351555162592],[-51.10903142008701,-23.392750890870328]],[[-51.13829432042955,-23.41600741009485],[-51.133310776080314,-23.418665600378624],[-51.132087688769644,-23.416440600302334],[-51.13002238782791,-23.418291487939495],[-51.12868664773901,-23.419010176689888],[-51.12824140104259,-23.42102839134528],[-51.12696466955051,-23.421860280620358],[-51.12532852205271,-23.422692164660027],[-51.1244541219139,-23.420969322085504],[-51.1215144208339,-23.424109801147612],[-51.12063465627703,-23.423268081315832],[-51.11970661195797,-23.423120410617486],[-51.11977098497433,-23.42156985833077],[-51.1188000253111,-23.421545246243184],[-51.11643431696008,-23.420836416154565],[-51.11942766222045,-23.419167696990424],[-51.11787198099193,-23.416775337218567],[-51.116546969738685,-23.41730697646229],[-51.115699391690086,-23.415702207051474],[-51.115120034542905,-23.413088261827834],[-51.119078975048524,-23.411114231305813],[-51.119599323597356,-23.41169512115064],[-51.12052200349841,-23.41489489238112],[-51.12147686990764,-23.417139608782644],[-51.12308619531643,-23.418626220171642],[-51.12754939111684,-23.41653905242448],[-51.12803218873949,-23.417395582795194],[-51.13119719537679,-23.415574218468866],[-51.13080022844262,-23.414766903017576],[-51.13278506311348,-23.41264029239725],[-51.13521514448077,-23.411055157619415],[-51.13585887464424,-23.410956701416854],[-51.13682446988958,-23.411188073376714],[-51.137205343569626,-23.411576974270133],[-51.13730190309418,-23.41324086645236],[-51.137430649126884,-23.414707830961888],[-51.13829432042955,-23.41600741009485]],[[-51.18929065852,-23.61469318354],[-51.18868716149,-23.61385268133],[-51.18817754178,-23.61338573333],[-51.18731118826,-23.61301708899],[-51.18628926663,-23.61314488581],[-51.18401743559,-23.61395590119],[-51.18348904042,-23.61396573165],[-51.18183143525,-23.61283522407],[-51.18140496401,-23.61344471632],[-51.18062980561,-23.61313505529],[-51.18001021533,-23.61409352754],[-51.17865838198,-23.61328742827],[-51.18064589886,-23.61060367181],[-51.17972321896,-23.61018095058],[-51.18061639456,-23.60849005203],[-51.1821157494,-23.60850479833],[-51.18260927586,-23.60775273479],[-51.18319936184,-23.60804274673],[-51.18415154605,-23.60627808786],[-51.18511177687,-23.60666149766],[-51.18649043231,-23.60469528171],[-51.18902243762,-23.60610112912],[-51.18821241049,-23.60741848294],[-51.18918873458,-23.60801816947],[-51.188899056,-23.60953211999],[-51.18962325244,-23.60992535103],[-51.1911896625,-23.6111935131],[-51.1901489654,-23.61244691705],[-51.19054056792,-23.6127565797],[-51.19029380469,-23.61377895281],[-51.18929065852,-23.61469318354]],[[-51.08005769639,-23.52984412096],[-51.07962317853,-23.52205317842],[-51.08468182473,-23.52194496764],[-51.08581908135,-23.52404030606],[-51.0858941832,-23.52703569673],[-51.08579494147,-23.52777346722],[-51.08530141501,-23.52806365581],[-51.08513511805,-23.52856533627],[-51.08512438922,-23.52981952906],[-51.08470864682,-23.53023759067],[-51.08343459754,-23.53023759067],[-51.08329512267,-23.52978018202],[-51.08005769639,-23.52984412096]]],"terms_url":"http://siglon.londrina.pr.gov.br/","terms_text":"Prefeitura do Londrinas, PR"},{"id":"NSW_LPI_BaseMap","name":"LPI NSW Base Map","type":"tms","template":"https://maps.six.nsw.gov.au/arcgis/rest/services/public/NSW_Base_Map/MapServer/tile/{zoom}/{y}/{x}","scaleExtent":[0,19],"polygon":[[[140.9948644,-28.952966],[148.9611382,-28.8997729],[148.9870097,-28.4862285],[151.013609,-28.4786485],[151.1084711,-28.7032909],[151.8759917,-28.683118],[151.9334839,-28.4078753],[152.25544,-28.2332683],[153.0660798,-28.2104723],[153.1408196,-28.1090981],[153.4735137,-28.1164808],[153.3576523,-27.693606],[159.4938303,-27.699252],[159.4856997,-37.8474137],[149.5256879,-37.8281502],[149.9159578,-37.4869999],[148.0485886,-36.8131741],[147.9680996,-36.1567945],[146.7147701,-36.2866613],[145.3004625,-36.1567945],[144.5300673,-36.1475101],[142.8397973,-35.0254303],[142.356863,-34.7802471],[141.9774146,-34.4016159],[140.9950258,-34.1371824],[140.9948644,-28.952966]]],"terms_url":"http://spatialservices.finance.nsw.gov.au/mapping_and_imagery/lpi_web_services","terms_text":"© Land and Property Information 2016"},{"id":"NSW_LPI_Imagery","name":"LPI NSW Imagery","type":"tms","template":"https://maps.six.nsw.gov.au/arcgis/rest/services/public/NSW_Imagery/MapServer/tile/{zoom}/{y}/{x}","scaleExtent":[0,21],"polygon":[[[140.9868688,-28.9887829],[148.9951472,-28.9727491],[148.9966717,-28.4915066],[151.0029027,-28.4930697],[151.0029027,-28.7261663],[151.4915093,-28.7323921],[151.4918687,-28.7155337],[151.9228213,-28.719635],[151.9251607,-28.4897139],[151.9955886,-28.4898718],[151.9989947,-28.1192742],[152.4967606,-28.122091],[152.4968241,-28.1146398],[153.0044563,-28.1154389],[153.0044563,-28.120397],[153.5038629,-28.119345],[153.5039264,-28.1227063],[153.5919395,-28.1223619],[153.5926582,-28.1776872],[153.6111186,-28.1757867],[153.6113881,-28.1825173],[153.7426846,-28.2162084],[153.7787253,-28.710911],[152.6237954,-32.5877239],[152.3123961,-32.6328837],[151.4141942,-33.5790388],[150.8929925,-35.2648721],[150.4620695,-35.7777256],[150.0156501,-37.5103569],[149.9918121,-37.5126787],[149.519778,-37.5130704],[149.5199577,-37.5216919],[149.4462958,-37.5353701],[149.063344,-37.5357975],[148.9836635,-37.5217631],[148.9816872,-37.5191982],[148.9863847,-37.2584972],[148.4875376,-37.265846],[148.4824774,-37.0092669],[147.994386,-37.014339],[147.988288,-36.5332184],[147.9529707,-36.5260725],[147.9486513,-36.0685992],[147.5034997,-36.0716798],[147.5047701,-36.2651047],[146.4919996,-36.266129],[146.4922536,-36.2565],[145.9929826,-36.2534267],[145.9965866,-36.0188147],[145.9831568,-36.0187058],[145.9624506,-36.0219026],[145.946236,-36.0120936],[145.9454275,-36.0060259],[145.5041534,-36.0013564],[145.5037941,-36.0109125],[145.0072008,-36.0036213],[145.0035404,-36.1520424],[144.4860806,-36.1423149],[144.4874127,-36.0137522],[143.9874676,-36.0024134],[143.9932853,-35.5723753],[143.4971691,-35.5837101],[143.4917967,-35.4065648],[143.4613438,-35.3674934],[143.4585591,-35.3555888],[143.4897755,-35.3396522],[143.4895509,-35.332214],[143.4316994,-35.2570613],[143.2505542,-35.2606556],[143.2438356,-35.0132729],[142.9933305,-35.0177207],[142.9919767,-34.7961882],[142.4971375,-34.8032323],[142.4973172,-34.8007613],[142.4211401,-34.8017571],[142.4209155,-34.7838306],[142.2330892,-34.7859191],[142.2307707,-34.7807542],[142.2269959,-34.5061271],[141.9975302,-34.5083733],[141.9945959,-34.2526687],[141.4982345,-34.2556921],[141.498171,-34.2522794],[140.9945397,-34.2528411],[140.9868688,-28.9887829]]],"terms_url":"http://spatialservices.finance.nsw.gov.au/mapping_and_imagery/lpi_web_services","terms_text":"© Land and Property Information 2016","best":true},{"id":"NSW_LPI_TopographicMap","name":"LPI NSW Topographic Map","type":"tms","template":"https://maps.six.nsw.gov.au/arcgis/rest/services/public/NSW_Topo_Map/MapServer/tile/{zoom}/{y}/{x}","scaleExtent":[0,16],"polygon":[[[140.9988422,-28.9992444],[148.9502438,-28.9993736],[148.9498845,-28.9665265],[148.9998308,-28.9665265],[149.0000917,-28.8165829],[149.1000729,-28.8165829],[149.0997046,-28.7488533],[148.9998504,-28.7497444],[148.9998169,-28.5000304],[151.0000514,-28.5005192],[151.0005904,-28.7325849],[151.0239466,-28.7327424],[151.0241262,-28.7418794],[151.0329297,-28.7418794],[151.033828,-28.7505431],[151.999984,-28.7495314],[151.999984,-28.7164478],[152.0334014,-28.7166053],[152.0332217,-28.683196],[152.0000739,-28.6833537],[151.9998769,-28.6416273],[151.9829886,-28.6413908],[151.9831683,-28.624912],[151.9331321,-28.6247543],[151.9334122,-28.500071],[151.9998875,-28.5002289],[151.9998556,-28.3749591],[152.2499739,-28.3750718],[152.2499356,-28.2500066],[152.9997192,-28.2498563],[152.9998989,-28.2832447],[153.1165002,-28.2834029],[153.11659,-28.2498563],[153.1666262,-28.2500146],[153.166716,-28.2331582],[153.2499898,-28.2332373],[153.2500265,-28.1249689],[153.6249628,-28.1250833],[153.6248398,-28.4999134],[153.7497955,-28.4999924],[153.7495877,-28.7497976],[153.6248117,-28.7501127],[153.6249745,-28.9999333],[153.4997672,-29.0000612],[153.4998417,-29.4995077],[153.3747962,-29.500055],[153.3754111,-29.8750302],[153.4999113,-29.8751403],[153.4999113,-30.0000922],[153.2498947,-29.9997621],[153.250025,-30.1917704],[153.2748185,-30.1916151],[153.2748185,-30.2168467],[153.2166077,-30.2166139],[153.2166077,-30.250065],[153.250025,-30.250065],[153.2497502,-30.3751935],[153.1243608,-30.3749743],[153.1246457,-30.6250359],[153.0331676,-30.6250482],[153.0333884,-30.8750837],[153.1249214,-30.8750291],[153.1249344,-31.1250505],[153.0082433,-31.1249736],[153.0082914,-31.2499759],[153.0000019,-31.250003],[152.9999392,-31.6249919],[152.8749386,-31.6250491],[152.8749572,-31.749954],[152.7832899,-31.7500034],[152.7831966,-31.8748579],[152.749914,-31.8750105],[152.7500397,-32.0000207],[152.6249044,-31.9999446],[152.6249078,-32.5000047],[152.4999757,-32.4999569],[152.5000336,-32.5666443],[152.4166699,-32.5663415],[152.4167598,-32.6249954],[152.3498477,-32.624991],[152.3498477,-32.6332294],[152.2830786,-32.6332218],[152.2832583,-32.6249755],[152.2494816,-32.6249755],[152.2498101,-32.874906],[151.8745693,-32.8750443],[151.8748535,-33.0000091],[151.7497706,-33.0001533],[151.7504669,-33.2500398],[151.6252418,-33.2497393],[151.6250828,-33.3751621],[151.499585,-33.3751442],[151.5003127,-33.6249385],[151.3741466,-33.6243658],[151.3727902,-34.001962],[151.2477819,-34.0011194],[151.2477819,-34.2493114],[150.9957327,-34.2501515],[151.0008143,-34.62483],[150.8717407,-34.6265026],[150.872757,-35.1242738],[150.7670589,-35.1234425],[150.7690916,-35.2463774],[150.6257894,-35.2496974],[150.6280314,-35.3751485],[150.4999742,-35.3751485],[150.4959088,-35.6275034],[150.3719169,-35.6250251],[150.3749658,-35.7537957],[150.2672351,-35.7513213],[150.2652024,-35.8741232],[150.2479249,-35.870829],[150.2458922,-36.374885],[150.1229166,-36.374885],[150.1259656,-36.6224345],[150.0253491,-36.6240658],[150.0283981,-36.7471337],[149.9928266,-36.7495768],[150.0040062,-37.1224477],[150.0588879,-37.1273097],[150.0568553,-37.37809],[149.9979083,-37.3732441],[149.9999409,-37.4830073],[149.987745,-37.4846202],[149.9857123,-37.5080043],[148.0684571,-36.80624],[147.9930603,-36.1379955],[147.8148345,-36.0055567],[147.3893924,-36.0113701],[147.3822059,-36.1310306],[146.9972549,-36.1275479],[146.9886311,-36.2528271],[146.4956356,-36.2447132],[146.5042595,-36.126387],[145.0011817,-36.0079505],[145.0154103,-36.2542074],[144.5072465,-36.2476506],[144.4991158,-36.0211037],[143.9965422,-35.9810531],[143.3382568,-35.2331794],[142.4097581,-34.7669434],[142.0361436,-34.3758837],[140.9965216,-34.1385805],[140.9988422,-28.9992444]]],"terms_url":"http://spatialservices.finance.nsw.gov.au/mapping_and_imagery/lpi_web_services","terms_text":"© Land and Property Information 2016"},{"id":"Mapbox","name":"Mapbox Satellite","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/openstreetmap.map-inh7ifmo/{zoom}/{x}/{y}.png?access_token=pk.eyJ1Ijoib3BlbnN0cmVldG1hcCIsImEiOiJncjlmd0t3In0.DmZsIeOW-3x-C5eX-wAqTw","description":"Satellite and aerial imagery.","scaleExtent":[0,19],"terms_url":"http://www.mapbox.com/about/maps/","terms_text":"Terms & Feedback","default":true},{"id":"geodata.md.gov-MD_SixInchImagery","name":"MD Latest 6 Inch Aerial Imagery","type":"tms","template":"http://whoots.mapwarper.net/tms/{zoom}/{x}/{y}/MD_SixInchImagery/http://geodata.md.gov/imap/services/Imagery/MD_SixInchImagery/MapServer/WmsServer","description":"Six Inch resolution aerial imagery for the State of Maryland","scaleExtent":[0,20],"polygon":[[[-76.234131,37.920368],[-76.598053,38.158317],[-76.940002,38.270532],[-77.038193,38.413786],[-77.23526,38.33627],[-77.312164,38.410558],[-77.262726,38.566422],[-77.042999,38.713376],[-77.049866,38.793697],[-76.92627,38.892503],[-77.040939,38.984499],[-77.12162,38.925229],[-77.150116,38.955137],[-77.252426,38.975425],[-77.259293,39.024252],[-77.34581,39.054918],[-77.461853,39.070379],[-77.537384,39.139647],[-77.474213,39.224807],[-77.572746,39.304284],[-77.723465,39.328986],[-77.777023,39.463234],[-77.861481,39.516225],[-77.840881,39.608862],[-77.956238,39.59299],[-78.166351,39.695564],[-78.270035,39.621557],[-78.338699,39.640066],[-78.466415,39.523641],[-78.662796,39.540058],[-78.798752,39.606217],[-78.9814,39.446799],[-79.06723,39.476486],[-79.485054,39.199536],[-79.485569,39.72158],[-75.788359,39.721811],[-75.690994,38.460579],[-75.049238,38.458159],[-75.049839,38.402218],[-75.081511,38.323208],[-75.097733,38.309066],[-75.186996,38.097551],[-75.23798,38.022402],[-75.61821,37.989669],[-75.863686,37.909534],[-76.234131,37.920368]]],"terms_url":"http://imap.maryland.gov/Pages/imagery-products.aspx","terms_text":"DoIT, MD iMap, MDP"},{"id":"geodata.md.gov-MD_ColorBasemap","name":"MD Transportation Basemap","type":"tms","template":"http://whoots.mapwarper.net/tms/{zoom}/{x}/{y}/MD_ColorBasemap/http://geodata.md.gov/imap/services/Transportation/MD_ColorBasemap/MapServer/WmsServer","description":"Maryland State Highway Administration road features and additional Maryland focused landmarks","polygon":[[[-76.234131,37.920368],[-76.598053,38.158317],[-76.940002,38.270532],[-77.038193,38.413786],[-77.23526,38.33627],[-77.312164,38.410558],[-77.262726,38.566422],[-77.042999,38.713376],[-77.049866,38.793697],[-76.92627,38.892503],[-77.040939,38.984499],[-77.12162,38.925229],[-77.150116,38.955137],[-77.252426,38.975425],[-77.259293,39.024252],[-77.34581,39.054918],[-77.461853,39.070379],[-77.537384,39.139647],[-77.474213,39.224807],[-77.572746,39.304284],[-77.723465,39.328986],[-77.777023,39.463234],[-77.861481,39.516225],[-77.840881,39.608862],[-77.956238,39.59299],[-78.166351,39.695564],[-78.270035,39.621557],[-78.338699,39.640066],[-78.466415,39.523641],[-78.662796,39.540058],[-78.798752,39.606217],[-78.9814,39.446799],[-79.06723,39.476486],[-79.485054,39.199536],[-79.485569,39.72158],[-75.788359,39.721811],[-75.690994,38.460579],[-75.049238,38.458159],[-75.049839,38.402218],[-75.081511,38.323208],[-75.097733,38.309066],[-75.186996,38.097551],[-75.23798,38.022402],[-75.61821,37.989669],[-75.863686,37.909534],[-76.234131,37.920368]]],"terms_url":"http://imap.maryland.gov/Pages/imagery-products.aspx","terms_text":"DoIT, MD iMap, MDP"},{"id":"New_and_Misaligned_TIGER_Roads-2013","name":"New & Misaligned TIGER Roads","type":"tms","template":"http://{switch:a,b,c}.tiles.mapbox.com/v4/enf.e0b8291e/{zoom}/{x}/{y}.png?access_token=pk.eyJ1Ijoib3BlbnN0cmVldG1hcCIsImEiOiJhNVlHd29ZIn0.ti6wATGDWOmCnCYen-Ip7Q","description":"At zoom level 16+, public domain map data from the US Census. At lower zooms, only changes since 2006 minus changes already incorporated into OpenStreetMap","scaleExtent":[0,22],"polygon":[[[-124.7617886,48.4130148],[-124.6059492,45.90245],[-124.9934269,40.0557614],[-122.5369737,36.8566086],[-119.9775867,33.0064099],[-117.675935,32.4630223],[-114.8612307,32.4799891],[-111.0089311,31.336015],[-108.1992687,31.3260016],[-108.1871123,31.7755116],[-106.5307225,31.7820947],[-106.4842052,31.7464455],[-106.429317,31.7520583],[-106.2868855,31.5613291],[-106.205248,31.446704],[-105.0205259,30.5360988],[-104.5881916,29.6997856],[-103.2518856,28.8908685],[-102.7173632,29.3920567],[-102.1513983,29.7475702],[-101.2552871,29.4810523],[-100.0062436,28.0082173],[-99.2351068,26.4475962],[-98.0109067,25.9928035],[-97.435024,25.8266009],[-96.9555259,25.9821589],[-96.8061741,27.7978168],[-95.5563349,28.5876066],[-93.7405308,29.4742093],[-90.9028456,28.8564513],[-88.0156706,28.9944338],[-88.0162494,30.0038862],[-86.0277506,30.0047454],[-84.0187909,28.9961781],[-81.9971976,25.9826768],[-81.9966618,25.0134917],[-84.0165592,25.0125783],[-84.0160068,24.0052745],[-80.0199985,24.007096],[-79.8901116,26.8550713],[-80.0245309,32.0161282],[-75.4147385,35.0531894],[-74.0211163,39.5727927],[-72.002019,40.9912464],[-69.8797398,40.9920457],[-69.8489304,43.2619916],[-66.9452845,44.7104937],[-67.7596632,47.0990024],[-69.2505131,47.5122328],[-70.4614886,46.2176574],[-71.412273,45.254878],[-72.0222508,45.0059846],[-75.0798841,44.9802854],[-76.9023061,43.8024568],[-78.7623935,43.6249578],[-79.15798,43.4462589],[-79.0060087,42.8005317],[-82.662475,41.6889458],[-82.1761642,43.588535],[-83.2813977,46.138853],[-87.5064535,48.0142702],[-88.3492194,48.2963271],[-89.4353148,47.9837822],[-93.9981078,49.0067142],[-95.1105379,49.412004],[-96.0131199,49.0060547],[-123.3228926,49.0042878],[-123.2275233,48.1849927],[-124.7617886,48.4130148]],[[-160.5787616,22.5062947],[-160.5782192,21.4984647],[-158.7470604,21.2439843],[-157.5083185,20.995803],[-155.9961942,18.7790194],[-154.6217803,18.7586966],[-154.6890176,19.8805722],[-156.2927622,21.2225888],[-157.5047384,21.9984962],[-159.0093692,22.5070181],[-160.5787616,22.5062947]],[[-167.1571546,68.721974],[-164.8553982,67.0255078],[-168.002195,66.0017503],[-169.0087448,66.001546],[-169.0075381,64.9987675],[-172.5143281,63.8767267],[-173.8197023,59.74014],[-162.5018149,58.0005815],[-160.0159024,58.0012389],[-160.0149725,57.000035],[-160.5054788,56.9999017],[-165.8092575,54.824847],[-178.000097,52.2446469],[-177.9992996,51.2554252],[-171.4689067,51.8215329],[-162.40251,53.956664],[-159.0075717,55.002502],[-158.0190709,55.0027849],[-151.9963213,55.9991902],[-151.500341,57.9987853],[-151.5012894,58.9919816],[-138.5159989,58.9953194],[-138.5150471,57.9986434],[-133.9948193,54.0031685],[-130.0044418,54.0043387],[-130.0070826,57.0000507],[-131.975877,56.9995156],[-135.1229873,59.756601],[-138.0071813,59.991805],[-139.1715881,60.4127229],[-140.9874011,61.0118551],[-140.9683975,69.9535069],[-156.176891,71.5633329],[-160.413634,70.7397728],[-163.0218273,69.9707435],[-164.9717003,68.994689],[-167.1571546,68.721974]]],"overlay":true},{"id":"geodata.state.nj.us-Infrared2015","name":"NJ 2015 Aerial Imagery (Infrared)","type":"tms","template":"http://whoots.mapwarper.net/tms/{zoom}/{x}/{y}/Infrared2015/http://geodata.state.nj.us/imagerywms/Infrared2015","description":"Digital orthophotography of New Jersey, Near Infrared, 1 foot resolution","scaleExtent":[0,20],"polygon":[[[-74.86599,40.085427],[-74.840927,40.107225],[-74.822903,40.130329],[-74.788055,40.124685],[-74.726086,40.149488],[-74.729176,40.16392],[-74.763336,40.191725],[-74.775524,40.214276],[-74.844017,40.247957],[-74.868393,40.291573],[-74.944611,40.33817],[-74.967098,40.395195],[-75.002632,40.406046],[-75.026836,40.402516],[-75.06134,40.416502],[-75.074215,40.455046],[-75.069065,40.536503],[-75.102367,40.567024],[-75.135927,40.573609],[-75.16777,40.559069],[-75.197639,40.573674],[-75.203733,40.618318],[-75.205064,40.691312],[-75.198326,40.753889],[-75.172405,40.780671],[-75.1367,40.777292],[-75.090179,40.822383],[-75.100994,40.839269],[-75.096874,40.850956],[-75.068464,40.850372],[-75.057049,40.867574],[-75.13773,40.973094],[-75.135155,40.994411],[-75.039024,41.03819],[-74.981518,41.112598],[-74.905472,41.170384],[-74.84024,41.278645],[-74.798012,41.322685],[-74.757156,41.347691],[-74.695702,41.360576],[-74.041054,41.059088],[-74.041051,41.059087],[-74.04105,41.059087],[-74.04105,41.059086],[-74.041049,41.059086],[-73.890266,40.998039],[-73.933406,40.882078],[-73.933407,40.882077],[-73.933408,40.882076],[-73.933408,40.882075],[-74.011459,40.75558],[-74.024543,40.709436],[-74.066048,40.651732],[-74.152222,40.638967],[-74.183121,40.644568],[-74.200459,40.631281],[-74.199257,40.598444],[-74.21505,40.558026],[-74.246807,40.548113],[-74.24715,40.519541],[-74.267578,40.489651],[-74.26054,40.469282],[-74.199257,40.445641],[-74.181061,40.460401],[-74.136429,40.459095],[-73.997555,40.413496],[-74.026566,40.47777],[-74.003906,40.484037],[-73.977814,40.452042],[-73.964767,40.33189],[-74.088364,39.756824],[-74.356842,39.383406],[-74.609528,39.215231],[-74.776382,38.998909],[-74.863586,38.931639],[-74.931221,38.920688],[-74.980316,38.930304],[-74.960747,39.00798],[-74.905472,39.100226],[-74.899979,39.164141],[-75.101166,39.201398],[-75.135498,39.171062],[-75.425949,39.378099],[-75.475044,39.43195],[-75.543365,39.457403],[-75.552292,39.482845],[-75.538902,39.541911],[-75.519676,39.56997],[-75.571175,39.608069],[-75.577698,39.625524],[-75.539932,39.656456],[-75.472984,39.747454],[-75.466253,39.750761],[-75.466252,39.750762],[-75.466252,39.750763],[-75.466251,39.750764],[-75.466251,39.750765],[-75.46625,39.750767],[-75.466249,39.750768],[-75.466249,39.750769],[-75.465088,39.764478],[-75.415041,39.801786],[-75.324669,39.858891],[-75.246048,39.864689],[-75.143738,39.900255],[-75.142365,39.957912],[-75.07061,39.987117],[-75.056534,40.008683],[-74.935341,40.072555],[-74.86599,40.085427]]],"terms_url":"https://njgin.state.nj.us/NJ_NJGINExplorer/ShowMetadata.jsp?docId={E30775F2-6370-4525-8E68-C371ED29BBB3}","terms_text":"NJ Office of Information Technology (NJOIT), Office of Geographic Information Systems (OGIS)"},{"id":"geodata.state.nj.us-Natural2015","name":"NJ 2015 Aerial Imagery (Natural Color)","type":"tms","template":"http://whoots.mapwarper.net/tms/{zoom}/{x}/{y}/Natural2015/http://geodata.state.nj.us/imagerywms/Natural2015","description":"Digital orthophotography of New Jersey, Natural Color, 1 foot resolution","scaleExtent":[0,20],"polygon":[[[-74.86599,40.085427],[-74.840927,40.107225],[-74.822903,40.130329],[-74.788055,40.124685],[-74.726086,40.149488],[-74.729176,40.16392],[-74.763336,40.191725],[-74.775524,40.214276],[-74.844017,40.247957],[-74.868393,40.291573],[-74.944611,40.33817],[-74.967098,40.395195],[-75.002632,40.406046],[-75.026836,40.402516],[-75.06134,40.416502],[-75.074215,40.455046],[-75.069065,40.536503],[-75.102367,40.567024],[-75.135927,40.573609],[-75.16777,40.559069],[-75.197639,40.573674],[-75.203733,40.618318],[-75.205064,40.691312],[-75.198326,40.753889],[-75.172405,40.780671],[-75.1367,40.777292],[-75.090179,40.822383],[-75.100994,40.839269],[-75.096874,40.850956],[-75.068464,40.850372],[-75.057049,40.867574],[-75.13773,40.973094],[-75.135155,40.994411],[-75.039024,41.03819],[-74.981518,41.112598],[-74.905472,41.170384],[-74.84024,41.278645],[-74.798012,41.322685],[-74.757156,41.347691],[-74.695702,41.360576],[-74.041054,41.059088],[-74.041051,41.059087],[-74.04105,41.059087],[-74.04105,41.059086],[-74.041049,41.059086],[-73.890266,40.998039],[-73.933406,40.882078],[-73.933407,40.882077],[-73.933408,40.882076],[-73.933408,40.882075],[-74.011459,40.75558],[-74.024543,40.709436],[-74.066048,40.651732],[-74.152222,40.638967],[-74.183121,40.644568],[-74.200459,40.631281],[-74.199257,40.598444],[-74.21505,40.558026],[-74.246807,40.548113],[-74.24715,40.519541],[-74.267578,40.489651],[-74.26054,40.469282],[-74.199257,40.445641],[-74.181061,40.460401],[-74.136429,40.459095],[-73.997555,40.413496],[-74.026566,40.47777],[-74.003906,40.484037],[-73.977814,40.452042],[-73.964767,40.33189],[-74.088364,39.756824],[-74.356842,39.383406],[-74.609528,39.215231],[-74.776382,38.998909],[-74.863586,38.931639],[-74.931221,38.920688],[-74.980316,38.930304],[-74.960747,39.00798],[-74.905472,39.100226],[-74.899979,39.164141],[-75.101166,39.201398],[-75.135498,39.171062],[-75.425949,39.378099],[-75.475044,39.43195],[-75.543365,39.457403],[-75.552292,39.482845],[-75.538902,39.541911],[-75.519676,39.56997],[-75.571175,39.608069],[-75.577698,39.625524],[-75.539932,39.656456],[-75.472984,39.747454],[-75.466253,39.750761],[-75.466252,39.750762],[-75.466252,39.750763],[-75.466251,39.750764],[-75.466251,39.750765],[-75.46625,39.750767],[-75.466249,39.750768],[-75.466249,39.750769],[-75.465088,39.764478],[-75.415041,39.801786],[-75.324669,39.858891],[-75.246048,39.864689],[-75.143738,39.900255],[-75.142365,39.957912],[-75.07061,39.987117],[-75.056534,40.008683],[-74.935341,40.072555],[-74.86599,40.085427]]],"terms_url":"https://njgin.state.nj.us/NJ_NJGINExplorer/ShowMetadata.jsp?docId={CDC67AB8-ADA1-4B4B-9087-67A82CB9151C}","terms_text":"NJ Office of Information Technology (NJOIT), Office of Geographic Information Systems (OGIS)"},{"id":"NLS-Bartholomew-hfinch-hist","name":"NLS - Bartholomew Half Inch, 1897-1907","type":"tms","template":"http://geo.nls.uk/mapdata2/bartholomew/great_britain/{zoom}/{x}/{-y}.png","scaleExtent":[0,15],"polygon":[[[-6.4585407,49.9044128],[-6.3872009,49.9841116],[-6.2296827,49.9896159],[-6.2171269,49.8680087],[-6.4551164,49.8591793],[-6.4585407,49.9044128]],[[-1.4495137,60.8634056],[-0.7167114,60.8545122],[-0.7349744,60.4359756],[-0.6938826,60.4168218],[-0.7258429,60.3942735],[-0.7395401,60.0484714],[-0.9267357,60.0461918],[-0.9381501,59.8266157],[-1.4586452,59.831205],[-1.4455187,60.0535999],[-1.463211,60.0535999],[-1.4643524,60.0630002],[-1.5716475,60.0638546],[-1.5693646,60.1790005],[-1.643558,60.1807033],[-1.643558,60.1892162],[-1.8216221,60.1894999],[-1.8204807,60.3615507],[-1.8415973,60.3697345],[-1.8216221,60.3832755],[-1.8179852,60.5934321],[-1.453168,60.5934321],[-1.4495137,60.8634056]],[[-4.9089213,54.4242078],[-4.282598,54.4429861],[-4.2535417,54.029769],[-4.8766366,54.0221831],[-4.9089213,54.4242078]],[[-5.8667408,59.1444603],[-5.7759966,59.1470945],[-5.7720016,59.1014052],[-5.8621751,59.0990605],[-5.8667408,59.1444603]],[[-1.7065887,59.5703599],[-1.5579165,59.5693481],[-1.5564897,59.4965695],[-1.7054472,59.4975834],[-1.7065887,59.5703599]],[[-7.6865827,58.2940975],[-7.5330594,58.3006957],[-7.5256401,58.2646905],[-7.6797341,58.2577853],[-7.6865827,58.2940975]],[[-4.5338281,59.0359871],[-4.481322,59.0371616],[-4.4796099,59.0186583],[-4.5332574,59.0180707],[-4.5338281,59.0359871]],[[-8.6710698,57.8769896],[-8.4673234,57.8897332],[-8.4467775,57.7907],[-8.6510947,57.7779213],[-8.6710698,57.8769896]],[[-5.2395519,50.3530581],[-5.7920073,50.3384899],[-5.760047,49.9317027],[-4.6551363,49.9581461],[-4.677965,50.2860073],[-4.244219,50.2801723],[-4.2487848,50.2042525],[-3.3812929,50.2042525],[-3.4223846,50.5188201],[-3.1164796,50.5246258],[-3.1210453,50.6579592],[-2.6736357,50.6619495],[-2.5953453,50.6394325],[-2.5905026,50.5728419],[-2.4791203,50.5733545],[-2.4758919,50.5066704],[-2.3967943,50.5056438],[-2.401637,50.5723293],[-1.0400296,50.5718167],[-1.0335726,50.7059289],[-0.549302,50.7038843],[-0.5460736,50.7886618],[-0.0924734,50.7856002],[-0.0876307,50.7181949],[0.4789659,50.7120623],[0.487037,50.8182467],[0.9761503,50.8049868],[0.9922927,51.0126311],[1.4491213,51.0004424],[1.4781775,51.4090372],[1.0229632,51.4271576],[1.035877,51.7640881],[1.6105448,51.7500992],[1.646058,52.1560003],[1.7267698,52.1540195],[1.749369,52.4481811],[1.7870672,52.4811624],[1.759102,52.522505],[1.7933451,52.9602749],[0.3798147,52.9958468],[0.3895238,53.2511239],[0.3478614,53.2511239],[0.3238912,53.282186],[0.3461492,53.6538501],[0.128487,53.6575466],[0.116582,53.6674703],[0.1350586,54.0655731],[-0.0609831,54.065908],[-0.0414249,54.4709448],[-0.5662701,54.4771794],[-0.5592078,54.6565127],[-1.1665638,54.6623485],[-1.1637389,54.842611],[-1.3316194,54.843909],[-1.3257065,55.2470842],[-1.529453,55.2487108],[-1.524178,55.6540122],[-1.7638798,55.6540122],[-1.7733693,55.9719116],[-2.1607858,55.9682981],[-2.1543289,56.0621387],[-2.4578051,56.0585337],[-2.4190635,56.641717],[-2.0962164,56.641717],[-2.0833025,57.0021322],[-1.9283359,57.0126802],[-1.9180966,57.3590895],[-1.7502161,57.3625721],[-1.7695869,57.7608634],[-3.6937554,57.7574187],[-3.7066693,57.9806386],[-3.5969013,57.9772149],[-3.6033582,58.1207277],[-3.0222335,58.1309566],[-3.0286905,58.5410788],[-2.8478961,58.530968],[-2.86081,58.8430508],[-2.679624,58.8414991],[-2.6841897,58.885175],[-2.6339665,58.9052239],[-2.679624,58.9335083],[-2.6887555,59.0229231],[-2.3668703,59.0229231],[-2.3702946,59.2652861],[-2.3429001,59.2821989],[-2.3714361,59.2996861],[-2.3737189,59.3707083],[-2.3429001,59.385825],[-2.3725775,59.400354],[-2.3714361,59.4259098],[-3.0734196,59.4230067],[-3.0711368,59.3433649],[-3.103097,59.3311405],[-3.0745611,59.3136695],[-3.0722782,59.232603],[-3.3850319,59.1484167],[-3.3747589,58.9352753],[-3.5653789,58.9323303],[-3.554829,58.69759],[-5.2808579,58.6667732],[-5.2534159,58.3514125],[-5.5068508,58.3437887],[-5.4761804,58.0323557],[-5.8974958,58.0212436],[-5.8522972,57.6171758],[-6.1396311,57.6137174],[-6.1541592,57.7423183],[-6.2913692,57.7380102],[-6.3365678,58.1398784],[-6.1121891,58.1466944],[-6.1473778,58.5106285],[-6.2934817,58.5416182],[-6.8413713,58.2977321],[-7.0057382,58.2929331],[-7.1016189,58.2064403],[-7.2573132,58.1793148],[-7.2531092,58.1004928],[-7.4070698,58.0905566],[-7.391347,57.7911354],[-7.790991,57.7733151],[-7.7624215,57.5444165],[-7.698501,57.1453194],[-7.7943817,57.1304547],[-7.716764,56.7368628],[-7.0122067,56.7654359],[-6.979922,56.5453858],[-7.0638622,56.5453858],[-7.0444914,56.3562587],[-6.500676,56.3812917],[-6.4491433,55.9793649],[-6.563287,55.9691456],[-6.5393742,55.7030135],[-6.5595521,55.6907321],[-6.5345315,55.6761713],[-6.5216176,55.5704434],[-5.8912587,55.5923416],[-5.8560127,55.2320733],[-5.2293639,55.2515958],[-5.1837064,54.6254139],[-3.6655956,54.6518373],[-3.6496155,54.4320023],[-3.5400375,54.4306744],[-3.530906,54.0290181],[-3.0697656,54.030359],[-3.0675737,53.8221388],[-3.0804876,53.7739911],[-3.0619239,53.7477488],[-3.0611168,53.6737049],[-3.2144691,53.6708361],[-3.2057699,53.4226163],[-3.2799632,53.355224],[-3.2896655,53.3608441],[-3.3327547,53.364931],[-3.3761293,53.3540318],[-4.0888976,53.3433102],[-4.0945474,53.4612036],[-4.697412,53.4448624],[-4.6882805,53.3318598],[-4.7202407,53.2895771],[-4.6837148,53.2486184],[-4.6768661,53.1542644],[-4.8480816,53.1446807],[-4.8178336,52.7440299],[-4.2545751,52.7558939],[-4.228876,52.254876],[-4.2607571,52.2536408],[-4.2724603,52.2432637],[-4.8136263,52.230095],[-4.8079191,52.1138892],[-5.3889104,52.0991668],[-5.3717888,51.9129667],[-5.4208706,51.9101502],[-5.414022,51.8453218],[-5.3683645,51.8474373],[-5.3466772,51.5595332],[-4.773676,51.5758518],[-4.7656859,51.4885146],[-4.1915432,51.4970427],[-4.1869775,51.4344663],[-3.6151177,51.4444274],[-3.6105519,51.3746543],[-3.1494115,51.3789292],[-3.1494115,51.2919281],[-4.3038735,51.2745907],[-4.2861169,51.0508721],[-4.8543277,51.0366633],[-4.8372201,50.7212787],[-5.2618345,50.7082694],[-5.2395519,50.3530581]],[[-2.1502671,60.171318],[-2.0030218,60.1696146],[-2.0013096,60.0997023],[-2.148555,60.1011247],[-2.1502671,60.171318]],[[-6.2086011,59.1163488],[-6.1229934,59.1166418],[-6.121852,59.0714985],[-6.2097426,59.0714985],[-6.2086011,59.1163488]],[[-4.4159559,59.0889036],[-4.4212022,59.0770848],[-4.3971904,59.0779143],[-4.3913388,59.0897328],[-4.4159559,59.0889036]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"NLS-OS-7th_Series","name":"NLS - OS 1-inch 7th Series 1955-61","type":"tms","template":"http://geo.nls.uk/mapdata2/os/seventh/{zoom}/{x}/{-y}.png","scaleExtent":[5,16],"polygon":[[[-6.4585407,49.9044128],[-6.3872009,49.9841116],[-6.2296827,49.9896159],[-6.2171269,49.8680087],[-6.4551164,49.8591793],[-6.4585407,49.9044128]],[[-1.4495137,60.8634056],[-0.7167114,60.8545122],[-0.7349744,60.4359756],[-0.6938826,60.4168218],[-0.7258429,60.3942735],[-0.7395401,60.0484714],[-0.9267357,60.0461918],[-0.9381501,59.8266157],[-1.4586452,59.831205],[-1.4455187,60.0535999],[-1.463211,60.0535999],[-1.4643524,60.0630002],[-1.5716475,60.0638546],[-1.5693646,60.1790005],[-1.643558,60.1807033],[-1.643558,60.1892162],[-1.8216221,60.1894999],[-1.8204807,60.3615507],[-1.8415973,60.3697345],[-1.8216221,60.3832755],[-1.8179852,60.5934321],[-1.453168,60.5934321],[-1.4495137,60.8634056]],[[-4.9089213,54.4242078],[-4.282598,54.4429861],[-4.2535417,54.029769],[-4.8766366,54.0221831],[-4.9089213,54.4242078]],[[-5.8667408,59.1444603],[-5.7759966,59.1470945],[-5.7720016,59.1014052],[-5.8621751,59.0990605],[-5.8667408,59.1444603]],[[-1.7065887,59.5703599],[-1.5579165,59.5693481],[-1.5564897,59.4965695],[-1.7054472,59.4975834],[-1.7065887,59.5703599]],[[-7.6865827,58.2940975],[-7.5330594,58.3006957],[-7.5256401,58.2646905],[-7.6797341,58.2577853],[-7.6865827,58.2940975]],[[-4.5338281,59.0359871],[-4.481322,59.0371616],[-4.4796099,59.0186583],[-4.5332574,59.0180707],[-4.5338281,59.0359871]],[[-8.6710698,57.8769896],[-8.4673234,57.8897332],[-8.4467775,57.7907],[-8.6510947,57.7779213],[-8.6710698,57.8769896]],[[-5.2395519,50.3530581],[-5.7920073,50.3384899],[-5.760047,49.9317027],[-4.6551363,49.9581461],[-4.677965,50.2860073],[-4.244219,50.2801723],[-4.2487848,50.2042525],[-3.3812929,50.2042525],[-3.4223846,50.5188201],[-3.1164796,50.5246258],[-3.1210453,50.6579592],[-2.6736357,50.6619495],[-2.5953453,50.6394325],[-2.5905026,50.5728419],[-2.4791203,50.5733545],[-2.4758919,50.5066704],[-2.3967943,50.5056438],[-2.401637,50.5723293],[-1.0400296,50.5718167],[-1.0335726,50.7059289],[-0.549302,50.7038843],[-0.5460736,50.7886618],[-0.0924734,50.7856002],[-0.0876307,50.7181949],[0.4789659,50.7120623],[0.487037,50.8182467],[0.9761503,50.8049868],[0.9922927,51.0126311],[1.4491213,51.0004424],[1.4781775,51.4090372],[1.0229632,51.4271576],[1.035877,51.7640881],[1.6105448,51.7500992],[1.646058,52.1560003],[1.7267698,52.1540195],[1.749369,52.4481811],[1.7870672,52.4811624],[1.759102,52.522505],[1.7933451,52.9602749],[0.3798147,52.9958468],[0.3895238,53.2511239],[0.3478614,53.2511239],[0.3238912,53.282186],[0.3461492,53.6538501],[0.128487,53.6575466],[0.116582,53.6674703],[0.1350586,54.0655731],[-0.0609831,54.065908],[-0.0414249,54.4709448],[-0.5662701,54.4771794],[-0.5592078,54.6565127],[-1.1665638,54.6623485],[-1.1637389,54.842611],[-1.3316194,54.843909],[-1.3257065,55.2470842],[-1.529453,55.2487108],[-1.524178,55.6540122],[-1.7638798,55.6540122],[-1.7733693,55.9719116],[-2.1607858,55.9682981],[-2.1543289,56.0621387],[-2.4578051,56.0585337],[-2.4190635,56.641717],[-2.0962164,56.641717],[-2.0833025,57.0021322],[-1.9283359,57.0126802],[-1.9180966,57.3590895],[-1.7502161,57.3625721],[-1.7695869,57.7608634],[-3.6937554,57.7574187],[-3.7066693,57.9806386],[-3.5969013,57.9772149],[-3.6033582,58.1207277],[-3.0222335,58.1309566],[-3.0286905,58.5410788],[-2.8478961,58.530968],[-2.86081,58.8430508],[-2.679624,58.8414991],[-2.6841897,58.885175],[-2.6339665,58.9052239],[-2.679624,58.9335083],[-2.6887555,59.0229231],[-2.3668703,59.0229231],[-2.3702946,59.2652861],[-2.3429001,59.2821989],[-2.3714361,59.2996861],[-2.3737189,59.3707083],[-2.3429001,59.385825],[-2.3725775,59.400354],[-2.3714361,59.4259098],[-3.0734196,59.4230067],[-3.0711368,59.3433649],[-3.103097,59.3311405],[-3.0745611,59.3136695],[-3.0722782,59.232603],[-3.3850319,59.1484167],[-3.3747589,58.9352753],[-3.5653789,58.9323303],[-3.554829,58.69759],[-5.2808579,58.6667732],[-5.2534159,58.3514125],[-5.5068508,58.3437887],[-5.4761804,58.0323557],[-5.8974958,58.0212436],[-5.8522972,57.6171758],[-6.1396311,57.6137174],[-6.1541592,57.7423183],[-6.2913692,57.7380102],[-6.3365678,58.1398784],[-6.1121891,58.1466944],[-6.1473778,58.5106285],[-6.2934817,58.5416182],[-6.8413713,58.2977321],[-7.0057382,58.2929331],[-7.1016189,58.2064403],[-7.2573132,58.1793148],[-7.2531092,58.1004928],[-7.4070698,58.0905566],[-7.391347,57.7911354],[-7.790991,57.7733151],[-7.7624215,57.5444165],[-7.698501,57.1453194],[-7.7943817,57.1304547],[-7.716764,56.7368628],[-7.0122067,56.7654359],[-6.979922,56.5453858],[-7.0638622,56.5453858],[-7.0444914,56.3562587],[-6.500676,56.3812917],[-6.4491433,55.9793649],[-6.563287,55.9691456],[-6.5393742,55.7030135],[-6.5595521,55.6907321],[-6.5345315,55.6761713],[-6.5216176,55.5704434],[-5.8912587,55.5923416],[-5.8560127,55.2320733],[-5.2293639,55.2515958],[-5.1837064,54.6254139],[-3.6655956,54.6518373],[-3.6496155,54.4320023],[-3.5400375,54.4306744],[-3.530906,54.0290181],[-3.0697656,54.030359],[-3.0675737,53.8221388],[-3.0804876,53.7739911],[-3.0619239,53.7477488],[-3.0611168,53.6737049],[-3.2144691,53.6708361],[-3.2057699,53.4226163],[-3.2799632,53.355224],[-3.2896655,53.3608441],[-3.3327547,53.364931],[-3.3761293,53.3540318],[-4.0888976,53.3433102],[-4.0945474,53.4612036],[-4.697412,53.4448624],[-4.6882805,53.3318598],[-4.7202407,53.2895771],[-4.6837148,53.2486184],[-4.6768661,53.1542644],[-4.8480816,53.1446807],[-4.8178336,52.7440299],[-4.2545751,52.7558939],[-4.228876,52.254876],[-4.2607571,52.2536408],[-4.2724603,52.2432637],[-4.8136263,52.230095],[-4.8079191,52.1138892],[-5.3889104,52.0991668],[-5.3717888,51.9129667],[-5.4208706,51.9101502],[-5.414022,51.8453218],[-5.3683645,51.8474373],[-5.3466772,51.5595332],[-4.773676,51.5758518],[-4.7656859,51.4885146],[-4.1915432,51.4970427],[-4.1869775,51.4344663],[-3.6151177,51.4444274],[-3.6105519,51.3746543],[-3.1494115,51.3789292],[-3.1494115,51.2919281],[-4.3038735,51.2745907],[-4.2861169,51.0508721],[-4.8543277,51.0366633],[-4.8372201,50.7212787],[-5.2618345,50.7082694],[-5.2395519,50.3530581]],[[-2.1502671,60.171318],[-2.0030218,60.1696146],[-2.0013096,60.0997023],[-2.148555,60.1011247],[-2.1502671,60.171318]],[[-6.2086011,59.1163488],[-6.1229934,59.1166418],[-6.121852,59.0714985],[-6.2097426,59.0714985],[-6.2086011,59.1163488]],[[-4.4159559,59.0889036],[-4.4212022,59.0770848],[-4.3971904,59.0779143],[-4.3913388,59.0897328],[-4.4159559,59.0889036]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"NLS-OS-1st_Series","name":"NLS - OS 1:25k 1st Series 1937-61","type":"tms","template":"http://geo.nls.uk/mapdata2/os/25000/{zoom}/{x}/{-y}.png","scaleExtent":[5,16],"polygon":[[[-4.7157244,54.6796556],[-4.6850662,54.6800268],[-4.6835779,54.6623245],[-4.7148782,54.6615818],[-4.7157244,54.6796556]],[[-3.7085748,58.3371151],[-3.5405937,58.3380684],[-3.5315137,58.1608002],[-3.3608086,58.1622372],[-3.3653486,58.252173],[-3.1610473,58.2536063],[-3.1610473,58.3261509],[-3.0275704,58.3271045],[-3.0366505,58.6139001],[-3.0021463,58.614373],[-3.0030543,58.7036341],[-3.4180129,58.7003322],[-3.4171049,58.6290293],[-3.7240109,58.6266658],[-3.7231029,58.606806],[-4.2361262,58.5992374],[-4.2334022,58.5092347],[-3.88836,58.5144516],[-3.8829119,58.4261327],[-3.7158389,58.4270836],[-3.7085748,58.3371151]],[[-6.46676,49.9943621],[-6.1889102,50.004868],[-6.1789222,49.8967815],[-6.3169391,49.8915171],[-6.312399,49.8200979],[-6.4504159,49.8159968],[-6.46676,49.9943621]],[[-5.6453263,50.2029809],[-5.7801329,50.2014076],[-5.7637888,50.0197267],[-5.3479221,50.0290604],[-5.3388421,49.9414854],[-5.024672,49.9473287],[-5.0355681,50.0383923],[-5.0010639,50.0453901],[-4.9974319,50.1304478],[-4.855783,50.13394],[-4.861231,50.206057],[-4.6546085,50.2140172],[-4.6558926,50.3018616],[-4.5184924,50.3026818],[-4.51464,50.325642],[-4.2488284,50.3264618],[-4.2488284,50.3100631],[-4.10886,50.3141633],[-4.1062917,50.2411267],[-3.9648088,50.2432047],[-3.9640778,50.2254158],[-3.8522287,50.2273626],[-3.8503757,50.1552563],[-3.6921809,50.1572487],[-3.5414602,50.1602198],[-3.5465781,50.3226814],[-3.4068012,50.3241013],[-3.4165761,50.5892711],[-3.2746691,50.5962721],[-3.2749172,50.6106323],[-2.9971742,50.613972],[-2.9896008,50.688537],[-2.7120266,50.690565],[-2.710908,50.6195964],[-2.5695473,50.6157538],[-2.5651019,50.5134083],[-2.4014463,50.513379],[-2.3940583,50.6160348],[-2.2894123,50.6147436],[-2.2876184,50.6008549],[-2.1477855,50.6048506],[-2.1451013,50.5325437],[-1.9335117,50.5347477],[-1.9362139,50.6170445],[-1.8573025,50.6228094],[-1.8554865,50.709139],[-1.6066929,50.709139],[-1.6085089,50.6239615],[-1.4450678,50.6228094],[-1.4432518,50.5317039],[-1.1545059,50.5293951],[-1.1472419,50.6170485],[-1.011041,50.6205051],[-1.011041,50.7056889],[-0.704135,50.7045388],[-0.700503,50.7769401],[-0.5860943,50.7723465],[-0.5879103,50.7907181],[-0.0149586,50.7798108],[-0.0185906,50.7625836],[0.0967261,50.7620093],[0.0921861,50.6913106],[0.3046595,50.6890096],[0.3101075,50.7757917],[0.5511831,50.7726336],[0.5529991,50.8432096],[0.695556,50.8403428],[0.696464,50.8592608],[0.9852099,50.8523824],[0.9906579,50.9417226],[1.0160821,50.9411504],[1.0215301,51.0303204],[1.2812198,51.0240383],[1.2848518,51.0948044],[1.4277848,51.0948044],[1.4386809,51.2882859],[1.4713691,51.2871502],[1.4804492,51.3994534],[1.1590151,51.4073836],[1.1590151,51.3869889],[1.0191822,51.3903886],[1.0228142,51.4798247],[0.8793493,51.4843484],[0.8829813,51.5566675],[1.0264462,51.5544092],[1.0373423,51.7493319],[1.2607117,51.7482076],[1.2661598,51.8279642],[1.3351682,51.8335756],[1.3478803,51.9199021],[1.4840812,51.9199021],[1.4986093,52.0038271],[1.6438902,52.0027092],[1.6656823,52.270221],[1.7310588,52.270221],[1.7528509,52.4465637],[1.8254914,52.4476705],[1.8345714,52.624408],[1.7690346,52.6291402],[1.7741711,52.717904],[1.6996925,52.721793],[1.706113,52.8103687],[1.559724,52.8165777],[1.5648605,52.9034116],[1.4184715,52.9103818],[1.4223238,52.9281894],[1.3439928,52.9289635],[1.3491293,53.0001194],[0.4515789,53.022589],[0.4497629,52.9351139],[0.3789384,52.9351139],[0.3716744,52.846365],[0.2227614,52.8496552],[0.2336575,52.9329248],[0.3062979,52.9351139],[0.308114,53.022589],[0.3807544,53.0236813],[0.3993708,53.2933729],[0.3248922,53.2987454],[0.3274604,53.3853782],[0.2504136,53.38691],[0.2581183,53.4748924],[0.1862079,53.4779494],[0.1913443,53.6548777],[0.1502527,53.6594436],[0.1528209,53.7666003],[0.0012954,53.7734308],[0.0025796,53.8424326],[-0.0282392,53.841675],[-0.0226575,53.9311501],[-0.1406983,53.9322193],[-0.1416063,54.0219323],[-0.1706625,54.0235326],[-0.1679384,54.0949482],[-0.0126694,54.0912206],[-0.0099454,54.1811226],[-0.1615824,54.1837795],[-0.1606744,54.2029038],[-0.2405789,54.2034349],[-0.2378549,54.2936234],[-0.3894919,54.2941533],[-0.3857497,54.3837321],[-0.461638,54.3856364],[-0.4571122,54.4939066],[-0.6105651,54.4965434],[-0.6096571,54.5676704],[-0.7667421,54.569776],[-0.7640181,54.5887213],[-0.9192871,54.5908258],[-0.9148116,54.6608348],[-1.1485204,54.6634343],[-1.1472363,54.7528316],[-1.2268514,54.7532021],[-1.2265398,54.8429879],[-1.2991803,54.8435107],[-1.2991803,54.9333391],[-1.3454886,54.9354258],[-1.3436726,55.0234878],[-1.3772688,55.0255698],[-1.3754528,55.1310877],[-1.4997441,55.1315727],[-1.4969272,55.2928323],[-1.5296721,55.2942946],[-1.5258198,55.6523803],[-1.7659492,55.6545537],[-1.7620968,55.7435626],[-1.9688392,55.7435626],[-1.9698023,55.8334505],[-2.0019051,55.8336308],[-2.0015841,55.9235526],[-2.1604851,55.9240613],[-2.1613931,55.9413549],[-2.3202942,55.9408463],[-2.3212022,56.0145126],[-2.5627317,56.0124824],[-2.5645477,56.1022207],[-2.9658863,56.0991822],[-2.9667943,56.1710304],[-2.4828272,56.1755797],[-2.4882752,56.2856078],[-2.5645477,56.2835918],[-2.5681798,56.3742075],[-2.7261728,56.3732019],[-2.7316208,56.4425301],[-2.6190281,56.4425301],[-2.6153961,56.5317671],[-2.453771,56.5347715],[-2.4534686,56.6420248],[-2.4062523,56.6440218],[-2.3953562,56.7297964],[-2.2936596,56.7337811],[-2.2972916,56.807423],[-2.1629067,56.8113995],[-2.1592747,56.9958425],[-1.9922016,57.0017771],[-2.0067297,57.2737477],[-1.9195612,57.2757112],[-1.9304572,57.3482876],[-1.8106005,57.3443682],[-1.7997044,57.4402728],[-1.6616875,57.4285429],[-1.6689516,57.5398256],[-1.7452241,57.5398256],[-1.7524881,57.6313302],[-1.8287606,57.6332746],[-1.8287606,57.7187255],[-3.1768526,57.7171219],[-3.1794208,57.734264],[-3.5134082,57.7292105],[-3.5129542,57.7112683],[-3.7635638,57.7076303],[-3.7598539,57.635713],[-3.8420372,57.6343382],[-3.8458895,57.6178365],[-3.9794374,57.6157733],[-3.9794374,57.686544],[-3.8150708,57.689976],[-3.817639,57.7968899],[-3.6853753,57.7989429],[-3.6892276,57.8891567],[-3.9383458,57.8877915],[-3.9421981,57.9750592],[-3.6943641,57.9784638],[-3.6969323,58.0695865],[-4.0372226,58.0641528],[-4.0346543,57.9730163],[-4.2003051,57.9702923],[-4.1832772,57.7012869],[-4.518752,57.6951111],[-4.5122925,57.6050682],[-4.6789116,57.6016628],[-4.666022,57.4218334],[-3.6677696,57.4394729],[-3.671282,57.5295384],[-3.3384979,57.5331943],[-3.3330498,57.4438859],[-2.8336466,57.4485275],[-2.8236396,56.9992706],[-2.3305398,57.0006693],[-2.3298977,56.9113932],[-2.6579889,56.9092901],[-2.6559637,56.8198406],[-2.8216747,56.8188467],[-2.8184967,56.7295397],[-3.1449248,56.7265508],[-3.1435628,56.6362749],[-3.4679089,56.6350265],[-3.474265,56.7238108],[-3.8011471,56.7188284],[-3.785711,56.4493026],[-3.946428,56.4457896],[-3.9428873,56.2659777],[-4.423146,56.2588459],[-4.4141572,56.0815506],[-4.8944159,56.0708008],[-4.8791072,55.8896994],[-5.1994158,55.8821374],[-5.1852906,55.7023791],[-5.0273445,55.7067203],[-5.0222081,55.6879046],[-4.897649,55.6907999],[-4.8880181,55.6002822],[-4.7339244,55.6046348],[-4.7275038,55.5342082],[-4.773732,55.5334815],[-4.7685955,55.4447227],[-4.8494947,55.4418092],[-4.8405059,55.3506535],[-4.8700405,55.3513836],[-4.8649041,55.2629462],[-4.9920314,55.2592875],[-4.9907473,55.1691779],[-5.0600894,55.1655105],[-5.0575212,55.0751884],[-5.2141831,55.0722477],[-5.1991766,54.8020337],[-5.0466316,54.8062205],[-5.0502636,54.7244996],[-4.9703591,54.7203043],[-4.9776232,54.6215905],[-4.796022,54.6342056],[-4.796022,54.7307917],[-4.8977186,54.7265971],[-4.9086147,54.8145928],[-4.8069181,54.8166856],[-4.8105501,54.7915648],[-4.6943253,54.7978465],[-4.6761652,54.7244996],[-4.5744686,54.7244996],[-4.5599405,54.6426135],[-4.3093309,54.6384098],[-4.3333262,54.8229889],[-4.2626999,54.8274274],[-4.2549952,54.7348587],[-3.8338058,54.7400481],[-3.836374,54.8141105],[-3.7118149,54.8133706],[-3.7143831,54.8318654],[-3.5346072,54.8355633],[-3.5271039,54.9066228],[-3.4808758,54.9084684],[-3.4776655,54.7457328],[-3.5874573,54.744621],[-3.5836049,54.6546166],[-3.7107322,54.6531308],[-3.6991752,54.4550407],[-3.5746161,54.4572801],[-3.5759002,54.3863042],[-3.539945,54.3855564],[-3.5386609,54.297224],[-3.46033,54.2957252],[-3.4590458,54.2079507],[-3.3807149,54.2102037],[-3.381999,54.1169788],[-3.302878,54.1160656],[-3.300154,54.0276224],[-3.1013007,54.0292224],[-3.093596,53.6062158],[-3.2065981,53.6016441],[-3.2091663,53.4917753],[-3.2451215,53.4887193],[-3.2348486,53.4045934],[-3.5276266,53.3999999],[-3.5343966,53.328481],[-3.6488053,53.3252272],[-3.6527308,53.3057716],[-3.7271873,53.3046865],[-3.7315003,53.3945257],[-3.9108315,53.3912769],[-3.9071995,53.3023804],[-3.9521457,53.3015665],[-3.9566724,53.3912183],[-4.1081979,53.3889209],[-4.1081979,53.4072967],[-4.2622916,53.4065312],[-4.2635757,53.4753707],[-4.638537,53.4677274],[-4.6346847,53.3812621],[-4.7091633,53.3774321],[-4.7001745,53.1954965],[-4.5499332,53.1962658],[-4.5435126,53.1092488],[-4.3919871,53.1100196],[-4.3855666,53.0236002],[-4.6115707,53.0205105],[-4.603866,52.9284932],[-4.7566756,52.9261709],[-4.7476868,52.8370555],[-4.8208813,52.8331768],[-4.8208813,52.7446476],[-4.3701572,52.7539749],[-4.3765778,52.8401583],[-4.2314728,52.8455875],[-4.2237682,52.7586379],[-4.1056297,52.7570836],[-4.1015192,52.6714874],[-4.1487355,52.6703862],[-4.1305754,52.4008596],[-4.1995838,52.3986435],[-4.2050319,52.3110195],[-4.3466808,52.303247],[-4.3484968,52.2365693],[-4.4901457,52.2332328],[-4.4883297,52.2098702],[-4.6572188,52.2098702],[-4.6590348,52.1385939],[-4.7788916,52.13525],[-4.7807076,52.1162967],[-4.9259885,52.1140663],[-4.9187245,52.0392855],[-5.2365265,52.0314653],[-5.2347105,51.9442339],[-5.3473032,51.9408755],[-5.3473032,51.9195995],[-5.4925842,51.9162392],[-5.4853201,51.8265386],[-5.1983903,51.8321501],[-5.1893102,51.7625177],[-5.335825,51.7589528],[-5.3281204,51.6686495],[-5.1836575,51.6730296],[-5.1836575,51.6539134],[-5.0674452,51.6578966],[-5.0603825,51.5677905],[-4.5974594,51.5809588],[-4.60388,51.6726314],[-4.345773,51.6726314],[-4.3355001,51.4962964],[-3.9528341,51.5106841],[-3.9425611,51.5905333],[-3.8809237,51.5953198],[-3.8706508,51.5074872],[-3.7679216,51.4978952],[-3.7550805,51.4242895],[-3.5855774,51.41468],[-3.5778727,51.3329177],[-3.0796364,51.3329177],[-3.0770682,51.2494018],[-3.7216935,51.2381477],[-3.7216935,51.2558315],[-3.8706508,51.2558315],[-3.8680825,51.2365398],[-4.2944084,51.2252825],[-4.289272,51.0496352],[-4.5692089,51.0431767],[-4.5624122,50.9497388],[-4.5905604,50.9520269],[-4.5896524,50.8627065],[-4.6296046,50.8592677],[-4.6226411,50.7691513],[-4.6952816,50.7680028],[-4.6934655,50.6967379],[-4.8342064,50.6938621],[-4.8296664,50.6046231],[-4.9676833,50.6000126],[-4.9685913,50.5821427],[-5.1084242,50.5786832],[-5.1029762,50.4892254],[-5.1311244,50.48807],[-5.1274923,50.4163798],[-5.2664172,50.4117509],[-5.2609692,50.3034214],[-5.5124868,50.2976214],[-5.5061308,50.2256428],[-5.6468717,50.2209953],[-5.6453263,50.2029809]],[[-5.1336607,55.2630226],[-5.1021999,55.2639372],[-5.0999527,55.2458239],[-5.1322161,55.2446343],[-5.1336607,55.2630226]],[[-5.6431878,55.5095745],[-5.4861028,55.5126594],[-5.4715747,55.3348829],[-5.6277517,55.3302345],[-5.6431878,55.5095745]],[[-4.7213517,51.2180246],[-4.5804201,51.2212417],[-4.5746416,51.1306736],[-4.7174993,51.1280545],[-4.7213517,51.2180246]],[[-5.1608796,55.4153626],[-5.0045387,55.4190069],[-5.0184798,55.6153521],[-5.1755648,55.6138137],[-5.1608796,55.4153626]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"NLS-OS-25inch-hist","name":"NLS - OS 25-inch (Scotland), 1892-1905","type":"tms","template":"http://geo.nls.uk/mapdata2/os/25_inch/scotland_1/{zoom}/{x}/{y}.png","scaleExtent":[0,18],"polygon":[[[-5.2112173,54.8018593],[-5.0642752,54.8026508],[-5.0560354,54.6305176],[-4.3158316,54.6297227],[-4.3117117,54.7448258],[-3.8530325,54.7464112],[-3.8530325,54.8034424],[-3.5522818,54.8034424],[-3.5522818,54.8374644],[-3.468511,54.8406277],[-3.4657644,54.8983158],[-3.3847403,54.8991055],[-3.3888601,54.9559214],[-3.0920786,54.9539468],[-3.0392359,54.9923274],[-3.0212713,55.0493881],[-2.9591232,55.0463283],[-2.9202807,55.0666294],[-2.7857081,55.068652],[-2.7852225,55.0914426],[-2.7337562,55.0922761],[-2.737616,55.151204],[-2.7648395,55.1510672],[-2.7013114,55.1722505],[-2.6635459,55.2192808],[-2.6460364,55.2188891],[-2.629042,55.2233933],[-2.6317886,55.2287781],[-2.6235488,55.2446345],[-2.6197723,55.2454663],[-2.6099017,55.2454174],[-2.6099876,55.2486466],[-2.6408121,55.2590039],[-2.6247896,55.2615631],[-2.6045186,55.2823081],[-2.5693176,55.296132],[-2.5479542,55.3121617],[-2.5091116,55.3234891],[-2.4780376,55.3494471],[-2.4421083,55.3533118],[-2.4052079,55.3439256],[-2.3726772,55.3447539],[-2.3221819,55.3687665],[-2.3241241,55.3999337],[-2.2576062,55.425015],[-2.1985547,55.4273529],[-2.1484296,55.4717466],[-2.1944348,55.484199],[-2.2040479,55.529306],[-2.2960584,55.6379722],[-2.2177808,55.6379722],[-2.1059266,55.7452498],[-1.9716874,55.7462161],[-1.9697453,55.9190951],[-2.1201694,55.9207115],[-2.1242893,55.9776133],[-2.3440159,55.9783817],[-2.3440159,56.0390349],[-2.5046909,56.0413363],[-2.500571,56.1003588],[-2.8823459,56.0957629],[-2.8823459,56.1722898],[-2.4126804,56.1692316],[-2.4181736,56.2334017],[-2.5857151,56.2303484],[-2.5719822,56.3416356],[-2.7257908,56.3462022],[-2.7312839,56.4343808],[-2.6928318,56.4343808],[-2.6928318,56.4859769],[-2.5307834,56.4935587],[-2.5307834,56.570806],[-2.5302878,56.6047947],[-2.3732428,56.6044452],[-2.3684363,56.7398824],[-2.3292975,56.7398824],[-2.3292975,56.7888065],[-2.3145346,56.7891826],[-2.3148779,56.7967036],[-2.171369,56.7967036],[-2.1703979,56.9710595],[-2.0101725,56.9694716],[-2.0101725,57.0846832],[-2.0817687,57.085349],[-2.0488097,57.1259963],[-2.0409133,57.126369],[-2.0383434,57.2411129],[-1.878118,57.2421638],[-1.8771469,57.2978175],[-1.9868771,57.2983422],[-1.9082209,57.3560063],[-1.8752048,57.3560063],[-1.8761758,57.3769527],[-1.8120857,57.4120111],[-1.7120661,57.4120111],[-1.7034646,57.6441388],[-1.8666032,57.6451781],[-1.8646611,57.7033351],[-3.1204292,57.7064705],[-3.1218025,57.7504652],[-3.4445259,57.7526635],[-3.4472724,57.7138067],[-3.5145637,57.7094052],[-3.5118171,57.6939956],[-3.7645027,57.6917938],[-3.7672492,57.6344975],[-3.842378,57.6288312],[-3.8438346,57.5965825],[-3.9414265,57.5916386],[-3.9404554,57.6537782],[-3.8894746,57.6529989],[-3.8826772,57.7676408],[-3.7224517,57.766087],[-3.7195385,57.8819201],[-3.9146888,57.8853352],[-3.916062,57.9546243],[-3.745774,57.9538956],[-3.7471473,58.0688409],[-3.5837256,58.0695672],[-3.5837256,58.1116689],[-3.4560096,58.1138452],[-3.4544646,58.228503],[-3.4379851,58.2283222],[-3.4243233,58.2427725],[-3.412307,58.2438567],[-3.3735115,58.2695057],[-3.3063919,58.2862038],[-3.1229154,58.2859395],[-3.123602,58.3443661],[-2.9574338,58.3447264],[-2.951254,58.6422011],[-2.8812162,58.6429157],[-2.8851004,58.8112825],[-2.7180775,58.8142997],[-2.7161354,58.8715749],[-2.556881,58.8775984],[-2.5544533,58.9923453],[-2.5567617,59.0483775],[-2.391893,59.0485996],[-2.3918002,59.1106996],[-2.4733695,59.1106996],[-2.5591563,59.1783028],[-2.5630406,59.2210646],[-2.3921334,59.224046],[-2.3911409,59.2740075],[-2.3639512,59.2745036],[-2.3658933,59.285417],[-2.3911409,59.284921],[-2.3911409,59.3379505],[-2.2221759,59.3381981],[-2.2233897,59.395965],[-2.3758467,59.396583],[-2.3899271,59.4026383],[-2.4008516,59.3962122],[-2.5637882,59.3952604],[-2.5637882,59.3385811],[-2.7320164,59.3375306],[-2.7333896,59.3952604],[-3.0726511,59.3931174],[-3.0703404,59.3354759],[-3.0753186,59.3355634],[-3.0749753,59.3292593],[-3.0698254,59.3289091],[-3.069801,59.2196159],[-3.2363384,59.2166341],[-3.2336751,59.1606496],[-3.4032766,59.1588895],[-3.394086,58.9279316],[-3.5664497,58.9259268],[-3.5611089,58.8679885],[-3.392508,58.8699339],[-3.3894734,58.8698711],[-3.3891093,58.8684905],[-3.3912942,58.868616],[-3.3884161,58.7543084],[-3.2238208,58.7555677],[-3.2189655,58.691289],[-3.4634113,58.6905753],[-3.4551716,58.6341518],[-3.787508,58.6341518],[-3.7861347,58.5769211],[-3.9028645,58.5733411],[-3.9028645,58.6477304],[-4.0690327,58.6491594],[-4.0690327,58.5912376],[-4.7364521,58.5933845],[-4.7364521,58.6505884],[-5.0715351,58.6520173],[-5.0654779,58.5325854],[-5.2332047,58.5316087],[-5.2283494,58.4719947],[-5.2424298,58.4719947],[-5.2366034,58.4089731],[-5.2283494,58.4094818],[-5.2210664,58.3005859],[-5.5657939,58.2959933],[-5.5580254,58.2372573],[-5.4146722,58.2401326],[-5.4141866,58.2267768],[-5.3885749,58.2272242],[-5.382714,58.1198615],[-5.51043,58.1191362],[-5.5114011,58.006214],[-5.6745397,58.0041559],[-5.6716266,57.9449366],[-5.6716266,57.8887166],[-5.8347652,57.8856193],[-5.8277052,57.5988958],[-6.0384259,57.5986357],[-6.0389115,57.6459559],[-6.1981658,57.6456961],[-6.2076123,57.7600132],[-6.537067,57.7544033],[-6.5312406,57.6402392],[-6.7002056,57.6360809],[-6.6807844,57.5236293],[-6.8516915,57.5152857],[-6.8361545,57.3385811],[-6.6730158,57.3438213],[-6.674958,57.2850883],[-6.5098772,57.2850883],[-6.4982244,57.1757637],[-6.3506228,57.1820797],[-6.3312015,57.1251969],[-6.1797156,57.1230884],[-6.1719471,57.0682265],[-6.4593819,57.059779],[-6.4564687,57.1093806],[-6.6671895,57.1062165],[-6.6730158,57.002708],[-6.5021087,57.0048233],[-6.4836097,56.8917522],[-6.3266104,56.8894062],[-6.3156645,56.7799312],[-6.2146739,56.775675],[-6.2146739,56.7234965],[-6.6866107,56.7224309],[-6.6769001,56.6114413],[-6.8419809,56.607166],[-6.8400387,56.5483307],[-7.1546633,56.5461895],[-7.1488369,56.4872592],[-6.9915246,56.490476],[-6.9876404,56.4325329],[-6.6827265,56.4314591],[-6.6769001,56.5472601],[-6.5292985,56.5504717],[-6.5234721,56.4379018],[-6.3661598,56.4368281],[-6.3642177,56.3766524],[-6.5273563,56.3712749],[-6.5171745,56.2428427],[-6.4869621,56.247421],[-6.4869621,56.1893882],[-6.3001945,56.1985572],[-6.3029411,56.2581017],[-5.9019401,56.256576],[-5.8964469,56.0960466],[-6.0282829,56.0883855],[-6.0392692,56.1557502],[-6.3853385,56.1542205],[-6.3606193,55.96099],[-6.2123039,55.9640647],[-6.2047508,55.9202269],[-6.5185478,55.9129158],[-6.5061881,55.7501763],[-6.6764762,55.7409005],[-6.6599967,55.6263176],[-6.3551261,55.6232161],[-6.3578727,55.5689002],[-6.0392692,55.5720059],[-6.0310294,55.6247669],[-5.7398917,55.6309694],[-5.7371452,55.4569279],[-5.8964469,55.4600426],[-5.8964469,55.2789864],[-5.4350211,55.2821151],[-5.4405143,55.4506979],[-5.2867057,55.4569279],[-5.3086784,55.4070602],[-4.9735954,55.4008223],[-4.9845817,55.2038242],[-5.1493766,55.2038242],[-5.1411369,55.037337],[-5.2152946,55.0341891],[-5.2112173,54.8018593]],[[-2.1646559,60.1622059],[-1.9930299,60.1609801],[-1.9946862,60.1035151],[-2.1663122,60.104743],[-2.1646559,60.1622059]],[[-1.5360658,59.8570831],[-1.3653566,59.8559841],[-1.366847,59.7975565],[-1.190628,59.7964199],[-1.1862046,59.9695391],[-1.0078652,59.9683948],[-1.0041233,60.114145],[-0.8360832,60.1130715],[-0.834574,60.1716772],[-1.0074262,60.1727795],[-1.0052165,60.2583924],[-0.8299659,60.2572778],[-0.826979,60.3726551],[-0.6507514,60.3715381],[-0.6477198,60.4882292],[-0.9984896,60.4904445],[-0.9970279,60.546555],[-0.6425288,60.5443201],[-0.6394896,60.6606792],[-0.8148133,60.6617806],[-0.8132987,60.7196112],[-0.6383298,60.7185141],[-0.635467,60.8275393],[-0.797568,60.8285523],[-0.9941426,60.8297807],[-0.9954966,60.7782667],[-1.1670282,60.7793403],[-1.1700357,60.6646181],[-1.5222599,60.6668304],[-1.5237866,60.6084426],[-1.6975673,60.609536],[-1.7021271,60.4345249],[-1.5260578,60.4334111],[-1.5275203,60.3770719],[-1.8751127,60.3792746],[-1.8781372,60.2624647],[-1.7019645,60.2613443],[-1.7049134,60.1470532],[-1.528659,60.1459283],[-1.5360658,59.8570831]],[[-0.9847667,60.8943762],[-0.9860347,60.8361105],[-0.8078362,60.8351904],[-0.8065683,60.8934578],[-0.9847667,60.8943762]],[[-7.7696901,56.8788231],[-7.7614504,56.7608274],[-7.6009049,56.7641903],[-7.5972473,56.819332],[-7.4479894,56.8203948],[-7.4489319,56.8794098],[-7.2841369,56.8794098],[-7.2813904,57.0471152],[-7.1303283,57.0515969],[-7.1330749,57.511801],[-6.96828,57.5147514],[-6.9765198,57.6854668],[-6.8062317,57.6913392],[-6.8089782,57.8041985],[-6.6496765,57.8071252],[-6.6441833,57.8612267],[-6.3200866,57.8626878],[-6.3200866,58.1551617],[-6.1607849,58.1522633],[-6.1552917,58.20874],[-5.9850036,58.2101869],[-5.9904968,58.2680163],[-6.1497986,58.2665717],[-6.1415588,58.5557514],[-6.3173401,58.5557514],[-6.3091003,58.4983923],[-6.4876282,58.4955218],[-6.4876282,58.4423768],[-6.6606628,58.4395018],[-6.6469299,58.3819525],[-6.8117248,58.3805125],[-6.8117248,58.3286357],[-6.9792663,58.3286357],[-6.9710266,58.2694608],[-7.1413147,58.2680163],[-7.1403816,58.0358742],[-7.3020636,58.0351031],[-7.3030347,57.9774797],[-7.1379539,57.9777372],[-7.1413526,57.9202792],[-7.1398961,57.8640206],[-7.3020636,57.862471],[-7.298484,57.7442293],[-7.4509193,57.7456951],[-7.4550392,57.6899522],[-7.6186131,57.6906048],[-7.6198341,57.7456951],[-7.7901222,57.7442293],[-7.7873756,57.6855477],[-7.6222332,57.6853817],[-7.6173779,57.5712602],[-7.788285,57.5709998],[-7.7892561,57.512109],[-7.7038025,57.5115874],[-7.6999183,57.4546902],[-7.5367796,57.4552126],[-7.5348375,57.5126306],[-7.4581235,57.5131521],[-7.4552103,57.2824165],[-7.6115515,57.2845158],[-7.6144647,57.2272651],[-7.451326,57.2256881],[-7.451326,57.1103873],[-7.6164068,57.1088053],[-7.603783,56.8792358],[-7.7696901,56.8788231]],[[-1.7106618,59.5626284],[-1.5417509,59.562215],[-1.5423082,59.5037224],[-1.7112191,59.5041365],[-1.7106618,59.5626284]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"NLS-OS-6inch-Scotland-hist","name":"NLS - OS 6-inch Scotland 1842-82","type":"tms","template":"http://geo.nls.uk/maps/os/six_inch/{zoom}/{x}/{-y}.png","scaleExtent":[5,16],"polygon":[[[-5.2112173,54.8018593],[-5.0642752,54.8026508],[-5.0560354,54.6305176],[-4.3158316,54.6297227],[-4.3117117,54.7448258],[-3.8530325,54.7464112],[-3.8530325,54.8034424],[-3.5522818,54.8034424],[-3.5522818,54.8374644],[-3.468511,54.8406277],[-3.4657644,54.8983158],[-3.3847403,54.8991055],[-3.3888601,54.9559214],[-3.0920786,54.9539468],[-3.0392359,54.9923274],[-3.0212713,55.0493881],[-2.9591232,55.0463283],[-2.9202807,55.0666294],[-2.7857081,55.068652],[-2.7852225,55.0914426],[-2.7337562,55.0922761],[-2.737616,55.151204],[-2.7648395,55.1510672],[-2.7013114,55.1722505],[-2.6635459,55.2192808],[-2.6460364,55.2188891],[-2.629042,55.2233933],[-2.6317886,55.2287781],[-2.6235488,55.2446345],[-2.6197723,55.2454663],[-2.6099017,55.2454174],[-2.6099876,55.2486466],[-2.6408121,55.2590039],[-2.6247896,55.2615631],[-2.6045186,55.2823081],[-2.5693176,55.296132],[-2.5479542,55.3121617],[-2.5091116,55.3234891],[-2.4780376,55.3494471],[-2.4421083,55.3533118],[-2.4052079,55.3439256],[-2.3726772,55.3447539],[-2.3221819,55.3687665],[-2.3241241,55.3999337],[-2.2576062,55.425015],[-2.1985547,55.4273529],[-2.1484296,55.4717466],[-2.1944348,55.484199],[-2.2040479,55.529306],[-2.2960584,55.6379722],[-2.2177808,55.6379722],[-2.1059266,55.7452498],[-1.9716874,55.7462161],[-1.9697453,55.9190951],[-2.1201694,55.9207115],[-2.1242893,55.9776133],[-2.3440159,55.9783817],[-2.3440159,56.0390349],[-2.5046909,56.0413363],[-2.500571,56.1003588],[-2.8823459,56.0957629],[-2.8823459,56.1722898],[-2.4126804,56.1692316],[-2.4181736,56.2334017],[-2.5857151,56.2303484],[-2.5719822,56.3416356],[-2.7257908,56.3462022],[-2.7312839,56.4343808],[-2.6928318,56.4343808],[-2.6928318,56.4859769],[-2.5307834,56.4935587],[-2.5307834,56.570806],[-2.5302878,56.6047947],[-2.3732428,56.6044452],[-2.3684363,56.7398824],[-2.3292975,56.7398824],[-2.3292975,56.7888065],[-2.3145346,56.7891826],[-2.3148779,56.7967036],[-2.171369,56.7967036],[-2.1703979,56.9710595],[-2.0101725,56.9694716],[-2.0101725,57.0846832],[-2.0817687,57.085349],[-2.0488097,57.1259963],[-2.0409133,57.126369],[-2.0383434,57.2411129],[-1.878118,57.2421638],[-1.8771469,57.2978175],[-1.9868771,57.2983422],[-1.9082209,57.3560063],[-1.8752048,57.3560063],[-1.8761758,57.3769527],[-1.8120857,57.4120111],[-1.7120661,57.4120111],[-1.7034646,57.6441388],[-1.8666032,57.6451781],[-1.8646611,57.7033351],[-3.1204292,57.7064705],[-3.1218025,57.7504652],[-3.4445259,57.7526635],[-3.4472724,57.7138067],[-3.5145637,57.7094052],[-3.5118171,57.6939956],[-3.7645027,57.6917938],[-3.7672492,57.6344975],[-3.842378,57.6288312],[-3.8438346,57.5965825],[-3.9414265,57.5916386],[-3.9404554,57.6537782],[-3.8894746,57.6529989],[-3.8826772,57.7676408],[-3.7224517,57.766087],[-3.7195385,57.8819201],[-3.9146888,57.8853352],[-3.916062,57.9546243],[-3.745774,57.9538956],[-3.7471473,58.0688409],[-3.5837256,58.0695672],[-3.5837256,58.1116689],[-3.4560096,58.1138452],[-3.4544646,58.228503],[-3.4379851,58.2283222],[-3.4243233,58.2427725],[-3.412307,58.2438567],[-3.3735115,58.2695057],[-3.3063919,58.2862038],[-3.1229154,58.2859395],[-3.123602,58.3443661],[-2.9574338,58.3447264],[-2.951254,58.6422011],[-2.8812162,58.6429157],[-2.8851004,58.8112825],[-2.7180775,58.8142997],[-2.7161354,58.8715749],[-2.556881,58.8775984],[-2.5544533,58.9923453],[-2.5567617,59.0483775],[-2.391893,59.0485996],[-2.3918002,59.1106996],[-2.4733695,59.1106996],[-2.5591563,59.1783028],[-2.5630406,59.2210646],[-2.3921334,59.224046],[-2.3911409,59.2740075],[-2.3639512,59.2745036],[-2.3658933,59.285417],[-2.3911409,59.284921],[-2.3911409,59.3379505],[-2.2221759,59.3381981],[-2.2233897,59.395965],[-2.3758467,59.396583],[-2.3899271,59.4026383],[-2.4008516,59.3962122],[-2.5637882,59.3952604],[-2.5637882,59.3385811],[-2.7320164,59.3375306],[-2.7333896,59.3952604],[-3.0726511,59.3931174],[-3.0703404,59.3354759],[-3.0753186,59.3355634],[-3.0749753,59.3292593],[-3.0698254,59.3289091],[-3.069801,59.2196159],[-3.2363384,59.2166341],[-3.2336751,59.1606496],[-3.4032766,59.1588895],[-3.394086,58.9279316],[-3.5664497,58.9259268],[-3.5611089,58.8679885],[-3.392508,58.8699339],[-3.3894734,58.8698711],[-3.3891093,58.8684905],[-3.3912942,58.868616],[-3.3884161,58.7543084],[-3.2238208,58.7555677],[-3.2189655,58.691289],[-3.4634113,58.6905753],[-3.4551716,58.6341518],[-3.787508,58.6341518],[-3.7861347,58.5769211],[-3.9028645,58.5733411],[-3.9028645,58.6477304],[-4.0690327,58.6491594],[-4.0690327,58.5912376],[-4.7364521,58.5933845],[-4.7364521,58.6505884],[-5.0715351,58.6520173],[-5.0654779,58.5325854],[-5.2332047,58.5316087],[-5.2283494,58.4719947],[-5.2424298,58.4719947],[-5.2366034,58.4089731],[-5.2283494,58.4094818],[-5.2210664,58.3005859],[-5.5657939,58.2959933],[-5.5580254,58.2372573],[-5.4146722,58.2401326],[-5.4141866,58.2267768],[-5.3885749,58.2272242],[-5.382714,58.1198615],[-5.51043,58.1191362],[-5.5114011,58.006214],[-5.6745397,58.0041559],[-5.6716266,57.9449366],[-5.6716266,57.8887166],[-5.8347652,57.8856193],[-5.8277052,57.5988958],[-6.0384259,57.5986357],[-6.0389115,57.6459559],[-6.1981658,57.6456961],[-6.2076123,57.7600132],[-6.537067,57.7544033],[-6.5312406,57.6402392],[-6.7002056,57.6360809],[-6.6807844,57.5236293],[-6.8516915,57.5152857],[-6.8361545,57.3385811],[-6.6730158,57.3438213],[-6.674958,57.2850883],[-6.5098772,57.2850883],[-6.4982244,57.1757637],[-6.3506228,57.1820797],[-6.3312015,57.1251969],[-6.1797156,57.1230884],[-6.1719471,57.0682265],[-6.4593819,57.059779],[-6.4564687,57.1093806],[-6.6671895,57.1062165],[-6.6730158,57.002708],[-6.5021087,57.0048233],[-6.4836097,56.8917522],[-6.3266104,56.8894062],[-6.3156645,56.7799312],[-6.2146739,56.775675],[-6.2146739,56.7234965],[-6.6866107,56.7224309],[-6.6769001,56.6114413],[-6.8419809,56.607166],[-6.8400387,56.5483307],[-7.1546633,56.5461895],[-7.1488369,56.4872592],[-6.9915246,56.490476],[-6.9876404,56.4325329],[-6.6827265,56.4314591],[-6.6769001,56.5472601],[-6.5292985,56.5504717],[-6.5234721,56.4379018],[-6.3661598,56.4368281],[-6.3642177,56.3766524],[-6.5273563,56.3712749],[-6.5171745,56.2428427],[-6.4869621,56.247421],[-6.4869621,56.1893882],[-6.3001945,56.1985572],[-6.3029411,56.2581017],[-5.9019401,56.256576],[-5.8964469,56.0960466],[-6.0282829,56.0883855],[-6.0392692,56.1557502],[-6.3853385,56.1542205],[-6.3606193,55.96099],[-6.2123039,55.9640647],[-6.2047508,55.9202269],[-6.5185478,55.9129158],[-6.5061881,55.7501763],[-6.6764762,55.7409005],[-6.6599967,55.6263176],[-6.3551261,55.6232161],[-6.3578727,55.5689002],[-6.0392692,55.5720059],[-6.0310294,55.6247669],[-5.7398917,55.6309694],[-5.7371452,55.4569279],[-5.8964469,55.4600426],[-5.8964469,55.2789864],[-5.4350211,55.2821151],[-5.4405143,55.4506979],[-5.2867057,55.4569279],[-5.3086784,55.4070602],[-4.9735954,55.4008223],[-4.9845817,55.2038242],[-5.1493766,55.2038242],[-5.1411369,55.037337],[-5.2152946,55.0341891],[-5.2112173,54.8018593]],[[-2.1646559,60.1622059],[-1.9930299,60.1609801],[-1.9946862,60.1035151],[-2.1663122,60.104743],[-2.1646559,60.1622059]],[[-1.5360658,59.8570831],[-1.3653566,59.8559841],[-1.366847,59.7975565],[-1.190628,59.7964199],[-1.1862046,59.9695391],[-1.0078652,59.9683948],[-1.0041233,60.114145],[-0.8360832,60.1130715],[-0.834574,60.1716772],[-1.0074262,60.1727795],[-1.0052165,60.2583924],[-0.8299659,60.2572778],[-0.826979,60.3726551],[-0.6507514,60.3715381],[-0.6477198,60.4882292],[-0.9984896,60.4904445],[-0.9970279,60.546555],[-0.6425288,60.5443201],[-0.6394896,60.6606792],[-0.8148133,60.6617806],[-0.8132987,60.7196112],[-0.6383298,60.7185141],[-0.635467,60.8275393],[-0.797568,60.8285523],[-0.9941426,60.8297807],[-0.9954966,60.7782667],[-1.1670282,60.7793403],[-1.1700357,60.6646181],[-1.5222599,60.6668304],[-1.5237866,60.6084426],[-1.6975673,60.609536],[-1.7021271,60.4345249],[-1.5260578,60.4334111],[-1.5275203,60.3770719],[-1.8751127,60.3792746],[-1.8781372,60.2624647],[-1.7019645,60.2613443],[-1.7049134,60.1470532],[-1.528659,60.1459283],[-1.5360658,59.8570831]],[[-0.9847667,60.8943762],[-0.9860347,60.8361105],[-0.8078362,60.8351904],[-0.8065683,60.8934578],[-0.9847667,60.8943762]],[[-7.7696901,56.8788231],[-7.7614504,56.7608274],[-7.6009049,56.7641903],[-7.5972473,56.819332],[-7.4479894,56.8203948],[-7.4489319,56.8794098],[-7.2841369,56.8794098],[-7.2813904,57.0471152],[-7.1303283,57.0515969],[-7.1330749,57.511801],[-6.96828,57.5147514],[-6.9765198,57.6854668],[-6.8062317,57.6913392],[-6.8089782,57.8041985],[-6.6496765,57.8071252],[-6.6441833,57.8612267],[-6.3200866,57.8626878],[-6.3200866,58.1551617],[-6.1607849,58.1522633],[-6.1552917,58.20874],[-5.9850036,58.2101869],[-5.9904968,58.2680163],[-6.1497986,58.2665717],[-6.1415588,58.5557514],[-6.3173401,58.5557514],[-6.3091003,58.4983923],[-6.4876282,58.4955218],[-6.4876282,58.4423768],[-6.6606628,58.4395018],[-6.6469299,58.3819525],[-6.8117248,58.3805125],[-6.8117248,58.3286357],[-6.9792663,58.3286357],[-6.9710266,58.2694608],[-7.1413147,58.2680163],[-7.1403816,58.0358742],[-7.3020636,58.0351031],[-7.3030347,57.9774797],[-7.1379539,57.9777372],[-7.1413526,57.9202792],[-7.1398961,57.8640206],[-7.3020636,57.862471],[-7.298484,57.7442293],[-7.4509193,57.7456951],[-7.4550392,57.6899522],[-7.6186131,57.6906048],[-7.6198341,57.7456951],[-7.7901222,57.7442293],[-7.7873756,57.6855477],[-7.6222332,57.6853817],[-7.6173779,57.5712602],[-7.788285,57.5709998],[-7.7892561,57.512109],[-7.7038025,57.5115874],[-7.6999183,57.4546902],[-7.5367796,57.4552126],[-7.5348375,57.5126306],[-7.4581235,57.5131521],[-7.4552103,57.2824165],[-7.6115515,57.2845158],[-7.6144647,57.2272651],[-7.451326,57.2256881],[-7.451326,57.1103873],[-7.6164068,57.1088053],[-7.603783,56.8792358],[-7.7696901,56.8788231]],[[-1.7106618,59.5626284],[-1.5417509,59.562215],[-1.5423082,59.5037224],[-1.7112191,59.5041365],[-1.7106618,59.5626284]]],"terms_url":"http://geo.nls.uk/maps/","terms_text":"National Library of Scotland Historic Maps"},{"id":"NLSC-EMAP5","name":"NLSC General Map with Contour line","type":"tms","template":"http://maps.nlsc.gov.tw/S_Maps/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=EMAP5_OPENDATA&STYLE=_null&TILEMATRIXSET=EPSG:3857&TILEMATRIX=EPSG:3857:{zoom}&TILEROW={y}&TILECOL={x}&FORMAT=image/png","description":"The emap from Taiwan National Land Surveying and Mapping Center","scaleExtent":[0,15],"polygon":[[[120.4570579,26.3970586],[120.44256,26.3708009],[120.44713,26.3531513],[120.4673009,26.3405831],[120.4978723,26.3340866],[120.5141036,26.3401594],[120.5341168,26.3641649],[120.5297045,26.3842128],[120.4956661,26.4015754],[120.4570579,26.3970586]],[[119.9007221,25.9858609],[119.8960071,25.9648902],[119.9131301,25.9470399],[119.9503542,25.9278478],[119.9905563,25.9260623],[120.0198392,25.9363284],[120.0277804,25.9557423],[120.0275322,25.9845224],[119.9989937,26.0010288],[119.9404278,26.0028131],[119.9007221,25.9858609]],[[122.089,24.5485],[121.709,23.4541],[121.717,22.698],[121.818,21.95],[121.803,21.8735],[121.759,21.8087],[121.694,21.7653],[120.861,21.5631],[120.815,21.5576],[120.739,21.5728],[120.661,21.6296],[120.202,22.1809],[119.27,23.0542],[119.153,23.2049],[119.128,23.2485],[119.103,23.4],[119.118,23.4765],[119.137,23.512],[119.361,23.8885],[119.406,23.9407],[120.968,25.2284],[121.408,25.4687],[121.989,25.8147],[122.065,25.8299],[122.141,25.8147],[122.216,25.7663],[122.26,25.7015],[122.297,25.48],[122.196,24.9696],[122.089,24.5485]],[[116.6855033,20.8547596],[116.6309071,20.8149565],[116.5941695,20.7600846],[116.5797214,20.6967501],[116.5893056,20.6325865],[116.621766,20.5753367],[116.6731874,20.5319171],[116.7373678,20.5075783],[116.8065659,20.5052653],[116.8724354,20.5252581],[116.9270316,20.5651373],[116.9637692,20.6200797],[116.9782173,20.6834462],[116.9686331,20.7475883],[116.9361727,20.8047732],[116.8847512,20.8481147],[116.8205709,20.872399],[116.7513728,20.8747063],[116.6855033,20.8547596]],[[118.2261504,24.4563345],[118.2936439,24.4538527],[118.2851467,24.4751026],[118.3097372,24.4916821],[118.3767709,24.4729348],[118.4100947,24.5332285],[118.4479031,24.5284069],[118.4746394,24.4599272],[118.512992,24.4315479],[118.5065839,24.4202318],[118.4811625,24.4332439],[118.4610567,24.4089192],[118.426145,24.3970385],[118.3970055,24.4284184],[118.3765564,24.4258395],[118.3397565,24.3814628],[118.3031926,24.3705764],[118.2574234,24.4139213],[118.1381276,24.3724838],[118.1617342,24.4022433],[118.2094226,24.4139604],[118.1895784,24.4352201],[118.2176338,24.430205],[118.2261504,24.4563345]],[[120.2234496,26.30045],[120.2550843,26.3100412],[120.269888,26.3368716],[120.2591889,26.3652192],[120.2292544,26.3784823],[120.1976197,26.3688968],[120.182816,26.3420738],[120.1935151,26.3137205],[120.2234496,26.30045]],[[119.4374461,25.0047541],[119.4342024,24.9886249],[119.4541901,24.9722553],[119.4827444,24.9718376],[119.4898402,24.9937882],[119.4715877,25.0069239],[119.4374461,25.0047541]],[[119.8869914,26.180381],[119.893227,26.1203128],[119.9285109,26.1080224],[119.9779388,26.1223611],[120.0366775,26.151728],[120.1098054,26.2134921],[120.119269,26.2713663],[120.0629175,26.3172592],[119.9923706,26.3164881],[119.9467732,26.2898799],[119.9020362,26.2439761],[119.8869914,26.180381]]],"terms_url":"http://maps.nlsc.gov.tw/","terms_text":"NLSC EMAP 2015"},{"id":"MAPNIK","name":"OpenStreetMap (Standard)","type":"tms","template":"https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png","description":"The default OpenStreetMap layer.","scaleExtent":[0,19],"terms_url":"https://openstreetmap.org/","terms_text":"© OpenStreetMap contributors, CC-BY-SA","default":true},{"id":"OpenStreetMap-turistautak","name":"OpenStreetMap (turistautak)","type":"tms","template":"http://{switch:h,i,j}.tile.openstreetmap.hu/turistautak/{zoom}/{x}/{y}.png","scaleExtent":[0,18],"polygon":[[[16.1139147,46.8691038],[16.1789749,46.90662],[16.2000429,46.9415079],[16.2217547,46.9355441],[16.2462784,46.9463851],[16.2553226,46.9642125],[16.2764694,46.9626082],[16.290583,47.0139849],[16.3016199,46.9992329],[16.3414618,46.9965225],[16.3505162,47.0106313],[16.3734016,46.9985929],[16.412765,47.00475],[16.4332705,46.9927417],[16.4478119,47.003893],[16.479997,46.9941169],[16.5121988,47.0011695],[16.4635584,47.0322699],[16.4478586,47.0227481],[16.439123,47.029663],[16.445673,47.038872],[16.520323,47.056103],[16.473213,47.0736169],[16.4637199,47.09392],[16.500798,47.110058],[16.500035,47.123295],[16.5295349,47.1287419],[16.5171609,47.1496938],[16.454951,47.1425878],[16.4648728,47.1683349],[16.4555643,47.1875584],[16.4305559,47.1847022],[16.4195013,47.1949147],[16.4189215,47.2107114],[16.4371293,47.2097043],[16.4426335,47.2337117],[16.4313127,47.2527554],[16.4671512,47.2531652],[16.4892319,47.2798885],[16.4646338,47.3338455],[16.4337002,47.3528101],[16.458513,47.3670496],[16.4454619,47.4070195],[16.4831657,47.4093628],[16.4963821,47.3892659],[16.5170941,47.4100218],[16.5749054,47.4054243],[16.5807291,47.4191699],[16.661847,47.455595],[16.6706419,47.47422],[16.6523395,47.500342],[16.6895619,47.510161],[16.7147797,47.540199],[16.663545,47.567733],[16.673199,47.6049544],[16.6595343,47.6061018],[16.652758,47.622852],[16.6314207,47.6283176],[16.5739108,47.619667],[16.5147382,47.6461964],[16.4967504,47.6393149],[16.425464,47.6621679],[16.4437449,47.674205],[16.4480507,47.6964725],[16.4746984,47.6811576],[16.4872245,47.6979767],[16.5521729,47.7225519],[16.5363779,47.736785],[16.5479799,47.751544],[16.6095193,47.7603722],[16.6344148,47.7590843],[16.65729,47.7414879],[16.7209405,47.7353565],[16.7534062,47.6828165],[16.8301587,47.681058],[16.8394284,47.7045139],[16.8668943,47.7211462],[16.876679,47.6876452],[17.0937421,47.7077706],[17.0706562,47.7285366],[17.0516019,47.7938499],[17.0749479,47.8084997],[17.047139,47.8285635],[17.0519452,47.8377691],[17.0105513,47.8581765],[17.0163878,47.8673325],[17.0857537,47.8746239],[17.113171,47.9271605],[17.0917133,47.9342916],[17.1183782,47.9601083],[17.094657,47.9708775],[17.2010289,48.019992],[17.241769,48.0224651],[17.257955,47.998655],[17.334651,47.993125],[17.4029929,47.947849],[17.4539199,47.8852579],[17.5267369,47.865509],[17.5675779,47.8151289],[17.608402,47.8218859],[17.7085789,47.756678],[17.7798739,47.739487],[17.8660959,47.74575],[17.9001292,47.7392633],[17.946867,47.744668],[17.9708709,47.7578392],[18.0044103,47.7463402],[18.0380583,47.7576812],[18.2958774,47.7314616],[18.4540681,47.7651226],[18.4931553,47.7527552],[18.5590761,47.7659963],[18.6460866,47.7590921],[18.7260691,47.7890411],[18.7411784,47.8138245],[18.7920013,47.8230869],[18.8485417,47.8167221],[18.855876,47.826077],[18.828014,47.834291],[18.8135749,47.85555],[18.76353,47.8716049],[18.756858,47.896838],[18.776746,47.955092],[18.7552499,47.9763469],[18.8157429,47.993442],[18.819998,48.039676],[18.833268,48.048239],[18.8749364,48.0470707],[18.886674,48.058682],[18.9089819,48.051139],[18.9439039,48.058865],[18.9816099,48.0536009],[19.0148639,48.078179],[19.0585249,48.0573529],[19.0843619,48.072781],[19.107402,48.065596],[19.1352889,48.074146],[19.2413679,48.0536529],[19.2557819,48.0715559],[19.3031119,48.088711],[19.3865969,48.091914],[19.400018,48.082304],[19.454053,48.101436],[19.467354,48.083933],[19.4944199,48.109906],[19.492377,48.1396639],[19.5128219,48.154663],[19.504518,48.173443],[19.528967,48.190358],[19.526044,48.20313],[19.577502,48.2160149],[19.6308263,48.2500725],[19.6445239,48.2391719],[19.669857,48.239212],[19.691219,48.203894],[19.721125,48.201473],[19.74618,48.2165119],[19.7871629,48.19253],[19.7987329,48.19482],[19.8052829,48.183733],[19.782415,48.165039],[19.794812,48.153529],[19.821331,48.169081],[19.8452819,48.162742],[19.8551729,48.178431],[19.8601309,48.169409],[19.898745,48.1663119],[19.9145359,48.146863],[19.898298,48.1249019],[19.937383,48.131118],[19.9743939,48.1660049],[19.988706,48.1621679],[20.029038,48.1776849],[20.049449,48.1671999],[20.0729859,48.179606],[20.0700369,48.1917019],[20.1340909,48.225182],[20.1331879,48.253982],[20.206162,48.250979],[20.2038299,48.261906],[20.228466,48.262779],[20.2349469,48.279933],[20.286858,48.26164],[20.3257109,48.272794],[20.3374649,48.301667],[20.3656579,48.316606],[20.384077,48.3511809],[20.4098349,48.365857],[20.402532,48.382565],[20.4205349,48.403858],[20.416228,48.418536],[20.507929,48.489363],[20.5065069,48.534415],[20.537471,48.527878],[20.5464939,48.544292],[20.586595,48.535759],[20.6538739,48.561413],[20.836359,48.58284],[20.8378,48.57421],[20.8504359,48.5816329],[20.8453301,48.5665046],[20.8681549,48.551818],[20.922323,48.559453],[20.9346349,48.538341],[20.955882,48.533963],[20.9561979,48.521666],[20.9815849,48.5177669],[21.0151139,48.532313],[21.0663209,48.525894],[21.1174479,48.4910549],[21.1608749,48.521499],[21.179634,48.518232],[21.221061,48.537497],[21.305488,48.5222489],[21.313377,48.550841],[21.326875,48.554129],[21.319384,48.561201],[21.4154499,48.558951],[21.4226649,48.578821],[21.4406099,48.585104],[21.514091,48.551065],[21.5420199,48.508395],[21.6139329,48.509416],[21.6201879,48.469826],[21.663549,48.417961],[21.6645609,48.392164],[21.7017409,48.380695],[21.711871,48.357617],[21.8174139,48.332787],[21.8352029,48.3346409],[21.837213,48.363253],[21.8842979,48.356047],[21.8848429,48.367539],[21.897883,48.36256],[21.8997959,48.3702229],[21.9281859,48.3615969],[21.9268059,48.370899],[21.949198,48.378728],[21.994463,48.377323],[22.0213259,48.392749],[22.0546049,48.377528],[22.0764859,48.387241],[22.086743,48.371564],[22.1359089,48.380519],[22.131056,48.3912329],[22.152768,48.3962409],[22.1561913,48.4093076],[22.2125722,48.4256468],[22.2371405,48.4100396],[22.2654858,48.4098675],[22.2398761,48.3870055],[22.2675722,48.3611612],[22.3178106,48.3545437],[22.3132861,48.3250712],[22.3372944,48.3079113],[22.3384267,48.2792074],[22.3847547,48.2339632],[22.4006407,48.249198],[22.4328384,48.2525166],[22.456386,48.2423109],[22.4899029,48.2534237],[22.4972201,48.2395546],[22.5161491,48.237965],[22.5311088,48.2094282],[22.5711442,48.1961428],[22.5616362,48.1816066],[22.5982449,48.144756],[22.5902763,48.1073414],[22.6754492,48.091997],[22.7347192,48.119848],[22.7576242,48.1200599],[22.7703914,48.1090162],[22.772319,48.1218742],[22.8027688,48.1221112],[22.8025285,48.1070813],[22.8254256,48.1175119],[22.8364365,48.080249],[22.8611284,48.0750312],[22.8677955,48.0524256],[22.8820424,48.0548053],[22.8659692,48.0113165],[22.835562,47.9905988],[22.8407599,47.9813636],[22.8725729,47.9752683],[22.8697274,47.9659593],[22.8915652,47.9672446],[22.897435,47.9540629],[22.8473299,47.9077579],[22.7928135,47.8908586],[22.7586924,47.8941446],[22.77775,47.8422508],[22.7136344,47.8360928],[22.6801938,47.7877527],[22.6111171,47.7717455],[22.5490018,47.7722246],[22.4812121,47.8108886],[22.4513078,47.803389],[22.4313319,47.7398119],[22.3566167,47.7486206],[22.3177714,47.7660887],[22.3176236,47.7433657],[22.2851369,47.7292757],[22.264325,47.7310675],[22.2589955,47.6979057],[22.2306796,47.693196],[22.1796501,47.5916115],[22.1289245,47.5978984],[22.0942787,47.5583628],[22.0782587,47.5621299],[22.0534529,47.5474795],[22.0712176,47.5380742],[22.0617872,47.5288029],[22.0451278,47.5398919],[22.0367222,47.5326653],[22.0071886,47.48362],[22.0327909,47.4508372],[22.0238835,47.3908631],[22.0119849,47.3758016],[21.9627373,47.381053],[21.9382461,47.3725317],[21.8777922,47.2857763],[21.8872845,47.2730473],[21.8534909,47.2397622],[21.8580662,47.1873597],[21.8124804,47.1667511],[21.7924092,47.1059751],[21.7268258,47.0983882],[21.6976037,47.057915],[21.6504151,47.0408303],[21.6888701,47.0019977],[21.6678744,46.9712337],[21.6814917,46.9652089],[21.6381964,46.9330487],[21.5984455,46.9274708],[21.6142857,46.8867275],[21.6016694,46.8668202],[21.520328,46.8373749],[21.5186086,46.8000703],[21.4831761,46.7650246],[21.5263389,46.7393249],[21.529369,46.7209721],[21.4923253,46.6859652],[21.4728438,46.6959075],[21.4299047,46.693937],[21.4309553,46.6781367],[21.4546661,46.660863],[21.4162375,46.6426231],[21.4097959,46.6218052],[21.3657038,46.6379501],[21.3300499,46.6318155],[21.3139733,46.617666],[21.3012351,46.5908672],[21.3207905,46.5828562],[21.2743045,46.5407362],[21.2600254,46.5021583],[21.2744188,46.4767333],[21.2964506,46.4762973],[21.3174343,46.4507288],[21.2895176,46.4154784],[21.2963256,46.4069601],[21.2250116,46.4136899],[21.2064214,46.4033825],[21.1992563,46.3479034],[21.1762269,46.3357664],[21.180497,46.3044494],[21.1155437,46.3018529],[21.1030549,46.2624637],[21.0708792,46.2539014],[21.0660827,46.2429394],[21.0366237,46.2480392],[21.0246723,46.2665329],[20.960817,46.2623039],[20.9465849,46.2793024],[20.9250701,46.2766191],[20.9218133,46.2618129],[20.8732713,46.2877555],[20.7756538,46.2759602],[20.7490474,46.2508489],[20.7618619,46.204563],[20.727401,46.2077485],[20.7341052,46.1939355],[20.7140487,46.1660531],[20.6843592,46.1447802],[20.6549178,46.1497739],[20.6394471,46.1267602],[20.5450486,46.1790935],[20.5014839,46.190334],[20.4949436,46.1709908],[20.4592293,46.1428837],[20.3975133,46.1574709],[20.3685325,46.1528554],[20.3557074,46.1696256],[20.2968136,46.1521542],[20.2549024,46.1158522],[20.2484757,46.1300956],[20.2330132,46.1241668],[20.1817362,46.1601137],[20.1364966,46.1449476],[20.1009667,46.1772756],[20.0636156,46.1437275],[20.0346142,46.1458888],[20.0158072,46.1768354],[19.9354075,46.1764243],[19.8533469,46.1500005],[19.8179747,46.1281652],[19.7585403,46.1479754],[19.6982054,46.1879317],[19.6827672,46.1800388],[19.661508,46.1904394],[19.6317396,46.1692993],[19.5676482,46.179106],[19.5604013,46.1665762],[19.5026585,46.1424492],[19.5271208,46.1210269],[19.4645033,46.0953827],[19.4665828,46.0820437],[19.4160037,46.0460453],[19.3803957,46.0358749],[19.3640923,46.0522965],[19.2819012,46.0148048],[19.2965348,45.9881173],[19.2856472,45.9968981],[19.1479857,45.9963445],[19.1338422,46.0370993],[19.104873,46.0401673],[19.0660427,46.0001999],[19.0796791,45.9636376],[19.0059803,45.9590674],[19.0092745,45.9236559],[18.9061334,45.9353801],[18.8794572,45.9166827],[18.8647137,45.9208493],[18.8685629,45.9113361],[18.8276792,45.9051714],[18.8220041,45.9145893],[18.8075092,45.9036055],[18.809247,45.8796189],[18.7956242,45.8784488],[18.7048857,45.9181883],[18.6700246,45.9108439],[18.6596602,45.9168934],[18.6651348,45.899279],[18.6412808,45.8890396],[18.6550179,45.8742393],[18.6277704,45.8733782],[18.6148449,45.8531438],[18.6236656,45.8398531],[18.5732391,45.8137578],[18.5749849,45.8004344],[18.559716,45.8037961],[18.5223504,45.7826858],[18.4906706,45.7947167],[18.4821905,45.7655032],[18.4562828,45.7695229],[18.4450763,45.7605195],[18.446853,45.737128],[18.40763,45.7397119],[18.3918949,45.7616983],[18.3642257,45.7729364],[18.3394214,45.7471605],[18.2968157,45.7612196],[18.2440473,45.7612305],[18.2307311,45.7790328],[18.1908702,45.7878759],[18.1681939,45.7762712],[18.1246514,45.7896277],[18.1068067,45.7708256],[18.0818922,45.7645205],[17.9958808,45.7957311],[17.9302095,45.7863301],[17.9066757,45.7925692],[17.8653145,45.7670064],[17.8262748,45.8099957],[17.8089784,45.8040989],[17.7809054,45.8174884],[17.7603399,45.811923],[17.7408624,45.8295975],[17.6632915,45.8381849],[17.6276211,45.8979446],[17.5700676,45.9358204],[17.4378254,45.9503823],[17.4258964,45.9272681],[17.4108059,45.9399665],[17.392149,45.9302149],[17.3828713,45.9475733],[17.3476208,45.9423413],[17.3438769,45.9605329],[17.3537711,45.9525011],[17.3905375,45.9581914],[17.387423,45.9661823],[17.3583539,45.9642737],[17.3754852,45.9686921],[17.3751895,45.9881054],[17.3635685,45.9915442],[17.3567202,45.9735836],[17.3339583,45.9960781],[17.3319847,45.9728948],[17.3129974,45.9665347],[17.323647,45.9887776],[17.2987653,45.9838652],[17.3041996,46.0021128],[17.2579726,46.0110256],[17.29632,46.0285169],[17.2541514,46.030005],[17.270955,46.0567055],[17.2324767,46.0592034],[17.2525145,46.0664725],[17.2313144,46.0790345],[17.2019916,46.0765488],[17.2331299,46.0989644],[17.2104017,46.1001693],[17.2129734,46.113855],[17.175927,46.1084583],[17.1743424,46.1287608],[17.1865197,46.1332308],[17.1810983,46.1505485],[17.1562307,46.1585819],[17.1592857,46.1696818],[17.1261012,46.1684495],[17.1227409,46.1789791],[17.0752482,46.1889531],[17.0661614,46.2022984],[16.9735401,46.2251982],[16.973954,46.2431113],[16.9504085,46.2415285],[16.8862356,46.2814598],[16.8713682,46.3252767],[16.8802109,46.3356966],[16.8615374,46.3452401],[16.8656232,46.3556489],[16.8521959,46.3517189],[16.8498589,46.3626245],[16.8352859,46.3638195],[16.8376499,46.3748032],[16.8261732,46.3670994],[16.7933444,46.387385],[16.7592072,46.3776563],[16.7298672,46.40149],[16.7182119,46.3898704],[16.6772872,46.4494536],[16.6631785,46.4486958],[16.6663732,46.4582995],[16.6187915,46.4619875],[16.604468,46.4760773],[16.5235997,46.5053761],[16.5325768,46.5314027],[16.5176728,46.5363516],[16.5084107,46.5652692],[16.4829969,46.5660383],[16.4834008,46.5786011],[16.4455713,46.610952],[16.4248583,46.6131645],[16.385941,46.6442485],[16.3915424,46.6637257],[16.4198454,46.6584771],[16.4286335,46.6939737],[16.3689211,46.7040082],[16.3798266,46.7153869],[16.3710856,46.7222945],[16.3570587,46.7142387],[16.3185954,46.7541449],[16.3305417,46.7752119],[16.3121626,46.7780033],[16.3127666,46.797314],[16.3406373,46.8051851],[16.3508404,46.8300552],[16.3403309,46.8468762],[16.3015007,46.8595142],[16.2913867,46.8728341],[16.2332296,46.8766702],[16.1560866,46.8537074],[16.126571,46.8569079],[16.1139147,46.8691038]]],"terms_url":"http://openstreetmap.hu/","terms_text":"OpenStreetMap.hu"},{"id":"osm-gps","name":"OpenStreetMap GPS traces","type":"tms","template":"http://{switch:a,b,c}.gps-tile.openstreetmap.org/lines/{zoom}/{x}/{y}.png","description":"Public GPS traces uploaded to OpenStreetMap.","scaleExtent":[0,20],"terms_url":"http://www.openstreetmap.org/copyright","terms_text":"© OpenStreetMap contributors","terms_html":"<span style='display: inline-block; padding: 0 8px; background-color: rgba(0,0,0,0.5);'><span style='color: #eee;'>GPS Direction:</span> <span style='font-size: 15px; padding-left: 2px; font-weight: bold;'> <span style='color: #0ee;'>&larr;</span> <span style='color: #96f;'>&darr;</span> <span style='color: #6e0;'>&uarr;</span> <span style='color: #f63;'>&rarr;</span> </span></span> © <a href='http://www.openstreetmap.org/copyright'>OpenStreetMap contributors</a>.","overlay":true},{"id":"lu.geoportail.opendata.ortho2010","name":"Ortho 2010 geoportail.lu","type":"tms","template":"https://{switch:wmts3,wmts4}.geoportail.lu/opendata/wmts/ortho_2010/GLOBAL_WEBMERCATOR_4_V3/{zoom}/{x}/{y}.jpeg","scaleExtent":[0,20],"polygon":[[[5.961753,50.17631],[6.026268,50.18496],[6.033182,50.16395],[6.060695,50.15536],[6.07668,50.15913],[6.078237,50.17255],[6.101762,50.17199],[6.122501,50.16437],[6.120101,50.15594],[6.127695,50.14993],[6.113228,50.13739],[6.123691,50.13719],[6.140929,50.1305],[6.135554,50.11899],[6.138082,50.10263],[6.131085,50.09964],[6.135473,50.09119],[6.121939,50.09059],[6.126335,50.07817],[6.131858,50.07348],[6.121171,50.064],[6.114444,50.06139],[6.115631,50.05817],[6.123611,50.06323],[6.136608,50.04178],[6.130343,50.02975],[6.148207,50.02307],[6.13868,50.01572],[6.135938,50.01485],[6.131384,50.01905],[6.130243,50.01819],[6.139343,50.01116],[6.151702,50.01058],[6.145464,49.99689],[6.139657,49.9994],[6.138524,49.99829],[6.142178,49.99535],[6.150227,49.99518],[6.156247,49.98867],[6.173045,49.98589],[6.17348,49.98344],[6.170353,49.98376],[6.165487,49.97115],[6.171512,49.96298],[6.176298,49.962],[6.179954,49.95386],[6.183393,49.9548],[6.179829,49.96307],[6.183312,49.9686],[6.192774,49.97158],[6.199783,49.95352],[6.207066,49.95672],[6.212689,49.9514],[6.225023,49.95039],[6.22044,49.94369],[6.228241,49.93726],[6.22635,49.92766],[6.219133,49.92354],[6.229862,49.92125],[6.236032,49.91355],[6.231867,49.91064],[6.227694,49.91062],[6.232286,49.9072],[6.23381,49.90028],[6.246919,49.89535],[6.257809,49.88724],[6.263008,49.88101],[6.276455,49.87725],[6.281126,49.87957],[6.291661,49.87548],[6.297699,49.86673],[6.309889,49.87107],[6.315324,49.8673],[6.314651,49.86057],[6.323611,49.85188],[6.321577,49.8409],[6.327406,49.83673],[6.336561,49.83998],[6.339366,49.8507],[6.364651,49.85164],[6.402203,49.82098],[6.426434,49.81629],[6.428071,49.81186],[6.43097,49.81129],[6.441608,49.81547],[6.443442,49.81233],[6.45366,49.81275],[6.464538,49.81975],[6.47057,49.82385],[6.496805,49.81277],[6.50669,49.80993],[6.511554,49.80238],[6.51485,49.80513],[6.519604,49.81446],[6.529808,49.81048],[6.532249,49.80686],[6.530829,49.80116],[6.506225,49.78899],[6.519171,49.78344],[6.511055,49.77422],[6.520563,49.76818],[6.520516,49.76134],[6.503734,49.75086],[6.502627,49.73298],[6.507266,49.72938],[6.518092,49.7242],[6.516417,49.72129],[6.511763,49.72016],[6.504791,49.725],[6.498913,49.72639],[6.495576,49.72443],[6.507122,49.71655],[6.507884,49.71215],[6.504598,49.71227],[6.427139,49.66237],[6.439899,49.66025],[6.442511,49.65591],[6.421781,49.61809],[6.398978,49.60094],[6.379408,49.59526],[6.375507,49.58809],[6.384426,49.5801],[6.381188,49.57509],[6.369093,49.5783],[6.357913,49.57166],[6.384902,49.55817],[6.380095,49.54856],[6.358555,49.53296],[6.359322,49.52481],[6.370763,49.50545],[6.370562,49.45732],[6.333403,49.46493],[6.321894,49.47244],[6.295034,49.47928],[6.287889,49.48379],[6.271912,49.49995],[6.241327,49.50693],[6.196692,49.50331],[6.173373,49.50577],[6.160858,49.50085],[6.167099,49.49006],[6.140179,49.48525],[6.129367,49.48803],[6.127247,49.47081],[6.101403,49.46726],[6.104826,49.45076],[6.081667,49.45417],[6.077222,49.46139],[6.059167,49.46306],[6.052222,49.46028],[6.044213,49.44553],[6.025294,49.44703],[6.021545,49.45127],[6.01574,49.44885],[5.994123,49.45301],[5.976569,49.44885],[5.977725,49.45955],[5.972317,49.46087],[5.968912,49.48202],[5.9616,49.49026],[5.915781,49.49835],[5.890334,49.4948],[5.863321,49.50006],[5.84897,49.50826],[5.84828,49.51397],[5.83641,49.51817],[5.831868,49.52639],[5.84308,49.53081],[5.835622,49.54114],[5.816251,49.53325],[5.805201,49.54272],[5.859432,49.57158],[5.868663,49.587],[5.862888,49.58525],[5.851102,49.58379],[5.847116,49.58961],[5.845652,49.5981],[5.869401,49.6106],[5.881819,49.63815],[5.899978,49.63907],[5.899339,49.66239],[5.856561,49.67628],[5.856283,49.68211],[5.875703,49.71118],[5.864811,49.72331],[5.843249,49.71822],[5.82191,49.72128],[5.824894,49.73767],[5.820728,49.74878],[5.786264,49.79079],[5.765172,49.78961],[5.750937,49.79094],[5.741591,49.82126],[5.745814,49.82435],[5.737197,49.83353],[5.740531,49.84142],[5.747012,49.84048],[5.746237,49.84783],[5.753989,49.84878],[5.740663,49.85152],[5.752288,49.85922],[5.749545,49.87554],[5.775668,49.87438],[5.775053,49.88057],[5.734598,49.89341],[5.733033,49.90285],[5.757834,49.91737],[5.760393,49.93252],[5.770728,49.93711],[5.768783,49.94239],[5.768802,49.96104],[5.786724,49.96816],[5.80524,49.96677],[5.806521,49.97321],[5.831293,49.97995],[5.834616,49.98656],[5.818057,49.99936],[5.815606,50.01437],[5.847923,50.02809],[5.861889,50.04581],[5.850872,50.0563],[5.857809,50.07186],[5.880997,50.08069],[5.891965,50.12041],[5.952856,50.13384],[5.961753,50.17631]]],"terms_url":"https://data.public.lu/en/datasets/bd-l-ortho-webservices-wms-et-wmts","terms_text":"Administration du Cadastre et de la Topographie"},{"id":"lu.geoportail.opendata.ortho2013","name":"Ortho 2013 geoportail.lu","type":"tms","template":"https://{switch:wmts3,wmts4}.geoportail.lu/opendata/wmts/ortho_2013/GLOBAL_WEBMERCATOR_4_V3/{zoom}/{x}/{y}.jpeg","scaleExtent":[0,20],"polygon":[[[5.961753,50.17631],[6.026268,50.18496],[6.033182,50.16395],[6.060695,50.15536],[6.07668,50.15913],[6.078237,50.17255],[6.101762,50.17199],[6.122501,50.16437],[6.120101,50.15594],[6.127695,50.14993],[6.113228,50.13739],[6.123691,50.13719],[6.140929,50.1305],[6.135554,50.11899],[6.138082,50.10263],[6.131085,50.09964],[6.135473,50.09119],[6.121939,50.09059],[6.126335,50.07817],[6.131858,50.07348],[6.121171,50.064],[6.114444,50.06139],[6.115631,50.05817],[6.123611,50.06323],[6.136608,50.04178],[6.130343,50.02975],[6.148207,50.02307],[6.13868,50.01572],[6.135938,50.01485],[6.131384,50.01905],[6.130243,50.01819],[6.139343,50.01116],[6.151702,50.01058],[6.145464,49.99689],[6.139657,49.9994],[6.138524,49.99829],[6.142178,49.99535],[6.150227,49.99518],[6.156247,49.98867],[6.173045,49.98589],[6.17348,49.98344],[6.170353,49.98376],[6.165487,49.97115],[6.171512,49.96298],[6.176298,49.962],[6.179954,49.95386],[6.183393,49.9548],[6.179829,49.96307],[6.183312,49.9686],[6.192774,49.97158],[6.199783,49.95352],[6.207066,49.95672],[6.212689,49.9514],[6.225023,49.95039],[6.22044,49.94369],[6.228241,49.93726],[6.22635,49.92766],[6.219133,49.92354],[6.229862,49.92125],[6.236032,49.91355],[6.231867,49.91064],[6.227694,49.91062],[6.232286,49.9072],[6.23381,49.90028],[6.246919,49.89535],[6.257809,49.88724],[6.263008,49.88101],[6.276455,49.87725],[6.281126,49.87957],[6.291661,49.87548],[6.297699,49.86673],[6.309889,49.87107],[6.315324,49.8673],[6.314651,49.86057],[6.323611,49.85188],[6.321577,49.8409],[6.327406,49.83673],[6.336561,49.83998],[6.339366,49.8507],[6.364651,49.85164],[6.402203,49.82098],[6.426434,49.81629],[6.428071,49.81186],[6.43097,49.81129],[6.441608,49.81547],[6.443442,49.81233],[6.45366,49.81275],[6.464538,49.81975],[6.47057,49.82385],[6.496805,49.81277],[6.50669,49.80993],[6.511554,49.80238],[6.51485,49.80513],[6.519604,49.81446],[6.529808,49.81048],[6.532249,49.80686],[6.530829,49.80116],[6.506225,49.78899],[6.519171,49.78344],[6.511055,49.77422],[6.520563,49.76818],[6.520516,49.76134],[6.503734,49.75086],[6.502627,49.73298],[6.507266,49.72938],[6.518092,49.7242],[6.516417,49.72129],[6.511763,49.72016],[6.504791,49.725],[6.498913,49.72639],[6.495576,49.72443],[6.507122,49.71655],[6.507884,49.71215],[6.504598,49.71227],[6.427139,49.66237],[6.439899,49.66025],[6.442511,49.65591],[6.421781,49.61809],[6.398978,49.60094],[6.379408,49.59526],[6.375507,49.58809],[6.384426,49.5801],[6.381188,49.57509],[6.369093,49.5783],[6.357913,49.57166],[6.384902,49.55817],[6.380095,49.54856],[6.358555,49.53296],[6.359322,49.52481],[6.370763,49.50545],[6.370562,49.45732],[6.333403,49.46493],[6.321894,49.47244],[6.295034,49.47928],[6.287889,49.48379],[6.271912,49.49995],[6.241327,49.50693],[6.196692,49.50331],[6.173373,49.50577],[6.160858,49.50085],[6.167099,49.49006],[6.140179,49.48525],[6.129367,49.48803],[6.127247,49.47081],[6.101403,49.46726],[6.104826,49.45076],[6.081667,49.45417],[6.077222,49.46139],[6.059167,49.46306],[6.052222,49.46028],[6.044213,49.44553],[6.025294,49.44703],[6.021545,49.45127],[6.01574,49.44885],[5.994123,49.45301],[5.976569,49.44885],[5.977725,49.45955],[5.972317,49.46087],[5.968912,49.48202],[5.9616,49.49026],[5.915781,49.49835],[5.890334,49.4948],[5.863321,49.50006],[5.84897,49.50826],[5.84828,49.51397],[5.83641,49.51817],[5.831868,49.52639],[5.84308,49.53081],[5.835622,49.54114],[5.816251,49.53325],[5.805201,49.54272],[5.859432,49.57158],[5.868663,49.587],[5.862888,49.58525],[5.851102,49.58379],[5.847116,49.58961],[5.845652,49.5981],[5.869401,49.6106],[5.881819,49.63815],[5.899978,49.63907],[5.899339,49.66239],[5.856561,49.67628],[5.856283,49.68211],[5.875703,49.71118],[5.864811,49.72331],[5.843249,49.71822],[5.82191,49.72128],[5.824894,49.73767],[5.820728,49.74878],[5.786264,49.79079],[5.765172,49.78961],[5.750937,49.79094],[5.741591,49.82126],[5.745814,49.82435],[5.737197,49.83353],[5.740531,49.84142],[5.747012,49.84048],[5.746237,49.84783],[5.753989,49.84878],[5.740663,49.85152],[5.752288,49.85922],[5.749545,49.87554],[5.775668,49.87438],[5.775053,49.88057],[5.734598,49.89341],[5.733033,49.90285],[5.757834,49.91737],[5.760393,49.93252],[5.770728,49.93711],[5.768783,49.94239],[5.768802,49.96104],[5.786724,49.96816],[5.80524,49.96677],[5.806521,49.97321],[5.831293,49.97995],[5.834616,49.98656],[5.818057,49.99936],[5.815606,50.01437],[5.847923,50.02809],[5.861889,50.04581],[5.850872,50.0563],[5.857809,50.07186],[5.880997,50.08069],[5.891965,50.12041],[5.952856,50.13384],[5.961753,50.17631]]],"terms_url":"https://data.public.lu/en/datasets/bd-l-ortho-webservices-wms-et-wmts","terms_text":"Administration du Cadastre et de la Topographie"},{"id":"lu.geoportail.opendata.ortho2016","name":"Ortho 2016 geoportail.lu","type":"tms","template":"https://{switch:wmts3,wmts4}.geoportail.lu/opendata/wmts/ortho_2016/GLOBAL_WEBMERCATOR_4_V3/{zoom}/{x}/{y}.jpeg","scaleExtent":[0,20],"polygon":[[[5.961753,50.17631],[6.026268,50.18496],[6.033182,50.16395],[6.060695,50.15536],[6.07668,50.15913],[6.078237,50.17255],[6.101762,50.17199],[6.122501,50.16437],[6.120101,50.15594],[6.127695,50.14993],[6.113228,50.13739],[6.123691,50.13719],[6.140929,50.1305],[6.135554,50.11899],[6.138082,50.10263],[6.131085,50.09964],[6.135473,50.09119],[6.121939,50.09059],[6.126335,50.07817],[6.131858,50.07348],[6.121171,50.064],[6.114444,50.06139],[6.115631,50.05817],[6.123611,50.06323],[6.136608,50.04178],[6.130343,50.02975],[6.148207,50.02307],[6.13868,50.01572],[6.135938,50.01485],[6.131384,50.01905],[6.130243,50.01819],[6.139343,50.01116],[6.151702,50.01058],[6.145464,49.99689],[6.139657,49.9994],[6.138524,49.99829],[6.142178,49.99535],[6.150227,49.99518],[6.156247,49.98867],[6.173045,49.98589],[6.17348,49.98344],[6.170353,49.98376],[6.165487,49.97115],[6.171512,49.96298],[6.176298,49.962],[6.179954,49.95386],[6.183393,49.9548],[6.179829,49.96307],[6.183312,49.9686],[6.192774,49.97158],[6.199783,49.95352],[6.207066,49.95672],[6.212689,49.9514],[6.225023,49.95039],[6.22044,49.94369],[6.228241,49.93726],[6.22635,49.92766],[6.219133,49.92354],[6.229862,49.92125],[6.236032,49.91355],[6.231867,49.91064],[6.227694,49.91062],[6.232286,49.9072],[6.23381,49.90028],[6.246919,49.89535],[6.257809,49.88724],[6.263008,49.88101],[6.276455,49.87725],[6.281126,49.87957],[6.291661,49.87548],[6.297699,49.86673],[6.309889,49.87107],[6.315324,49.8673],[6.314651,49.86057],[6.323611,49.85188],[6.321577,49.8409],[6.327406,49.83673],[6.336561,49.83998],[6.339366,49.8507],[6.364651,49.85164],[6.402203,49.82098],[6.426434,49.81629],[6.428071,49.81186],[6.43097,49.81129],[6.441608,49.81547],[6.443442,49.81233],[6.45366,49.81275],[6.464538,49.81975],[6.47057,49.82385],[6.496805,49.81277],[6.50669,49.80993],[6.511554,49.80238],[6.51485,49.80513],[6.519604,49.81446],[6.529808,49.81048],[6.532249,49.80686],[6.530829,49.80116],[6.506225,49.78899],[6.519171,49.78344],[6.511055,49.77422],[6.520563,49.76818],[6.520516,49.76134],[6.503734,49.75086],[6.502627,49.73298],[6.507266,49.72938],[6.518092,49.7242],[6.516417,49.72129],[6.511763,49.72016],[6.504791,49.725],[6.498913,49.72639],[6.495576,49.72443],[6.507122,49.71655],[6.507884,49.71215],[6.504598,49.71227],[6.427139,49.66237],[6.439899,49.66025],[6.442511,49.65591],[6.421781,49.61809],[6.398978,49.60094],[6.379408,49.59526],[6.375507,49.58809],[6.384426,49.5801],[6.381188,49.57509],[6.369093,49.5783],[6.357913,49.57166],[6.384902,49.55817],[6.380095,49.54856],[6.358555,49.53296],[6.359322,49.52481],[6.370763,49.50545],[6.370562,49.45732],[6.333403,49.46493],[6.321894,49.47244],[6.295034,49.47928],[6.287889,49.48379],[6.271912,49.49995],[6.241327,49.50693],[6.196692,49.50331],[6.173373,49.50577],[6.160858,49.50085],[6.167099,49.49006],[6.140179,49.48525],[6.129367,49.48803],[6.127247,49.47081],[6.101403,49.46726],[6.104826,49.45076],[6.081667,49.45417],[6.077222,49.46139],[6.059167,49.46306],[6.052222,49.46028],[6.044213,49.44553],[6.025294,49.44703],[6.021545,49.45127],[6.01574,49.44885],[5.994123,49.45301],[5.976569,49.44885],[5.977725,49.45955],[5.972317,49.46087],[5.968912,49.48202],[5.9616,49.49026],[5.915781,49.49835],[5.890334,49.4948],[5.863321,49.50006],[5.84897,49.50826],[5.84828,49.51397],[5.83641,49.51817],[5.831868,49.52639],[5.84308,49.53081],[5.835622,49.54114],[5.816251,49.53325],[5.805201,49.54272],[5.859432,49.57158],[5.868663,49.587],[5.862888,49.58525],[5.851102,49.58379],[5.847116,49.58961],[5.845652,49.5981],[5.869401,49.6106],[5.881819,49.63815],[5.899978,49.63907],[5.899339,49.66239],[5.856561,49.67628],[5.856283,49.68211],[5.875703,49.71118],[5.864811,49.72331],[5.843249,49.71822],[5.82191,49.72128],[5.824894,49.73767],[5.820728,49.74878],[5.786264,49.79079],[5.765172,49.78961],[5.750937,49.79094],[5.741591,49.82126],[5.745814,49.82435],[5.737197,49.83353],[5.740531,49.84142],[5.747012,49.84048],[5.746237,49.84783],[5.753989,49.84878],[5.740663,49.85152],[5.752288,49.85922],[5.749545,49.87554],[5.775668,49.87438],[5.775053,49.88057],[5.734598,49.89341],[5.733033,49.90285],[5.757834,49.91737],[5.760393,49.93252],[5.770728,49.93711],[5.768783,49.94239],[5.768802,49.96104],[5.786724,49.96816],[5.80524,49.96677],[5.806521,49.97321],[5.831293,49.97995],[5.834616,49.98656],[5.818057,49.99936],[5.815606,50.01437],[5.847923,50.02809],[5.861889,50.04581],[5.850872,50.0563],[5.857809,50.07186],[5.880997,50.08069],[5.891965,50.12041],[5.952856,50.13384],[5.961753,50.17631]]],"terms_url":"https://data.public.lu/en/datasets/bd-l-ortho-webservices-wms-et-wmts","terms_text":"Administration du Cadastre et de la Topographie","best":true},{"id":"OS-historic-25k-OSM_Limited","name":"OS 1:25k historic (OSM)","type":"tms","template":"http://ooc.openstreetmap.org/os1/{zoom}/{x}/{y}.jpg","scaleExtent":[6,17],"polygon":[[[-6.4585407,49.9044128],[-6.3872009,49.9841116],[-6.2296827,49.9896159],[-6.2171269,49.8680087],[-6.4551164,49.8591793],[-6.4585407,49.9044128]],[[-1.4495137,60.8634056],[-0.7167114,60.8545122],[-0.7349744,60.4359756],[-0.6938826,60.4168218],[-0.7258429,60.3942735],[-0.7395401,60.0484714],[-0.9267357,60.0461918],[-0.9381501,59.8266157],[-1.4586452,59.831205],[-1.4455187,60.0535999],[-1.463211,60.0535999],[-1.4643524,60.0630002],[-1.5716475,60.0638546],[-1.5693646,60.1790005],[-1.643558,60.1807033],[-1.643558,60.1892162],[-1.8216221,60.1894999],[-1.8204807,60.3615507],[-1.8415973,60.3697345],[-1.8216221,60.3832755],[-1.8179852,60.5934321],[-1.453168,60.5934321],[-1.4495137,60.8634056]],[[-4.9089213,54.4242078],[-4.282598,54.4429861],[-4.2535417,54.029769],[-4.8766366,54.0221831],[-4.9089213,54.4242078]],[[-5.8667408,59.1444603],[-5.7759966,59.1470945],[-5.7720016,59.1014052],[-5.8621751,59.0990605],[-5.8667408,59.1444603]],[[-1.7065887,59.5703599],[-1.5579165,59.5693481],[-1.5564897,59.4965695],[-1.7054472,59.4975834],[-1.7065887,59.5703599]],[[-7.6865827,58.2940975],[-7.5330594,58.3006957],[-7.5256401,58.2646905],[-7.6797341,58.2577853],[-7.6865827,58.2940975]],[[-4.5338281,59.0359871],[-4.481322,59.0371616],[-4.4796099,59.0186583],[-4.5332574,59.0180707],[-4.5338281,59.0359871]],[[-8.6710698,57.8769896],[-8.4673234,57.8897332],[-8.4467775,57.7907],[-8.6510947,57.7779213],[-8.6710698,57.8769896]],[[-5.2395519,50.3530581],[-5.7920073,50.3384899],[-5.760047,49.9317027],[-4.6551363,49.9581461],[-4.677965,50.2860073],[-4.244219,50.2801723],[-4.2487848,50.2042525],[-3.3812929,50.2042525],[-3.4223846,50.5188201],[-3.1164796,50.5246258],[-3.1210453,50.6579592],[-2.6736357,50.6619495],[-2.5953453,50.6394325],[-2.5905026,50.5728419],[-2.4791203,50.5733545],[-2.4758919,50.5066704],[-2.3967943,50.5056438],[-2.401637,50.5723293],[-1.0400296,50.5718167],[-1.0335726,50.7059289],[-0.549302,50.7038843],[-0.5460736,50.7886618],[-0.0924734,50.7856002],[-0.0876307,50.7181949],[0.4789659,50.7120623],[0.487037,50.8182467],[0.9761503,50.8049868],[0.9922927,51.0126311],[1.4491213,51.0004424],[1.4781775,51.4090372],[1.0229632,51.4271576],[1.035877,51.7640881],[1.6105448,51.7500992],[1.646058,52.1560003],[1.7267698,52.1540195],[1.749369,52.4481811],[1.7870672,52.4811624],[1.759102,52.522505],[1.7933451,52.9602749],[0.3798147,52.9958468],[0.3895238,53.2511239],[0.3478614,53.2511239],[0.3238912,53.282186],[0.3461492,53.6538501],[0.128487,53.6575466],[0.116582,53.6674703],[0.1350586,54.0655731],[-0.0609831,54.065908],[-0.0414249,54.4709448],[-0.5662701,54.4771794],[-0.5592078,54.6565127],[-1.1665638,54.6623485],[-1.1637389,54.842611],[-1.3316194,54.843909],[-1.3257065,55.2470842],[-1.529453,55.2487108],[-1.524178,55.6540122],[-1.7638798,55.6540122],[-1.7733693,55.9719116],[-2.1607858,55.9682981],[-2.1543289,56.0621387],[-2.4578051,56.0585337],[-2.4190635,56.641717],[-2.0962164,56.641717],[-2.0833025,57.0021322],[-1.9283359,57.0126802],[-1.9180966,57.3590895],[-1.7502161,57.3625721],[-1.7695869,57.7608634],[-3.6937554,57.7574187],[-3.7066693,57.9806386],[-3.5969013,57.9772149],[-3.6033582,58.1207277],[-3.0222335,58.1309566],[-3.0286905,58.5410788],[-2.8478961,58.530968],[-2.86081,58.8430508],[-2.679624,58.8414991],[-2.6841897,58.885175],[-2.6339665,58.9052239],[-2.679624,58.9335083],[-2.6887555,59.0229231],[-2.3668703,59.0229231],[-2.3702946,59.2652861],[-2.3429001,59.2821989],[-2.3714361,59.2996861],[-2.3737189,59.3707083],[-2.3429001,59.385825],[-2.3725775,59.400354],[-2.3714361,59.4259098],[-3.0734196,59.4230067],[-3.0711368,59.3433649],[-3.103097,59.3311405],[-3.0745611,59.3136695],[-3.0722782,59.232603],[-3.3850319,59.1484167],[-3.3747589,58.9352753],[-3.5653789,58.9323303],[-3.554829,58.69759],[-5.2808579,58.6667732],[-5.2534159,58.3514125],[-5.5068508,58.3437887],[-5.4761804,58.0323557],[-5.8974958,58.0212436],[-5.8522972,57.6171758],[-6.1396311,57.6137174],[-6.1541592,57.7423183],[-6.2913692,57.7380102],[-6.3365678,58.1398784],[-6.1121891,58.1466944],[-6.1473778,58.5106285],[-6.2934817,58.5416182],[-6.8413713,58.2977321],[-7.0057382,58.2929331],[-7.1016189,58.2064403],[-7.2573132,58.1793148],[-7.2531092,58.1004928],[-7.4070698,58.0905566],[-7.391347,57.7911354],[-7.790991,57.7733151],[-7.7624215,57.5444165],[-7.698501,57.1453194],[-7.7943817,57.1304547],[-7.716764,56.7368628],[-7.0122067,56.7654359],[-6.979922,56.5453858],[-7.0638622,56.5453858],[-7.0444914,56.3562587],[-6.500676,56.3812917],[-6.4491433,55.9793649],[-6.563287,55.9691456],[-6.5393742,55.7030135],[-6.5595521,55.6907321],[-6.5345315,55.6761713],[-6.5216176,55.5704434],[-5.8912587,55.5923416],[-5.8560127,55.2320733],[-5.2293639,55.2515958],[-5.1837064,54.6254139],[-3.6655956,54.6518373],[-3.6496155,54.4320023],[-3.5400375,54.4306744],[-3.530906,54.0290181],[-3.0697656,54.030359],[-3.0675737,53.8221388],[-3.0804876,53.7739911],[-3.0619239,53.7477488],[-3.0611168,53.6737049],[-3.2144691,53.6708361],[-3.2057699,53.4226163],[-3.2799632,53.355224],[-3.2896655,53.3608441],[-3.3327547,53.364931],[-3.3761293,53.3540318],[-4.0888976,53.3433102],[-4.0945474,53.4612036],[-4.697412,53.4448624],[-4.6882805,53.3318598],[-4.7202407,53.2895771],[-4.6837148,53.2486184],[-4.6768661,53.1542644],[-4.8480816,53.1446807],[-4.8178336,52.7440299],[-4.2545751,52.7558939],[-4.228876,52.254876],[-4.2607571,52.2536408],[-4.2724603,52.2432637],[-4.8136263,52.230095],[-4.8079191,52.1138892],[-5.3889104,52.0991668],[-5.3717888,51.9129667],[-5.4208706,51.9101502],[-5.414022,51.8453218],[-5.3683645,51.8474373],[-5.3466772,51.5595332],[-4.773676,51.5758518],[-4.7656859,51.4885146],[-4.1915432,51.4970427],[-4.1869775,51.4344663],[-3.6151177,51.4444274],[-3.6105519,51.3746543],[-3.1494115,51.3789292],[-3.1494115,51.2919281],[-4.3038735,51.2745907],[-4.2861169,51.0508721],[-4.8543277,51.0366633],[-4.8372201,50.7212787],[-5.2618345,50.7082694],[-5.2395519,50.3530581]],[[-2.1502671,60.171318],[-2.0030218,60.1696146],[-2.0013096,60.0997023],[-2.148555,60.1011247],[-2.1502671,60.171318]],[[-6.2086011,59.1163488],[-6.1229934,59.1166418],[-6.121852,59.0714985],[-6.2097426,59.0714985],[-6.2086011,59.1163488]],[[-4.4159559,59.0889036],[-4.4212022,59.0770848],[-4.3971904,59.0779143],[-4.3913388,59.0897328],[-4.4159559,59.0889036]]]},{"id":"OS-New_Popular_Edition-historic","name":"OS New Popular Edition historic","type":"tms","template":"http://ooc.openstreetmap.org/npe/{zoom}/{x}/{y}.png","polygon":[[[-5.8,49.8],[-5.8,55.8],[1.9,55.8],[1.9,49.8],[-5.8,49.8]]]},{"id":"OS-OpenData_Locator","name":"OS OpenData Locator","type":"tms","template":"http://tiles.itoworld.com/os_locator/{zoom}/{x}/{y}.png","polygon":[[[-9,49.8],[-9,61.1],[1.9,61.1],[1.9,49.8],[-9,49.8]]],"overlay":true},{"id":"OS-OpenData_StreetView","name":"OS OpenData StreetView","type":"tms","template":"http://os.openstreetmap.org/sv/{zoom}/{x}/{y}.png","scaleExtent":[1,18],"polygon":[[[-5.8292886,50.0229734],[-5.8292886,50.254819],[-5.373356,50.254819],[-5.373356,50.3530588],[-5.1756021,50.3530588],[-5.1756021,50.5925406],[-4.9970743,50.5925406],[-4.9970743,50.6935617],[-4.7965738,50.6935617],[-4.7965738,50.7822112],[-4.6949503,50.7822112],[-4.6949503,50.9607371],[-4.6043131,50.9607371],[-4.6043131,51.0692066],[-4.3792215,51.0692066],[-4.3792215,51.2521782],[-3.9039346,51.2521782],[-3.9039346,51.2916998],[-3.7171671,51.2916998],[-3.7171671,51.2453014],[-3.1486246,51.2453014],[-3.1486246,51.362067],[-3.7446329,51.362067],[-3.7446329,51.4340386],[-3.8297769,51.4340386],[-3.8297769,51.5298246],[-4.0852091,51.5298246],[-4.0852091,51.4939284],[-4.3792215,51.4939284],[-4.3792215,51.5427168],[-5.1444195,51.5427168],[-5.1444195,51.6296003],[-5.7387103,51.6296003],[-5.7387103,51.774037],[-5.5095393,51.774037],[-5.5095393,51.9802596],[-5.198799,51.9802596],[-5.198799,52.0973358],[-4.8880588,52.0973358],[-4.8880588,52.1831557],[-4.4957492,52.1831557],[-4.4957492,52.2925739],[-4.3015365,52.2925739],[-4.3015365,52.3685318],[-4.1811246,52.3685318],[-4.1811246,52.7933685],[-4.4413696,52.7933685],[-4.4413696,52.7369614],[-4.8569847,52.7369614],[-4.8569847,52.9317255],[-4.7288044,52.9317255],[-4.7288044,53.5038599],[-4.1578191,53.5038599],[-4.1578191,53.4113498],[-3.3110518,53.4113498],[-3.3110518,53.5038599],[-3.2333667,53.5038599],[-3.2333667,54.0159169],[-3.3926211,54.0159169],[-3.3926211,54.1980953],[-3.559644,54.1980953],[-3.559644,54.433732],[-3.7188984,54.433732],[-3.7188984,54.721897],[-4.3015365,54.721897],[-4.3015365,54.6140739],[-5.0473132,54.6140739],[-5.0473132,54.7532915],[-5.2298731,54.7532915],[-5.2298731,55.2190799],[-5.6532567,55.2190799],[-5.6532567,55.250088],[-5.8979647,55.250088],[-5.8979647,55.4822462],[-6.5933212,55.4822462],[-6.5933212,56.3013441],[-7.1727691,56.3013441],[-7.1727691,56.5601822],[-6.8171722,56.5601822],[-6.8171722,56.6991713],[-6.5315276,56.6991713],[-6.5315276,56.9066964],[-6.811679,56.9066964],[-6.811679,57.3716613],[-6.8721038,57.3716613],[-6.8721038,57.5518893],[-7.0973235,57.5518893],[-7.0973235,57.2411085],[-7.1742278,57.2411085],[-7.1742278,56.9066964],[-7.3719817,56.9066964],[-7.3719817,56.8075885],[-7.5202972,56.8075885],[-7.5202972,56.7142479],[-7.8306806,56.7142479],[-7.8306806,56.8994605],[-7.6494061,56.8994605],[-7.6494061,57.4739617],[-7.8306806,57.4739617],[-7.8306806,57.7915584],[-7.4736249,57.7915584],[-7.4736249,58.086063],[-7.1879804,58.086063],[-7.1879804,58.367197],[-6.8034589,58.367197],[-6.8034589,58.4155786],[-6.638664,58.4155786],[-6.638664,58.4673277],[-6.5178143,58.4673277],[-6.5178143,58.5625632],[-6.0536224,58.5625632],[-6.0536224,58.1568843],[-6.1470062,58.1568843],[-6.1470062,58.1105865],[-6.2799798,58.1105865],[-6.2799798,57.7122664],[-6.1591302,57.7122664],[-6.1591302,57.6667563],[-5.9339104,57.6667563],[-5.9339104,57.8892524],[-5.80643,57.8892524],[-5.80643,57.9621767],[-5.6141692,57.9621767],[-5.6141692,58.0911236],[-5.490819,58.0911236],[-5.490819,58.3733281],[-5.3199118,58.3733281],[-5.3199118,58.75015],[-3.5719977,58.75015],[-3.5719977,59.2091788],[-3.1944501,59.2091788],[-3.1944501,59.4759216],[-2.243583,59.4759216],[-2.243583,59.1388749],[-2.4611012,59.1388749],[-2.4611012,58.8185938],[-2.7407675,58.8185938],[-2.7407675,58.5804743],[-2.9116746,58.5804743],[-2.9116746,58.1157523],[-3.4865441,58.1157523],[-3.4865441,57.740386],[-1.7153245,57.740386],[-1.7153245,57.2225558],[-1.9794538,57.2225558],[-1.9794538,56.8760742],[-2.1658979,56.8760742],[-2.1658979,56.6333186],[-2.3601106,56.6333186],[-2.3601106,56.0477521],[-1.9794538,56.0477521],[-1.9794538,55.8650949],[-1.4745008,55.8650949],[-1.4745008,55.2499926],[-1.3221997,55.2499926],[-1.3221997,54.8221737],[-1.0550014,54.8221737],[-1.0550014,54.6746628],[-0.6618765,54.6746628],[-0.6618765,54.5527463],[-0.3247617,54.5527463],[-0.3247617,54.2865195],[0.0092841,54.2865195],[0.0092841,53.7938518],[0.2081962,53.7938518],[0.2081962,53.5217726],[0.4163548,53.5217726],[0.4163548,53.0298851],[1.4273388,53.0298851],[1.4273388,52.92021],[1.8333912,52.92021],[1.8333912,52.042488],[1.5235504,52.042488],[1.5235504,51.8261335],[1.2697049,51.8261335],[1.2697049,51.6967453],[1.116651,51.6967453],[1.116651,51.440346],[1.5235504,51.440346],[1.5235504,51.3331831],[1.4507565,51.3331831],[1.4507565,51.0207553],[1.0699883,51.0207553],[1.0699883,50.9008416],[0.7788126,50.9008416],[0.7788126,50.729843],[-0.7255952,50.729843],[-0.7255952,50.7038437],[-1.0074383,50.7038437],[-1.0074383,50.5736307],[-2.3625252,50.5736307],[-2.3625252,50.4846421],[-2.4987805,50.4846421],[-2.4987805,50.5736307],[-3.4096378,50.5736307],[-3.4096378,50.2057837],[-3.6922446,50.2057837],[-3.6922446,50.1347737],[-5.005468,50.1347737],[-5.005468,49.9474456],[-5.2839506,49.9474456],[-5.2839506,50.0229734],[-5.8292886,50.0229734]],[[-6.4580707,49.8673563],[-6.4580707,49.9499935],[-6.3978807,49.9499935],[-6.3978807,50.0053797],[-6.1799606,50.0053797],[-6.1799606,49.9168614],[-6.2540201,49.9168614],[-6.2540201,49.8673563],[-6.4580707,49.8673563]],[[-5.8343165,49.932156],[-5.8343165,49.9754641],[-5.7683254,49.9754641],[-5.7683254,49.932156],[-5.8343165,49.932156]],[[-1.9483797,60.6885737],[-1.9483797,60.3058841],[-1.7543149,60.3058841],[-1.7543149,60.1284428],[-1.5754914,60.1284428],[-1.5754914,59.797917],[-1.0316959,59.797917],[-1.0316959,60.0354518],[-0.6626918,60.0354518],[-0.6626918,60.9103862],[-1.1034395,60.9103862],[-1.1034395,60.8040022],[-1.3506319,60.8040022],[-1.3506319,60.6885737],[-1.9483797,60.6885737]],[[-2.203381,60.1968568],[-2.203381,60.0929443],[-1.9864011,60.0929443],[-1.9864011,60.1968568],[-2.203381,60.1968568]],[[-1.7543149,59.5698289],[-1.7543149,59.4639383],[-1.5373349,59.4639383],[-1.5373349,59.5698289],[-1.7543149,59.5698289]],[[-4.5585981,59.1370518],[-4.5585981,58.9569099],[-4.2867004,58.9569099],[-4.2867004,59.1370518],[-4.5585981,59.1370518]],[[-6.2787732,59.2025744],[-6.2787732,59.0227769],[-5.6650612,59.0227769],[-5.6650612,59.2025744],[-6.2787732,59.2025744]],[[-8.7163482,57.9440556],[-8.7163482,57.7305936],[-8.3592926,57.7305936],[-8.3592926,57.9440556],[-8.7163482,57.9440556]],[[-7.6077005,50.4021026],[-7.6077005,50.2688657],[-7.3907205,50.2688657],[-7.3907205,50.4021026],[-7.6077005,50.4021026]],[[-7.7304303,58.3579902],[-7.7304303,58.248313],[-7.5134503,58.248313],[-7.5134503,58.3579902],[-7.7304303,58.3579902]]]},{"id":"OS-Scottish_Popular-historic","name":"OS Scottish Popular historic","type":"tms","template":"http://ooc.openstreetmap.org/npescotland/tiles/{zoom}/{x}/{y}.jpg","scaleExtent":[6,15],"polygon":[[[-7.8,54.5],[-7.8,61.1],[-1.1,61.1],[-1.1,54.5],[-7.8,54.5]]]},{"id":"Pangasinan_Bulacan_HiRes","name":"Pangasinán/Bulacan (Philippines HiRes)","type":"tms","template":"http://gravitystorm.dev.openstreetmap.org/imagery/philippines/{zoom}/{x}/{y}.png","scaleExtent":[12,19],"polygon":[[[120.336593,15.985768],[120.445995,15.984],[120.446134,15.974459],[120.476464,15.974592],[120.594247,15.946832],[120.598064,16.090795],[120.596537,16.197999],[120.368537,16.218527],[120.347576,16.042308],[120.336593,15.985768]],[[120.8268,15.3658],[121.2684,15.2602],[121.2699,14.7025],[120.695,14.8423],[120.8268,15.3658]]]},{"id":"Actueel_ortho25_WMTS","name":"PDOK Luchtfoto Beeldmateriaal 25cm","type":"tms","template":"http://geodata.nationaalgeoregister.nl/luchtfoto/wmts?FORMAT=image/jpeg&SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=2016_ortho25&STYLE=&FORMAT=image/jpeg&tileMatrixSet=OGC:1.0:GoogleMapsCompatible&tileMatrix={zoom}&tileRow={y}&tileCol={x}","description":"Landsdekkende dataset 25cm resolutie kleuren luchtfotos van de meest recente jaargang.","scaleExtent":[0,18],"polygon":[[[3.1437689,51.3598403],[3.1575018,51.2411346],[3.3387762,51.1154412],[3.9128119,51.0585083],[4.6571356,51.2806657],[4.8933416,51.2634825],[5.1789862,51.1257851],[5.3849798,51.1309561],[5.5442816,51.056782],[5.4206854,50.8595581],[5.4673773,50.7032633],[5.6568914,50.6192567],[6.1485296,50.6214349],[6.3023382,50.8578243],[6.2995916,50.9543819],[6.2638861,51.0183545],[6.3723761,51.0925902],[6.4012152,51.2011393],[6.3737494,51.2510206],[6.4451605,51.3158713],[6.4204413,51.5496009],[6.343537,51.6792182],[6.796723,51.7642909],[7.046662,51.9102418],[7.0713812,52.0455856],[7.2718817,52.1704147],[7.3075872,52.3855111],[7.2059637,52.5319494],[7.282868,52.614576],[7.2993475,52.7785318],[7.4421698,52.9782705],[7.43393,53.2831352],[7.0439154,53.5515877],[6.7829901,53.6363531],[6.2391668,53.5401639],[5.6871039,53.5124077],[5.173493,53.4388477],[4.8164373,53.2338445],[4.6516424,53.0658312],[4.5417791,52.4859784],[4.3220526,52.1956753],[4.08104,52.0136897],[4.0219885,52.0162253],[3.9368445,51.9637937],[3.9519507,51.8807927],[3.844834,51.8494157],[3.6237341,51.7075226],[3.6553198,51.6606936],[3.6333471,51.6274583],[3.5468298,51.622343],[3.3957678,51.5609145],[3.3820349,51.5173524],[3.4987646,51.4326715],[3.3298498,51.3855587],[3.1437689,51.3598403]]],"terms_text":"Nationaal Georegister, CC BY 4.0","best":true},{"id":"PNOA-Spain-TMS","name":"PNOA Spain","type":"tms","template":"http://www.ign.es/wmts/pnoa-ma?request=GetTile&service=WMTS&VERSION=1.0.0&Layer=OI.OrthoimageCoverage&Style=default&Format=image/png&TileMatrixSet=GoogleMapsCompatible&TileMatrix={zoom}&TileRow={y}&TileCol={x}","polygon":[[[-17.8846298,28.4460601],[-17.8939535,28.5225529],[-18.0212548,28.7481927],[-18.0224091,28.8038375],[-17.9424017,28.8726124],[-17.8911792,28.8737099],[-17.8903302,28.8515102],[-17.7675902,28.8537764],[-17.7669837,28.8312183],[-17.7412714,28.8319975],[-17.7394926,28.7642235],[-17.7139824,28.7649677],[-17.7129312,28.7303731],[-17.7574427,28.6931782],[-17.7570788,28.6741254],[-17.7457913,28.6743524],[-17.7457266,28.6165627],[-17.7519687,28.5833675],[-17.7622536,28.5591958],[-17.7833086,28.541667],[-17.7831575,28.4936643],[-17.808611,28.4925024],[-17.8060072,28.4468974],[-17.8846298,28.4460601]],[[-18.1661033,27.7851643],[-18.163494,27.6949247],[-18.0889827,27.6963366],[-18.0873398,27.6738724],[-18.0364092,27.6753701],[-18.0350079,27.6302571],[-17.9589987,27.6323976],[-17.8603269,27.7926025],[-17.8630328,27.8368793],[-17.8884015,27.8364947],[-17.8891263,27.8590536],[-17.9906491,27.8567467],[-18.0386803,27.7655831],[-18.1146412,27.7637873],[-18.1154627,27.7863613],[-18.1661033,27.7851643]],[[-17.36038,28.0639801],[-17.3629657,28.1757247],[-17.3375583,28.1763688],[-17.3384577,28.2213012],[-17.1857883,28.2238767],[-17.0820788,28.1351849],[-17.0808422,28.0679977],[-17.1315446,28.0668073],[-17.1563337,28.0214628],[-17.2321063,28.0203711],[-17.2319938,27.9980388],[-17.2576823,27.9978403],[-17.257851,28.0199741],[-17.3086658,28.0192298],[-17.36038,28.0639801]],[[-16.9278171,28.3275779],[-16.9286591,28.3721879],[-16.8776666,28.3729288],[-16.8780707,28.3954191],[-16.5214259,28.4226146],[-16.4457117,28.491135],[-16.4462506,28.535972],[-16.4205859,28.5362679],[-16.4209227,28.5588419],[-16.3443329,28.5597589],[-16.3446023,28.5822095],[-16.1912541,28.5837179],[-16.1916246,28.6068435],[-16.1279344,28.6078193],[-16.1277997,28.5921762],[-16.0995079,28.5925015],[-16.0993395,28.5163822],[-16.1648148,28.5161158],[-16.1647474,28.4938583],[-16.2385755,28.4484704],[-16.2653516,28.4476116],[-16.2658569,28.4030038],[-16.3167484,28.4017594],[-16.3163105,28.380189],[-16.3420763,28.3795075],[-16.3408301,28.2892963],[-16.415837,28.1976134],[-16.415096,28.1311312],[-16.5153297,28.0164796],[-16.6168433,28.01532],[-16.6168096,27.9930469],[-16.7184243,27.9919168],[-16.7190979,28.0371426],[-16.7446952,28.0367859],[-16.7453351,28.0818146],[-16.7706967,28.0816065],[-16.8223966,28.1259036],[-16.8231712,28.1708652],[-16.8487012,28.1707464],[-16.8502842,28.260791],[-16.8756457,28.2605537],[-16.8760836,28.2832162],[-16.9015125,28.2827713],[-16.9023882,28.3279337],[-16.9278171,28.3275779]],[[-15.8537427,27.9008901],[-15.8542032,27.9901812],[-15.828953,27.9906555],[-15.8291065,28.035578],[-15.7782992,28.0363232],[-15.7532793,28.0814298],[-15.7278756,28.0815652],[-15.7282593,28.1718567],[-15.4989741,28.1728039],[-15.4987438,28.1504075],[-15.4497785,28.1507459],[-15.4501622,28.1961425],[-15.3972827,28.1961425],[-15.3964385,28.0383554],[-15.3710348,28.0380167],[-15.3706511,28.0153212],[-15.3457847,28.0153212],[-15.3454777,27.9254406],[-15.3708046,27.9252372],[-15.3705743,27.8352137],[-15.395978,27.8347387],[-15.4209979,27.7879673],[-15.4718052,27.7893932],[-15.471882,27.7666454],[-15.522766,27.7667813],[-15.5477092,27.7216112],[-15.6236132,27.7213395],[-15.6241504,27.741991],[-15.7007451,27.7433495],[-15.801669,27.8110501],[-15.8537427,27.9008901]],[[-14.5215621,28.0467778],[-14.5224358,28.1184131],[-14.4157526,28.1156076],[-14.2168794,28.2278805],[-14.2153651,28.33903],[-14.1641672,28.4528287],[-14.1115132,28.4747955],[-14.0335806,28.7226671],[-13.9565217,28.7449351],[-13.9561722,28.7665857],[-13.8290221,28.7664325],[-13.8289639,28.7879765],[-13.8000741,28.7879255],[-13.8012972,28.7189894],[-13.827566,28.719347],[-13.8278572,28.6517968],[-13.8025786,28.651899],[-13.8033941,28.5384172],[-13.8288474,28.5384684],[-13.8315061,28.3970177],[-13.9158189,28.2241438],[-13.9856445,28.2235696],[-14.0369588,28.1795787],[-14.1387139,28.1799894],[-14.1386556,28.1579103],[-14.2153651,28.1578076],[-14.2147244,28.1118888],[-14.2913173,28.0452356],[-14.3319673,28.0368713],[-14.4457846,28.0469834],[-14.4466583,28.0657961],[-14.4962835,28.0682631],[-14.495934,28.0458525],[-14.5215621,28.0467778]],[[-13.800662,28.8456579],[-13.8009273,28.8231121],[-13.775688,28.8230539],[-13.69729,28.8898184],[-13.69729,28.9127744],[-13.6072498,28.9117991],[-13.4388551,29.0002417],[-13.4374559,29.1351289],[-13.4117005,29.1349931],[-13.4105556,29.2229789],[-13.4592801,29.255586],[-13.4597392,29.2942023],[-13.5091254,29.2945638],[-13.5100581,29.3163453],[-13.5635382,29.3172941],[-13.5640564,29.2713764],[-13.5389228,29.2711956],[-13.5389747,29.2500375],[-13.5661293,29.2501279],[-13.5665956,29.2030039],[-13.5156549,29.2022349],[-13.5156549,29.1820579],[-13.5398038,29.1827819],[-13.5408921,29.137528],[-13.65782,29.1368528],[-13.713222,29.0935079],[-13.7663353,29.0934533],[-13.8502463,29.0165937],[-13.8518224,28.983425],[-13.8524443,28.914861],[-13.9013122,28.89245],[-13.9024005,28.8469779],[-13.800662,28.8456579]],[[1.6479916,38.9990693],[1.7321668,38.9993635],[1.7314703,39.0441733],[1.6489512,39.0431944],[1.6481552,39.1276358],[1.3948608,39.1265691],[1.3954412,39.0864199],[1.2281145,39.0852615],[1.2291095,39.0028958],[1.1448657,39.0018003],[1.1452803,38.8319988],[1.3113632,38.8331615],[1.3121924,38.7906483],[1.3946949,38.7916178],[1.3951924,38.7529597],[1.3112803,38.7519251],[1.3125919,38.6238804],[1.6489036,38.6251112],[1.6480745,38.7111504],[1.58456,38.7101152],[1.5811604,38.7005387],[1.5491544,38.7002798],[1.5197188,38.7092094],[1.50355,38.7253185],[1.4813282,38.9155064],[1.5518906,38.9254411],[1.5667328,38.9566554],[1.6487378,38.9583318],[1.6479916,38.9990693]],[[2.5450749,39.4166673],[2.43933,39.4161122],[2.438714,39.4846853],[2.439022,39.4993424],[2.3122308,39.4993424],[2.3119228,39.5417911],[2.2290722,39.5409994],[2.2283536,39.6260571],[2.3460076,39.6270851],[2.9270445,39.9601558],[3.1456647,39.9600498],[3.1460753,40.0019797],[3.2313899,40.0019797],[3.2312872,39.8329231],[3.1482313,39.8331596],[3.1484366,39.7935717],[3.4814817,39.7931773],[3.4803472,39.5959027],[3.3150618,39.4784606],[3.3146179,39.3785504],[3.0830178,39.2499355],[2.9798608,39.2501482],[2.9790395,39.3334971],[2.7287424,39.3334177],[2.7288451,39.4581361],[2.6456865,39.4577397],[2.6453785,39.4996593],[2.5452802,39.4994216],[2.5450749,39.4166673]],[[3.8120402,40.0434431],[3.729082,40.0437979],[3.7286185,39.9584155],[3.8126633,39.9576011],[3.8122771,39.9164393],[3.9608975,39.9159813],[4.1938142,39.791308],[4.3150279,39.7905799],[4.3159934,39.8329294],[4.3987393,39.8320396],[4.3973664,39.9185834],[4.3158003,39.9193274],[4.3161865,40.0433985],[4.2318959,40.0443594],[4.2324752,40.0847793],[4.1491501,40.086109],[4.1490623,40.1255157],[4.0627981,40.1272166],[4.0624217,40.0849941],[3.8128687,40.085294],[3.8120402,40.0434431]],[[-8.8910646,41.8228891],[-9.1092038,42.5751065],[-9.0365469,42.730656],[-9.0883419,42.7269569],[-9.1466113,42.7750272],[-9.2185488,42.9016271],[-9.2760988,42.8605106],[-9.3099094,42.9311297],[-9.2789763,42.9821991],[-9.3099094,43.0600377],[-9.2523594,43.1041725],[-9.2314975,43.1703151],[-9.1473307,43.210176],[-9.06748,43.1991644],[-9.0336694,43.2426748],[-8.99842,43.2447709],[-8.9998588,43.2955793],[-8.9372732,43.3055265],[-8.92936,43.326986],[-8.8638969,43.3290792],[-8.8761263,43.3740655],[-8.8221732,43.3735426],[-8.785485,43.3191358],[-8.7063538,43.305003],[-8.6099575,43.3296025],[-8.5509688,43.3233227],[-8.5243519,43.3364048],[-8.5250713,43.3646525],[-8.45745,43.3918416],[-8.3610538,43.4111803],[-8.3603344,43.4634161],[-8.3344369,43.5797394],[-8.2776063,43.5708796],[-8.0646713,43.7239184],[-7.9992081,43.7233986],[-7.9171994,43.7826357],[-7.8560525,43.7914643],[-7.83591,43.7374337],[-7.6628443,43.809819],[-7.3188932,43.6782695],[-7.1997467,43.5830817],[-6.2488228,43.6075032],[-6.1229322,43.5790105],[-5.8520425,43.6798953],[-5.6036334,43.5708672],[-5.2855347,43.5619084],[-5.1787525,43.4991591],[-4.9089869,43.4836655],[-4.6156167,43.4192021],[-4.1839917,43.4249168],[-3.8029478,43.5195394],[-3.7400025,43.4869277],[-3.5612827,43.5423572],[-3.1083013,43.3816347],[-2.9385737,43.4624573],[-2.7452417,43.4755094],[-2.3046245,43.3170625],[-1.9854018,43.3563045],[-1.8552841,43.3972545],[-1.769802,43.3964383],[-1.7700492,43.3760501],[-1.7100474,43.3756908],[-1.7113451,43.3312527],[-1.7225915,43.3131806],[-1.6890375,43.3129108],[-1.6881106,43.3341294],[-1.6446695,43.3337248],[-1.6449785,43.3133155],[-1.6029903,43.3129528],[-1.6034352,43.2926624],[-1.5635905,43.2921227],[-1.5630468,43.3133844],[-1.4779905,43.3128355],[-1.3667723,43.2761368],[-1.3568809,43.2381533],[-1.3703692,43.1712972],[-1.4423067,43.0833554],[-1.4198262,43.0603647],[-1.3730668,43.051166],[-1.3640746,43.1115893],[-1.3020285,43.135217],[-1.2354864,43.1332484],[-1.2795481,43.0774443],[-1.1923239,43.0649635],[-1.0061856,43.0077821],[-0.942341,42.9748951],[-0.7562028,42.9821318],[-0.7148387,42.9610774],[-0.6968543,42.9031405],[-0.5511809,42.8220693],[-0.5044215,42.8484456],[-0.4288871,42.8200906],[-0.3164848,42.8655842],[-0.1456332,42.810856],[-0.0314324,42.7124874],[0.1861785,42.7540985],[0.3021777,42.7177729],[0.3642238,42.7428729],[0.4487504,42.7144695],[0.6276949,42.7223973],[0.6411832,42.8576747],[0.7149192,42.882718],[0.9675996,42.8181119],[1.108777,42.7989808],[1.1753192,42.7342872],[1.3632559,42.7415521],[1.4113736,42.7093914],[1.4806054,42.7103407],[1.4813006,42.5010664],[1.6443591,42.5020345],[1.6432777,42.5424539],[1.730407,42.5434214],[1.7316429,42.5011803],[2.0638621,42.5016359],[2.0645572,42.4590247],[2.3969309,42.4599364],[2.3976786,42.4178363],[2.4804823,42.4179732],[2.4809767,42.3759441],[2.6447922,42.3762636],[2.6444832,42.4592447],[2.8113266,42.4596094],[2.8112648,42.5010358],[3.063878,42.5008535],[3.063878,42.4591535],[3.2307832,42.4593359],[3.2304935,42.3764363],[3.3141469,42.3760369],[3.3141243,42.3339864],[3.397855,42.3340435],[3.3973912,42.290094],[3.3138923,42.2908368],[3.3139695,42.2070151],[3.1475896,42.2073012],[3.1475896,42.1260612],[3.2305478,42.1260039],[3.2466753,41.9529359],[3.1945206,41.8558943],[3.060537,41.7647419],[2.7835777,41.6371796],[2.26293,41.4271601],[2.1649151,41.2989297],[1.86008,41.2232228],[1.3763003,41.116273],[1.1793714,41.0464585],[1.0858526,41.048493],[0.758537,40.8195599],[0.9114042,40.733761],[0.8781331,40.6751363],[0.6650182,40.5358666],[0.5580112,40.5502166],[0.433919,40.3757589],[0.2675635,40.1919192],[0.1641534,40.0647234],[0.0751307,40.0144671],[0.010387,39.8952188],[-0.0939224,39.8116904],[-0.1847435,39.6311716],[-0.2908513,39.5036254],[-0.2863552,39.333431],[-0.1856427,39.1774612],[-0.2135185,39.1558487],[-0.1110076,38.9722246],[0.0094878,38.8826835],[0.1218901,38.872183],[0.2342925,38.798636],[0.2558737,38.7264162],[0.0958128,38.6133825],[-0.0022021,38.6070586],[-0.0570544,38.5269073],[-0.2719677,38.4762395],[-0.379874,38.3931234],[-0.3834708,38.3381297],[-0.4509122,38.3310763],[-0.5048654,38.2830943],[-0.4823849,38.1948095],[-0.429331,38.1658287],[-0.4545091,38.148859],[-0.5839966,38.1721913],[-0.6136708,38.1198599],[-0.6370505,37.9612228],[-0.6811123,37.9456238],[-0.7323677,37.8810656],[-0.7215771,37.7830562],[-0.688306,37.7340026],[-0.6641461,37.6231485],[-0.7193941,37.5878413],[-0.9196258,37.5375806],[-1.1107098,37.5164093],[-1.3383246,37.5286671],[-1.4408917,37.3903714],[-1.6766966,37.2765189],[-1.8540816,36.9122889],[-2.0683486,36.6929117],[-2.2158766,36.6619233],[-2.3721861,36.7801753],[-2.6812926,36.6591056],[-2.9201476,36.6675585],[-3.09402,36.712625],[-3.4610839,36.6548788],[-3.7280395,36.6929117],[-4.3743529,36.6633322],[-4.6571151,36.4404171],[-4.9188018,36.4531321],[-5.1699508,36.3513541],[-5.2841094,36.1970201],[-5.2680911,36.1241812],[-5.3524784,36.1224654],[-5.3516094,36.0401413],[-5.4365759,36.0388921],[-5.4353207,36.0034384],[-5.6888562,36.0036518],[-5.6899635,36.0405317],[-5.85506,36.0385595],[-5.8566821,36.1242077],[-5.9384817,36.1221487],[-5.9400265,36.1655625],[-5.9983445,36.1645024],[-6.0357297,36.1780957],[-6.0775178,36.2224132],[-6.1506113,36.2864561],[-6.231541,36.3770075],[-6.3358504,36.5310643],[-6.3214629,36.5816265],[-6.404191,36.6234958],[-6.4743301,36.7489673],[-6.4158808,36.7993866],[-6.490516,36.9173818],[-6.6298949,37.0194012],[-6.8744824,37.1083766],[-7.0426363,37.1850699],[-7.2647434,37.1843535],[-7.3753473,37.1535419],[-7.408316,37.1682196],[-7.4202886,37.2118318],[-7.4249231,37.2350505],[-7.4380543,37.2451969],[-7.4459717,37.3326142],[-7.4480958,37.3909382],[-7.4696271,37.4075829],[-7.4647029,37.4530494],[-7.5019723,37.516411],[-7.5191587,37.5229203],[-7.5219588,37.5723727],[-7.4501271,37.6695835],[-7.4249019,37.7599222],[-7.316662,37.839974],[-7.268329,37.988952],[-7.1536786,38.0155235],[-7.1177098,38.0553626],[-7.0142997,38.0243785],[-6.9963153,38.1075633],[-6.9614706,38.201254],[-7.080617,38.1570753],[-7.3402665,38.4402363],[-7.2638329,38.7380741],[-7.0435243,38.8729667],[-7.0615086,38.907962],[-6.9693387,39.0198308],[-7.0008114,39.0887867],[-7.1536786,39.0957658],[-7.1525545,39.1602899],[-7.2447245,39.1968854],[-7.2559647,39.2813308],[-7.3368944,39.3535074],[-7.3279022,39.4559917],[-7.5144901,39.5886496],[-7.5527069,39.6795427],[-7.0502684,39.6752171],[-6.9951913,39.8195433],[-6.9221297,39.8790868],[-6.886161,40.0229854],[-7.0412762,40.1347927],[-7.0176717,40.266146],[-6.8086034,40.3450071],[-6.8681766,40.4451649],[-6.8535643,40.6066433],[-6.837828,40.8757589],[-6.9536024,41.0370445],[-6.8018592,41.0395879],[-6.7681385,41.138706],[-6.6411239,41.2655616],[-6.5624422,41.2630269],[-6.217367,41.5791017],[-6.3162811,41.644652],[-6.5152332,41.6412921],[-6.5871707,41.6883151],[-6.5478299,41.8559743],[-6.6298836,41.9112057],[-7.1334461,41.9404756],[-7.1682909,41.8718791],[-7.4256922,41.7847727],[-7.9539833,41.8459271],[-8.130455,41.7805819],[-8.2518495,41.9078597],[-8.1293309,42.0348842],[-8.2484774,42.1008034],[-8.3676239,42.0557521],[-8.6070409,42.0340493],[-8.8910646,41.8228891]]],"terms_text":"PNOA","best":true},{"id":"Slovakia-Historic-Maps","name":"Slovakia Historic Maps","type":"tms","template":"http://tms.freemap.sk/historicke/{zoom}/{x}/{y}.png","scaleExtent":[0,12],"polygon":[[[16.8196949,47.4927236],[16.8196949,49.5030322],[22.8388318,49.5030322],[22.8388318,47.4927236],[16.8196949,47.4927236]]]},{"id":"Soskut_Pusztazamor_Tarnok_Diosd_orto_2017","name":"Sóskút, Pusztazámor, Tárnok, Diósd ortophoto 2017","type":"tms","template":"http://adam.openstreetmap.hu/mapproxy/tiles/1.0.0/Soskut-Tarnok-Pusztazamor-Diosd/mercator/{zoom}/{x}/{y}.png","polygon":[[[18.79273330201,47.37078533804],[18.791936169,47.37048036201],[18.79139114593,47.37063268281],[18.7901097,47.3717614],[18.7891647,47.3734529],[18.78721506824,47.37566027041],[18.7860339,47.37764910001],[18.7849824,47.3790513],[18.783695,47.3803226],[18.782665,47.3819499],[18.781399,47.3836789],[18.7793426,47.3871257],[18.776657,47.3893959],[18.764716,47.396699],[18.7616966,47.3996569],[18.7563102,47.4032821],[18.7583737,47.4065272],[18.75879657883,47.40776342073],[18.76199554897,47.41217224817],[18.7630394973,47.41315137445],[18.7659298,47.4147108],[18.7704058,47.4176575],[18.77247285488,47.41808545272],[18.7724806,47.4202978],[18.8086021,47.4404108],[18.8174212,47.435389],[18.8209188,47.4357228],[18.8280427,47.4375516],[18.8302099,47.4352584],[18.8358533,47.4375371],[18.8404882,47.4334586],[18.847655,47.4357228],[18.8510024,47.4328054],[18.8689996,47.4396086],[18.87361350924,47.43597176329],[18.87499181607,47.43342149293],[18.87386045593,47.43248349864],[18.8760377,47.4279677],[18.8605023,47.4230028],[18.8662101,47.4179794],[18.8724328,47.4108645],[18.8662959,47.4077278],[18.8696433,47.4047072],[18.86776892261,47.40207457802],[18.86509430105,47.40052438512],[18.87081279074,47.3983820654],[18.86772375423,47.39699336542],[18.86992005424,47.39655168559],[18.87648610191,47.39477958954],[18.87748924808,47.39494663392],[18.87866942005,47.39462343887],[18.88358322696,47.3899604942],[18.88290731029,47.3896699544],[18.88538567142,47.38530440107],[18.87747851924,47.38339390377],[18.88181296901,47.37604910406],[18.87914148883,47.37392756692],[18.88638345317,47.36922645965],[18.88205973224,47.36772957402],[18.87973157482,47.36640704749],[18.8746997507,47.36252284243],[18.87282220439,47.36136733615],[18.87027947025,47.36062605465],[18.86687842922,47.3585329683],[18.86234013156,47.35637438604],[18.85566679554,47.35199153827],[18.84873596744,47.34728120653],[18.83192388134,47.3384118486],[18.82497159557,47.34257772442],[18.81619540767,47.34925116493],[18.8107880743,47.35356882392],[18.80823461132,47.35599644336],[18.80645362453,47.35854023611],[18.80707589702,47.359019909],[18.80634633617,47.36021180457],[18.80465118007,47.36175250772],[18.80381433086,47.36335130305],[18.80054616504,47.36544732015],[18.79988097721,47.36617355102],[18.79416204336,47.36974865444],[18.79273330201,47.37078533804]],[[18.91871480064,47.4093812629],[18.91826418952,47.40997664498],[18.9206674488,47.41155945729],[18.92509845809,47.41372304121],[18.93473295288,47.41916790937],[18.94063381271,47.42241278301],[18.94981769638,47.41937843296],[18.95154503898,47.41749820965],[18.95689872818,47.41922598493],[18.95770339088,47.41877589767],[18.95755318717,47.41435467478],[18.9621129425,47.40506817222],[18.96266011314,47.40117592194],[18.96316436843,47.39903360927],[18.95446328239,47.3967314338],[18.95275739746,47.39526437993],[18.95201710777,47.39362297422],[18.95119098739,47.39356487042],[18.94692091064,47.39798783856],[18.94410995559,47.3984526281],[18.94161013679,47.39868502134],[18.93735078887,47.39633199249],[18.93617061691,47.39682584676],[18.93122462348,47.39999947627],[18.93120316581,47.40023186269],[18.92923978881,47.40204734624],[18.92561344223,47.40604845111],[18.92465857582,47.40635342305],[18.92293123321,47.40925782918],[18.91871480064,47.4093812629]]],"terms_url":"http://fototerkep.hu/","terms_text":"Fototerkep.hu","best":true},{"id":"South_Africa-CD_NGI-Aerial","name":"South Africa CD:NGI Aerial","type":"tms","template":"http://{switch:a,b,c}.aerial.openstreetmap.org.za/ngi-aerial/{zoom}/{x}/{y}.jpg","scaleExtent":[1,22],"polygon":[[[17.8396817,-32.7983384],[17.8893509,-32.6972835],[18.00364,-32.6982187],[18.0991679,-32.7485251],[18.2898747,-32.5526645],[18.2930182,-32.0487089],[18.105455,-31.6454966],[17.8529257,-31.3443951],[17.5480046,-30.902171],[17.4044506,-30.6374731],[17.2493704,-30.3991663],[16.9936977,-29.6543552],[16.7987996,-29.19437],[16.5494139,-28.8415949],[16.4498691,-28.691876],[16.4491046,-28.5515766],[16.6002551,-28.4825663],[16.7514057,-28.4486958],[16.7462192,-28.2458973],[16.8855148,-28.04729],[16.9929502,-28.0244005],[17.0529659,-28.0257086],[17.1007562,-28.0338839],[17.2011527,-28.0930546],[17.2026346,-28.2328424],[17.2474611,-28.2338215],[17.2507953,-28.198892],[17.3511919,-28.1975861],[17.3515624,-28.2442655],[17.4015754,-28.2452446],[17.4149122,-28.3489751],[17.4008345,-28.547997],[17.4526999,-28.5489733],[17.4512071,-28.6495106],[17.4983599,-28.6872054],[17.6028204,-28.6830048],[17.6499732,-28.6967928],[17.6525928,-28.7381457],[17.801386,-28.7381457],[17.9994276,-28.7560602],[18.0002748,-28.7956172],[18.1574507,-28.8718055],[18.5063811,-28.8718055],[18.6153564,-28.8295875],[18.9087513,-28.8277516],[19.1046973,-28.9488548],[19.1969071,-28.9378513],[19.243012,-28.8516164],[19.2314858,-28.802963],[19.2587296,-28.7009928],[19.4431493,-28.6973163],[19.5500289,-28.4958332],[19.6967264,-28.4939914],[19.698822,-28.4479358],[19.8507587,-28.4433291],[19.8497109,-28.4027818],[19.9953605,-28.399095],[19.9893671,-24.7497859],[20.2916682,-24.9192346],[20.4724562,-25.1501701],[20.6532441,-25.4529449],[20.733265,-25.6801957],[20.8281046,-25.8963498],[20.8429232,-26.215851],[20.6502804,-26.4840868],[20.6532441,-26.8204869],[21.0889134,-26.846933],[21.6727695,-26.8389998],[21.7765003,-26.6696268],[21.9721069,-26.6431395],[22.2803355,-26.3274702],[22.5707817,-26.1333967],[22.7752795,-25.6775246],[23.0005235,-25.2761948],[23.4658301,-25.2735148],[23.883717,-25.597366],[24.2364017,-25.613402],[24.603905,-25.7896563],[25.110704,-25.7389432],[25.5078447,-25.6855376],[25.6441766,-25.4823781],[25.8419267,-24.7805437],[25.846641,-24.7538456],[26.3928487,-24.6332894],[26.4739066,-24.5653312],[26.5089966,-24.4842437],[26.5861946,-24.4075775],[26.7300635,-24.3014458],[26.8567384,-24.2499463],[26.8574402,-24.1026901],[26.9215471,-23.8990957],[26.931831,-23.8461891],[26.9714827,-23.6994344],[27.0006074,-23.6367644],[27.0578041,-23.6052574],[27.1360547,-23.5203437],[27.3339623,-23.3973792],[27.5144057,-23.3593929],[27.5958145,-23.2085465],[27.8098634,-23.0994957],[27.8828506,-23.0620496],[27.9382928,-22.9496487],[28.0407556,-22.8255118],[28.2056786,-22.6552861],[28.3397223,-22.5639374],[28.4906093,-22.560697],[28.6108769,-22.5400248],[28.828175,-22.4550173],[28.9285324,-22.4232328],[28.9594116,-22.3090081],[29.0162574,-22.208335],[29.2324117,-22.1693453],[29.3531213,-22.1842926],[29.6548952,-22.1186426],[29.7777102,-22.1361956],[29.9292989,-22.1849425],[30.1166795,-22.2830348],[30.2563377,-22.2914767],[30.3033582,-22.3395204],[30.5061784,-22.3057617],[30.8374279,-22.284983],[31.0058599,-22.3077095],[31.1834152,-22.3232913],[31.2930586,-22.3674647],[31.5680579,-23.1903385],[31.5568311,-23.4430809],[31.6931122,-23.6175209],[31.7119696,-23.741136],[31.7774743,-23.8800628],[31.8886337,-23.9481098],[31.9144386,-24.1746736],[31.9948307,-24.3040878],[32.0166656,-24.4405988],[32.0077331,-24.6536578],[32.019643,-24.9140701],[32.035523,-25.0849767],[32.019643,-25.3821442],[31.9928457,-25.4493771],[31.9997931,-25.5165725],[32.0057481,-25.6078978],[32.0057481,-25.6624806],[31.9362735,-25.8403721],[31.9809357,-25.9546537],[31.8687838,-26.0037251],[31.4162062,-25.7277683],[31.3229117,-25.7438611],[31.2504595,-25.8296526],[31.1393001,-25.9162746],[31.1164727,-25.9912361],[30.9656135,-26.2665756],[30.8921689,-26.3279703],[30.8534616,-26.4035568],[30.8226943,-26.4488849],[30.8022583,-26.5240694],[30.8038369,-26.8082089],[30.9020939,-26.7807451],[30.9100338,-26.8489495],[30.9824859,-26.9082627],[30.976531,-27.0029222],[31.0034434,-27.0441587],[31.1543322,-27.1980416],[31.5015607,-27.311117],[31.9700183,-27.311117],[31.9700183,-27.120472],[31.9769658,-27.050664],[32.0002464,-26.7983892],[32.1069826,-26.7984645],[32.3114546,-26.8479493],[32.899986,-26.8516059],[32.886091,-26.9816971],[32.709427,-27.4785436],[32.6240724,-27.7775144],[32.5813951,-28.07479],[32.5387178,-28.2288046],[32.4275584,-28.5021568],[32.3640388,-28.5945699],[32.0702603,-28.8469827],[31.9878832,-28.9069497],[31.7764818,-28.969487],[31.4638459,-29.2859343],[31.359634,-29.3854348],[31.1680825,-29.6307408],[31.064863,-29.7893535],[31.0534493,-29.8470469],[31.0669933,-29.8640319],[31.0455459,-29.9502017],[30.9518556,-30.0033946],[30.8651833,-30.1024093],[30.7244725,-30.392502],[30.3556256,-30.9308873],[30.0972364,-31.2458274],[29.8673136,-31.4304296],[29.7409393,-31.5014699],[29.481312,-31.6978686],[28.8943171,-32.2898903],[28.5497137,-32.5894641],[28.1436499,-32.8320732],[28.0748735,-32.941689],[27.8450942,-33.082869],[27.3757956,-33.3860685],[26.8805407,-33.6458951],[26.5916871,-33.7480756],[26.4527308,-33.7935795],[26.206754,-33.7548943],[26.0077897,-33.7223961],[25.8055494,-33.7524272],[25.7511073,-33.8006512],[25.6529079,-33.8543597],[25.6529079,-33.9469768],[25.7195789,-34.0040115],[25.7202807,-34.0511235],[25.5508915,-34.063151],[25.3504571,-34.0502627],[25.2810609,-34.0020322],[25.0476316,-33.9994588],[24.954724,-34.0043594],[24.9496586,-34.1010363],[24.8770358,-34.1506456],[24.8762914,-34.2005281],[24.8532574,-34.2189562],[24.7645287,-34.2017946],[24.5001356,-34.2003254],[24.3486733,-34.1163824],[24.1988819,-34.1019039],[23.9963377,-34.0514443],[23.8017509,-34.0524332],[23.7493589,-34.0111855],[23.4973536,-34.009014],[23.4155191,-34.0434586],[23.4154284,-34.1140433],[22.9000853,-34.0993009],[22.8412418,-34.0547911],[22.6470321,-34.0502627],[22.6459843,-34.0072768],[22.570016,-34.0064081],[22.5050499,-34.0645866],[22.2519968,-34.0645866],[22.2221334,-34.1014701],[22.1621197,-34.1057019],[22.1712431,-34.1521766],[22.1576913,-34.2180897],[22.0015632,-34.2172232],[21.9496952,-34.3220009],[21.8611528,-34.4007145],[21.5614708,-34.4020114],[21.5468011,-34.3661242],[21.501744,-34.3669892],[21.5006961,-34.4020114],[21.4194886,-34.4465247],[21.1978706,-34.4478208],[21.0988193,-34.3991325],[21.0033746,-34.3753872],[20.893192,-34.3997115],[20.8976647,-34.4854003],[20.7446802,-34.4828092],[20.5042011,-34.486264],[20.2527197,-34.701477],[20.0803502,-34.8361855],[19.9923317,-34.8379056],[19.899074,-34.8275845],[19.8938348,-34.7936018],[19.5972963,-34.7961833],[19.3929677,-34.642015],[19.2877095,-34.6404784],[19.2861377,-34.5986563],[19.3474363,-34.5244458],[19.3285256,-34.4534372],[19.098001,-34.449981],[19.0725583,-34.3802371],[19.0023531,-34.3525593],[18.9520568,-34.3949373],[18.7975006,-34.3936403],[18.7984174,-34.1016376],[18.501748,-34.1015292],[18.4999545,-34.3616945],[18.4477325,-34.3620007],[18.4479944,-34.3522691],[18.3974362,-34.3514041],[18.3971742,-34.3022959],[18.3565705,-34.3005647],[18.3479258,-34.2020436],[18.2972095,-34.1950274],[18.2951139,-33.9937138],[18.3374474,-33.9914079],[18.3476638,-33.8492427],[18.3479258,-33.781555],[18.4124718,-33.7448849],[18.3615477,-33.6501624],[18.2992013,-33.585591],[18.2166839,-33.448872],[18.1389858,-33.3974083],[17.9473472,-33.1602647],[17.8855247,-33.0575732],[17.8485884,-32.9668505],[17.8396817,-32.8507302],[17.8396817,-32.7983384]]],"best":true},{"id":"South-Tyrol-Orthofoto2011","name":"South Tyrol Orthofoto 2011","type":"tms","template":"http://geoservices.buergernetz.bz.it/geoserver/gwc/service/wmts/?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=P_BZ_OF_2011_EPSG3857&STYLE=default&TILEMATRIXSET=GoogleMapsCompatible&TILEMATRIX=GoogleMapsCompatible%3A{zoom}&TILEROW={y}&TILECOL={x}&FORMAT=image%2Fjpeg","scaleExtent":[0,18],"polygon":[[[10.38615,46.68821],[10.39201,46.69016],[10.40215,46.70624],[10.41274,46.70821],[10.41622,46.71479],[10.4168,46.71847],[10.39934,46.73435],[10.43464,46.75356],[10.44107,46.75413],[10.44011,46.77149],[10.42123,46.78861],[10.42845,46.79755],[10.43851,46.79869],[10.44925,46.80462],[10.45602,46.81635],[10.45438,46.82221],[10.4583,46.82478],[10.45513,46.83059],[10.45906,46.83548],[10.46483,46.83624],[10.46229,46.8413],[10.46987,46.84933],[10.46819,46.8553],[10.47838,46.86013],[10.48372,46.85543],[10.49628,46.85305],[10.49931,46.84857],[10.52124,46.84653],[10.5527,46.8511],[10.55795,46.84695],[10.55264,46.8408],[10.55536,46.84087],[10.58883,46.85125],[10.59502,46.85829],[10.60936,46.8597],[10.62441,46.86558],[10.64858,46.86655],[10.66787,46.87651],[10.67297,46.87138],[10.69112,46.86861],[10.69786,46.86339],[10.69508,46.85308],[10.70594,46.84786],[10.71763,46.84795],[10.72333,46.83892],[10.75621,46.83383],[10.76481,46.82409],[10.76387,46.81971],[10.75239,46.81387],[10.74506,46.80223],[10.7276,46.79709],[10.73122,46.78925],[10.75722,46.78624],[10.77744,46.79149],[10.78678,46.79735],[10.81439,46.77662],[10.82479,46.77472],[10.83129,46.78138],[10.84112,46.78282],[10.85354,46.77506],[10.86845,46.77313],[10.86993,46.7669],[10.88294,46.76393],[10.88962,46.76529],[10.8951,46.77092],[10.90527,46.76911],[10.92299,46.7764],[10.92821,46.77408],[10.94388,46.77648],[10.97522,46.77361],[10.97932,46.77014],[10.99475,46.76804],[11.01397,46.77317],[11.02328,46.76715],[11.0346,46.79428],[11.04234,46.801],[11.03792,46.80562],[11.05633,46.80928],[11.07279,46.82092],[11.08171,46.82252],[11.0762,46.83384],[11.06887,46.83793],[11.07303,46.84345],[11.06988,46.85348],[11.08742,46.87927],[11.09961,46.88922],[11.09538,46.89178],[11.09795,46.89844],[11.0946,46.91247],[11.10792,46.91706],[11.10804,46.92632],[11.11418,46.93234],[11.13851,46.92865],[11.16322,46.94091],[11.16642,46.94479],[11.16114,46.94979],[11.1637,46.96677],[11.17598,46.96367],[11.18658,46.97062],[11.19527,46.97152],[11.20418,46.96877],[11.20688,46.96403],[11.22047,46.97025],[11.24139,46.9708],[11.24865,46.97517],[11.25582,46.97535],[11.26272,46.98169],[11.27662,46.98168],[11.28762,46.98699],[11.30709,46.98525],[11.3205,46.99345],[11.33765,46.98606],[11.34516,46.99169],[11.35932,46.99154],[11.37697,46.98025],[11.38324,46.97168],[11.40465,46.96609],[11.43929,46.97601],[11.45134,46.99294],[11.46803,46.99582],[11.46859,47.003],[11.47831,47.01201],[11.50238,47.01073],[11.50313,47.00808],[11.51366,47.00595],[11.51679,47.00091],[11.53381,46.99233],[11.53846,46.98519],[11.55297,46.99149],[11.57663,46.99657],[11.58,47.00277],[11.58879,47.00641],[11.59901,47.00657],[11.60944,47.01207],[11.62697,47.01437],[11.63629,47.00383],[11.66542,46.99304],[11.6885,46.99658],[11.71226,46.99416],[11.72897,46.97322],[11.74698,46.97013],[11.76411,46.97412],[11.78106,46.99342],[11.81526,46.991],[11.83564,46.99417],[11.84396,47.0025],[11.85192,47.0014],[11.86722,47.01252],[11.87393,47.01136],[11.8794,47.01714],[11.89137,47.01728],[11.91627,47.03422],[11.9329,47.03864],[11.94688,47.03464],[11.95457,47.04374],[11.96773,47.04158],[11.97912,47.0511],[11.98587,47.04815],[11.99534,47.05064],[12.02037,47.04821],[12.02968,47.05127],[12.03353,47.0583],[12.04276,47.06228],[12.07543,47.0605],[12.08035,47.06951],[12.09308,47.07791],[12.10329,47.07931],[12.11867,47.07445],[12.13561,47.08171],[12.15125,47.08049],[12.15997,47.08267],[12.18589,47.09322],[12.2278,47.08302],[12.24228,47.06892],[12.23786,47.0644],[12.21821,47.05795],[12.2182,47.04483],[12.20552,47.02595],[12.18048,47.02414],[12.16423,47.01782],[12.14786,47.02357],[12.12723,47.01218],[12.12285,47.00662],[12.1322,46.99339],[12.12974,46.98593],[12.13977,46.982],[12.13808,46.96514],[12.13328,46.96292],[12.13882,46.95764],[12.15927,46.95133],[12.1702,46.93758],[12.15414,46.91654],[12.14675,46.91413],[12.16205,46.908],[12.16959,46.91121],[12.19154,46.90682],[12.20106,46.8965],[12.2022,46.88806],[12.21663,46.87517],[12.22147,46.88084],[12.23125,46.88146],[12.2345,46.88919],[12.24162,46.89192],[12.27486,46.88512],[12.27979,46.87921],[12.27736,46.87319],[12.29326,46.86566],[12.2912,46.85704],[12.29733,46.84455],[12.30833,46.84137],[12.30726,46.83271],[12.285,46.81503],[12.29383,46.8027],[12.28905,46.79948],[12.28889,46.79427],[12.28232,46.79153],[12.28539,46.7839],[12.30943,46.78603],[12.35837,46.77583],[12.37036,46.74163],[12.38475,46.71745],[12.40283,46.70811],[12.41103,46.70701],[12.41522,46.70163],[12.42862,46.6997],[12.42943,46.69567],[12.44268,46.68979],[12.47501,46.68756],[12.4795,46.67969],[12.43473,46.66714],[12.40648,46.64167],[12.38115,46.64183],[12.37944,46.63733],[12.3915,46.62765],[12.38577,46.62154],[12.35939,46.61829],[12.34465,46.62376],[12.34034,46.63022],[12.33578,46.62732],[12.3172,46.62876],[12.31785,46.62355],[12.30802,46.61811],[12.28413,46.61623],[12.26982,46.62003],[12.25931,46.62809],[12.24502,46.62326],[12.24198,46.61586],[12.21241,46.60918],[12.20444,46.59836],[12.19228,46.59321],[12.19261,46.62059],[12.1818,46.6192],[12.17117,46.63275],[12.16062,46.63574],[12.1511,46.63215],[12.1436,46.6327],[12.13739,46.64122],[12.12342,46.64475],[12.10949,46.65204],[12.10609,46.65783],[12.09345,46.66123],[12.08826,46.66638],[12.07985,46.66686],[12.07038,46.67386],[12.07173,46.66064],[12.06686,46.65364],[12.07479,46.64329],[12.06837,46.63997],[12.06495,46.62121],[12.05448,46.61778],[12.05318,46.60989],[12.04613,46.60716],[12.05043,46.60016],[12.04763,46.58357],[12.03665,46.57668],[12.0266,46.55871],[12.02189,46.55791],[11.99941,46.53208],[11.99411,46.53345],[11.98704,46.54417],[11.96633,46.54363],[11.95094,46.53869],[11.94719,46.52879],[11.94147,46.52689],[11.93294,46.52631],[11.9121,46.532],[11.8904,46.52175],[11.85192,46.51682],[11.82849,46.50783],[11.82334,46.51315],[11.82391,46.52141],[11.81086,46.53146],[11.79385,46.52023],[11.79189,46.51322],[11.76157,46.50503],[11.74317,46.50391],[11.73202,46.50877],[11.71935,46.50916],[11.71524,46.51245],[11.69889,46.50218],[11.6672,46.49647],[11.64515,46.49743],[11.63849,46.50051],[11.63495,46.49486],[11.64297,46.49346],[11.65174,46.48271],[11.64536,46.47189],[11.64179,46.47439],[11.62679,46.4708],[11.62987,46.46377],[11.61882,46.44325],[11.62143,46.42539],[11.60161,46.39731],[11.60307,46.38924],[11.5932,46.38265],[11.56489,46.38018],[11.55878,46.35076],[11.55249,46.34418],[11.54423,46.34483],[11.53837,46.35015],[11.52445,46.35502],[11.47969,46.36277],[11.48052,46.3551],[11.46322,46.34922],[11.45556,46.33396],[11.42105,46.32441],[11.40517,46.32387],[11.39865,46.31426],[11.39994,46.30709],[11.39569,46.3083],[11.38188,46.30052],[11.36088,46.29906],[11.36078,46.29682],[11.38256,46.29177],[11.3871,46.28143],[11.39609,46.27423],[11.39862,46.264],[11.38756,46.26029],[11.37347,46.2629],[11.36836,46.26135],[11.35783,46.26481],[11.35495,46.27564],[11.33912,46.28306],[11.33379,46.29049],[11.33471,46.2962],[11.3129,46.28256],[11.31737,46.27303],[11.30645,46.25786],[11.29124,46.2604],[11.24743,46.22933],[11.20622,46.2187],[11.18267,46.22496],[11.17077,46.23806],[11.17994,46.24434],[11.18351,46.25269],[11.18935,46.25354],[11.19448,46.2461],[11.20029,46.25566],[11.16604,46.26129],[11.14885,46.27904],[11.13725,46.28336],[11.14293,46.28934],[11.15847,46.29059],[11.16439,46.2986],[11.1761,46.30346],[11.1847,46.32104],[11.18894,46.32151],[11.18696,46.32673],[11.1942,46.33016],[11.20204,46.34212],[11.19001,46.35984],[11.19263,46.36578],[11.20393,46.36765],[11.19792,46.37232],[11.21275,46.39804],[11.21345,46.40675],[11.20565,46.4166],[11.21026,46.4206],[11.20347,46.42682],[11.21416,46.43556],[11.21634,46.44255],[11.20903,46.45293],[11.21419,46.45807],[11.21736,46.45731],[11.21886,46.46199],[11.21626,46.47277],[11.20939,46.481],[11.20876,46.49346],[11.19608,46.50241],[11.1924,46.501],[11.18686,46.50734],[11.18002,46.49823],[11.17014,46.49635],[11.16095,46.4878],[11.12934,46.48058],[11.1103,46.49643],[11.10449,46.4948],[11.08812,46.50128],[11.08173,46.53021],[11.05915,46.51508],[11.03795,46.51357],[11.05006,46.50784],[11.05773,46.49235],[11.06278,46.4894],[11.06894,46.46619],[11.07625,46.45487],[11.0778,46.44569],[11.07301,46.44042],[11.05394,46.44849],[11.0414,46.44569],[11.02817,46.46116],[11.00952,46.46917],[11.00462,46.47607],[10.98695,46.48289],[10.96543,46.48103],[10.95791,46.46983],[10.93819,46.46578],[10.9325,46.45831],[10.93332,46.4528],[10.91305,46.44284],[10.89161,46.44366],[10.88324,46.44995],[10.88093,46.44579],[10.87162,46.4438],[10.86174,46.43509],[10.85113,46.43817],[10.80034,46.44185],[10.78906,46.45164],[10.77835,46.47112],[10.76934,46.47609],[10.76463,46.4848],[10.75906,46.48547],[10.74422,46.48333],[10.71753,46.46022],[10.69667,46.4573],[10.68293,46.44846],[10.66821,46.45122],[10.63303,46.44309],[10.61439,46.45098],[10.60128,46.46139],[10.59995,46.46766],[10.57672,46.47237],[10.55875,46.48187],[10.54986,46.49123],[10.53685,46.49062],[10.52657,46.49425],[10.49366,46.49719],[10.48141,46.49337],[10.45714,46.5096],[10.45124,46.53083],[10.45814,46.54215],[10.47056,46.54377],[10.46954,46.54856],[10.47617,46.55749],[10.47321,46.56701],[10.48305,46.5777],[10.48575,46.58921],[10.48221,46.59199],[10.48576,46.59805],[10.48291,46.60512],[10.49055,46.61394],[10.44632,46.63989],[10.40935,46.63389],[10.40011,46.63648],[10.39873,46.6455],[10.38946,46.65862],[10.39057,46.67089],[10.3803,46.68399],[10.38615,46.68821]]],"terms_url":"http://geoservices.buergernetz.bz.it/geokatalog/","terms_text":"© Autonomen Provinz Bozen/Provincia Autonoma di Bolzano CC-BY 3.0"},{"id":"South-Tyrol-Orthofoto2014","name":"South Tyrol Orthofoto 2014","type":"tms","template":"http://geoservices.buergernetz.bz.it/geoserver/gwc/service/wmts/?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=P_BZ_OF_2014_EPSG3857&STYLE=default&TILEMATRIXSET=GoogleMapsCompatible&TILEMATRIX=GoogleMapsCompatible%3A{zoom}&TILEROW={y}&TILECOL={x}&FORMAT=image%2Fjpeg","scaleExtent":[0,18],"polygon":[[[12.23442,46.84254],[12.24913,46.82785],[12.24913,46.81945],[12.25753,46.81735],[12.26173,46.80686],[12.26594,46.80686],[12.26804,46.79637],[12.26173,46.79427],[12.27014,46.78587],[12.27224,46.76908],[12.28485,46.76698],[12.29745,46.7439],[12.30166,46.7439],[12.30166,46.7376],[12.28695,46.7376],[12.23652,46.72081],[12.18819,46.71451],[12.16298,46.70192],[12.10835,46.69353],[12.08944,46.68303],[12.05792,46.68093],[12.04531,46.67464],[12.03481,46.67464],[12.03061,46.68303],[12.0096,46.68303],[11.98438,46.66834],[11.94866,46.66414],[11.93816,46.65575],[11.90874,46.64525],[11.89193,46.64525],[11.8457,46.62846],[11.82049,46.62636],[11.80998,46.60748],[11.79528,46.60328],[11.78897,46.59069],[11.78057,46.58859],[11.76586,46.55501],[11.75325,46.54871],[11.73855,46.52982],[11.73224,46.52982],[11.72384,46.51513],[11.71543,46.51513],[11.71333,46.50254],[11.70913,46.50254],[11.70913,46.49624],[11.69652,46.48575],[11.69442,46.47735],[11.66711,46.47525],[11.66711,46.44587],[11.6608,46.44587],[11.64399,46.45846],[11.63769,46.45846],[11.63349,46.44587],[11.62508,46.44797],[11.62508,46.43957],[11.61878,46.43957],[11.61458,46.42278],[11.61037,46.42278],[11.61037,46.41649],[11.62508,46.41229],[11.62508,46.3934],[11.61458,46.38291],[11.60617,46.38291],[11.60407,46.37241],[11.58306,46.37241],[11.58306,46.34932],[11.55995,46.32414],[11.53894,46.32834],[11.53894,46.34513],[11.52423,46.34723],[11.50111,46.34723],[11.49901,46.32834],[11.48851,46.33044],[11.49271,46.32204],[11.41917,46.32414],[11.41707,46.25278],[11.35613,46.24858],[11.34773,46.25698],[11.34563,46.26747],[11.34143,46.26747],[11.33722,46.25068],[11.31201,46.24858],[11.30991,46.25278],[11.3015,46.25278],[11.2889,46.24019],[11.2889,46.2234],[11.25108,46.2234],[11.24898,46.2129],[11.16283,46.215],[11.16283,46.24858],[11.12711,46.24858],[11.13131,46.25278],[11.12291,46.25488],[11.12501,46.29895],[11.16283,46.29895],[11.16283,46.36821],[11.16703,46.36821],[11.16703,46.38081],[11.17543,46.3871],[11.17754,46.3997],[11.20485,46.3997],[11.20695,46.42068],[11.19014,46.42068],[11.19014,46.42698],[11.19435,46.42698],[11.19855,46.44167],[11.20485,46.44587],[11.20695,46.47315],[11.19014,46.47525],[11.18804,46.48365],[11.15232,46.47525],[11.08298,46.47525],[11.08088,46.43537],[11.04096,46.42068],[11.01154,46.42068],[10.99894,46.44587],[10.98843,46.44587],[10.98423,46.45217],[10.96952,46.45217],[10.96112,46.48365],[10.95691,46.48365],[10.95481,46.49414],[10.94851,46.49624],[10.94431,46.50673],[10.91069,46.49624],[10.90018,46.49624],[10.89808,46.51093],[10.85606,46.50254],[10.84135,46.54241],[10.86446,46.54661],[10.86236,46.55081],[10.76571,46.54031],[10.72158,46.55081],[10.59762,46.55291],[10.5619,46.54871],[10.53668,46.55291],[10.50096,46.54871],[10.48415,46.55501],[10.46314,46.55501],[10.47155,46.5676],[10.47365,46.59069],[10.47785,46.59069],[10.47785,46.61797],[10.46944,46.62636],[10.44843,46.63476],[10.42532,46.62846],[10.3938,46.63056],[10.3896,46.64525],[10.3812,46.64735],[10.3833,46.66414],[10.3791,46.66834],[10.3791,46.69353],[10.3854,46.72081],[10.3896,46.72081],[10.3938,46.7376],[10.41692,46.75229],[10.41692,46.78587],[10.42112,46.79847],[10.42532,46.79847],[10.42532,46.80686],[10.43373,46.81106],[10.43793,46.79007],[10.44423,46.78377],[10.44843,46.7439],[10.45264,46.7439],[10.45684,46.72711],[10.46104,46.72711],[10.46524,46.71032],[10.46944,46.71032],[10.47365,46.67254],[10.47995,46.67044],[10.48415,46.65575],[10.48836,46.65575],[10.48415,46.62846],[10.48836,46.62846],[10.48836,46.62217],[10.49886,46.62007],[10.52828,46.62427],[10.49886,46.63056],[10.49886,46.64525],[10.50516,46.64316],[10.49886,46.66204],[10.51777,46.65785],[10.58921,46.66204],[10.63123,46.65365],[10.79302,46.65575],[10.79723,46.65155],[10.88127,46.65155],[10.89178,46.65785],[10.9275,46.66414],[10.94431,46.67464],[10.98003,46.67464],[11.00104,46.68303],[11.02415,46.68303],[11.05147,46.69772],[11.12711,46.70822],[11.13971,46.71242],[11.14392,46.71871],[11.17543,46.72081],[11.19855,46.7334],[11.24898,46.7355],[11.25318,46.72291],[11.2952,46.72921],[11.30571,46.70822],[11.31831,46.70822],[11.33722,46.71871],[11.38555,46.72081],[11.43178,46.7376],[11.50952,46.7439],[11.54734,46.75649],[11.56835,46.75649],[11.58306,46.76698],[11.60617,46.76908],[11.61037,46.77538],[11.69862,46.79427],[11.71753,46.79427],[11.72174,46.79007],[11.73855,46.75859],[11.74905,46.75019],[11.76166,46.70192],[11.76586,46.70192],[11.78687,46.71661],[11.8331,46.72291],[11.86041,46.7376],[11.90874,46.7439],[11.92135,46.75229],[11.95286,46.75859],[11.95917,46.76488],[11.99489,46.77538],[12.00749,46.77538],[12.0096,46.77958],[12.03061,46.78168],[12.05792,46.79427],[12.09995,46.79847],[12.13566,46.81316],[12.15878,46.81316],[12.18609,46.82785],[12.21551,46.83205],[12.23442,46.84254]],[[11.97388,46.96637],[11.99489,46.96007],[11.99489,46.95587],[12.0096,46.95797],[12.0117,46.94748],[12.0159,46.94748],[12.0117,46.94118],[12.018,46.93908],[12.02851,46.92229],[12.00749,46.9118],[11.97388,46.9055],[11.95707,46.89501],[11.91714,46.88871],[11.85831,46.86982],[11.8394,46.86982],[11.80158,46.85303],[11.76166,46.84464],[11.74905,46.83415],[11.68181,46.81945],[11.67971,46.81526],[11.6545,46.81106],[11.64399,46.80476],[11.63769,46.80686],[11.63139,46.82155],[11.62508,46.82155],[11.62298,46.83205],[11.61037,46.84464],[11.61668,46.84884],[11.61458,46.85723],[11.61037,46.85723],[11.61668,46.86563],[11.64609,46.86563],[11.68602,46.88242],[11.69022,46.88871],[11.74905,46.89711],[11.75325,46.90341],[11.78057,46.9076],[11.80158,46.9202],[11.8457,46.92649],[11.87722,46.94118],[11.89613,46.94328],[11.92135,46.95797],[11.96757,46.96217],[11.97388,46.96637]]],"terms_url":"http://geoservices.buergernetz.bz.it/geokatalog/","terms_text":"© Autonomen Provinz Bozen/Provincia Autonoma di Bolzano CC-BY 3.0","best":true},{"id":"South-Tyrol-Topomap","name":"South Tyrol Topomap","type":"tms","template":"http://geoservices.buergernetz.bz.it/geoserver/gwc/service/wmts/?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=P_BZ_BASEMAP_TOPO&STYLE=default&TILEMATRIXSET=GoogleMapsCompatible&TILEMATRIX=GoogleMapsCompatible%3A{zoom}&TILEROW={y}&TILECOL={x}&FORMAT=image%2Fjpeg","description":"Topographical basemap of South Tyrol","scaleExtent":[0,20],"polygon":[[[10.38615,46.68821],[10.39201,46.69016],[10.40215,46.70624],[10.41274,46.70821],[10.41622,46.71479],[10.4168,46.71847],[10.39934,46.73435],[10.43464,46.75356],[10.44107,46.75413],[10.44011,46.77149],[10.42123,46.78861],[10.42845,46.79755],[10.43851,46.79869],[10.44925,46.80462],[10.45602,46.81635],[10.45438,46.82221],[10.4583,46.82478],[10.45513,46.83059],[10.45906,46.83548],[10.46483,46.83624],[10.46229,46.8413],[10.46987,46.84933],[10.46819,46.8553],[10.47838,46.86013],[10.48372,46.85543],[10.49628,46.85305],[10.49931,46.84857],[10.52124,46.84653],[10.5527,46.8511],[10.55795,46.84695],[10.55264,46.8408],[10.55536,46.84087],[10.58883,46.85125],[10.59502,46.85829],[10.60936,46.8597],[10.62441,46.86558],[10.64858,46.86655],[10.66787,46.87651],[10.67297,46.87138],[10.69112,46.86861],[10.69786,46.86339],[10.69508,46.85308],[10.70594,46.84786],[10.71763,46.84795],[10.72333,46.83892],[10.75621,46.83383],[10.76481,46.82409],[10.76387,46.81971],[10.75239,46.81387],[10.74506,46.80223],[10.7276,46.79709],[10.73122,46.78925],[10.75722,46.78624],[10.77744,46.79149],[10.78678,46.79735],[10.81439,46.77662],[10.82479,46.77472],[10.83129,46.78138],[10.84112,46.78282],[10.85354,46.77506],[10.86845,46.77313],[10.86993,46.7669],[10.88294,46.76393],[10.88962,46.76529],[10.8951,46.77092],[10.90527,46.76911],[10.92299,46.7764],[10.92821,46.77408],[10.94388,46.77648],[10.97522,46.77361],[10.97932,46.77014],[10.99475,46.76804],[11.01397,46.77317],[11.02328,46.76715],[11.0346,46.79428],[11.04234,46.801],[11.03792,46.80562],[11.05633,46.80928],[11.07279,46.82092],[11.08171,46.82252],[11.0762,46.83384],[11.06887,46.83793],[11.07303,46.84345],[11.06988,46.85348],[11.08742,46.87927],[11.09961,46.88922],[11.09538,46.89178],[11.09795,46.89844],[11.0946,46.91247],[11.10792,46.91706],[11.10804,46.92632],[11.11418,46.93234],[11.13851,46.92865],[11.16322,46.94091],[11.16642,46.94479],[11.16114,46.94979],[11.1637,46.96677],[11.17598,46.96367],[11.18658,46.97062],[11.19527,46.97152],[11.20418,46.96877],[11.20688,46.96403],[11.22047,46.97025],[11.24139,46.9708],[11.24865,46.97517],[11.25582,46.97535],[11.26272,46.98169],[11.27662,46.98168],[11.28762,46.98699],[11.30709,46.98525],[11.3205,46.99345],[11.33765,46.98606],[11.34516,46.99169],[11.35932,46.99154],[11.37697,46.98025],[11.38324,46.97168],[11.40465,46.96609],[11.43929,46.97601],[11.45134,46.99294],[11.46803,46.99582],[11.46859,47.003],[11.47831,47.01201],[11.50238,47.01073],[11.50313,47.00808],[11.51366,47.00595],[11.51679,47.00091],[11.53381,46.99233],[11.53846,46.98519],[11.55297,46.99149],[11.57663,46.99657],[11.58,47.00277],[11.58879,47.00641],[11.59901,47.00657],[11.60944,47.01207],[11.62697,47.01437],[11.63629,47.00383],[11.66542,46.99304],[11.6885,46.99658],[11.71226,46.99416],[11.72897,46.97322],[11.74698,46.97013],[11.76411,46.97412],[11.78106,46.99342],[11.81526,46.991],[11.83564,46.99417],[11.84396,47.0025],[11.85192,47.0014],[11.86722,47.01252],[11.87393,47.01136],[11.8794,47.01714],[11.89137,47.01728],[11.91627,47.03422],[11.9329,47.03864],[11.94688,47.03464],[11.95457,47.04374],[11.96773,47.04158],[11.97912,47.0511],[11.98587,47.04815],[11.99534,47.05064],[12.02037,47.04821],[12.02968,47.05127],[12.03353,47.0583],[12.04276,47.06228],[12.07543,47.0605],[12.08035,47.06951],[12.09308,47.07791],[12.10329,47.07931],[12.11867,47.07445],[12.13561,47.08171],[12.15125,47.08049],[12.15997,47.08267],[12.18589,47.09322],[12.2278,47.08302],[12.24228,47.06892],[12.23786,47.0644],[12.21821,47.05795],[12.2182,47.04483],[12.20552,47.02595],[12.18048,47.02414],[12.16423,47.01782],[12.14786,47.02357],[12.12723,47.01218],[12.12285,47.00662],[12.1322,46.99339],[12.12974,46.98593],[12.13977,46.982],[12.13808,46.96514],[12.13328,46.96292],[12.13882,46.95764],[12.15927,46.95133],[12.1702,46.93758],[12.15414,46.91654],[12.14675,46.91413],[12.16205,46.908],[12.16959,46.91121],[12.19154,46.90682],[12.20106,46.8965],[12.2022,46.88806],[12.21663,46.87517],[12.22147,46.88084],[12.23125,46.88146],[12.2345,46.88919],[12.24162,46.89192],[12.27486,46.88512],[12.27979,46.87921],[12.27736,46.87319],[12.29326,46.86566],[12.2912,46.85704],[12.29733,46.84455],[12.30833,46.84137],[12.30726,46.83271],[12.285,46.81503],[12.29383,46.8027],[12.28905,46.79948],[12.28889,46.79427],[12.28232,46.79153],[12.28539,46.7839],[12.30943,46.78603],[12.35837,46.77583],[12.37036,46.74163],[12.38475,46.71745],[12.40283,46.70811],[12.41103,46.70701],[12.41522,46.70163],[12.42862,46.6997],[12.42943,46.69567],[12.44268,46.68979],[12.47501,46.68756],[12.4795,46.67969],[12.43473,46.66714],[12.40648,46.64167],[12.38115,46.64183],[12.37944,46.63733],[12.3915,46.62765],[12.38577,46.62154],[12.35939,46.61829],[12.34465,46.62376],[12.34034,46.63022],[12.33578,46.62732],[12.3172,46.62876],[12.31785,46.62355],[12.30802,46.61811],[12.28413,46.61623],[12.26982,46.62003],[12.25931,46.62809],[12.24502,46.62326],[12.24198,46.61586],[12.21241,46.60918],[12.20444,46.59836],[12.19228,46.59321],[12.19261,46.62059],[12.1818,46.6192],[12.17117,46.63275],[12.16062,46.63574],[12.1511,46.63215],[12.1436,46.6327],[12.13739,46.64122],[12.12342,46.64475],[12.10949,46.65204],[12.10609,46.65783],[12.09345,46.66123],[12.08826,46.66638],[12.07985,46.66686],[12.07038,46.67386],[12.07173,46.66064],[12.06686,46.65364],[12.07479,46.64329],[12.06837,46.63997],[12.06495,46.62121],[12.05448,46.61778],[12.05318,46.60989],[12.04613,46.60716],[12.05043,46.60016],[12.04763,46.58357],[12.03665,46.57668],[12.0266,46.55871],[12.02189,46.55791],[11.99941,46.53208],[11.99411,46.53345],[11.98704,46.54417],[11.96633,46.54363],[11.95094,46.53869],[11.94719,46.52879],[11.94147,46.52689],[11.93294,46.52631],[11.9121,46.532],[11.8904,46.52175],[11.85192,46.51682],[11.82849,46.50783],[11.82334,46.51315],[11.82391,46.52141],[11.81086,46.53146],[11.79385,46.52023],[11.79189,46.51322],[11.76157,46.50503],[11.74317,46.50391],[11.73202,46.50877],[11.71935,46.50916],[11.71524,46.51245],[11.69889,46.50218],[11.6672,46.49647],[11.64515,46.49743],[11.63849,46.50051],[11.63495,46.49486],[11.64297,46.49346],[11.65174,46.48271],[11.64536,46.47189],[11.64179,46.47439],[11.62679,46.4708],[11.62987,46.46377],[11.61882,46.44325],[11.62143,46.42539],[11.60161,46.39731],[11.60307,46.38924],[11.5932,46.38265],[11.56489,46.38018],[11.55878,46.35076],[11.55249,46.34418],[11.54423,46.34483],[11.53837,46.35015],[11.52445,46.35502],[11.47969,46.36277],[11.48052,46.3551],[11.46322,46.34922],[11.45556,46.33396],[11.42105,46.32441],[11.40517,46.32387],[11.39865,46.31426],[11.39994,46.30709],[11.39569,46.3083],[11.38188,46.30052],[11.36088,46.29906],[11.36078,46.29682],[11.38256,46.29177],[11.3871,46.28143],[11.39609,46.27423],[11.39862,46.264],[11.38756,46.26029],[11.37347,46.2629],[11.36836,46.26135],[11.35783,46.26481],[11.35495,46.27564],[11.33912,46.28306],[11.33379,46.29049],[11.33471,46.2962],[11.3129,46.28256],[11.31737,46.27303],[11.30645,46.25786],[11.29124,46.2604],[11.24743,46.22933],[11.20622,46.2187],[11.18267,46.22496],[11.17077,46.23806],[11.17994,46.24434],[11.18351,46.25269],[11.18935,46.25354],[11.19448,46.2461],[11.20029,46.25566],[11.16604,46.26129],[11.14885,46.27904],[11.13725,46.28336],[11.14293,46.28934],[11.15847,46.29059],[11.16439,46.2986],[11.1761,46.30346],[11.1847,46.32104],[11.18894,46.32151],[11.18696,46.32673],[11.1942,46.33016],[11.20204,46.34212],[11.19001,46.35984],[11.19263,46.36578],[11.20393,46.36765],[11.19792,46.37232],[11.21275,46.39804],[11.21345,46.40675],[11.20565,46.4166],[11.21026,46.4206],[11.20347,46.42682],[11.21416,46.43556],[11.21634,46.44255],[11.20903,46.45293],[11.21419,46.45807],[11.21736,46.45731],[11.21886,46.46199],[11.21626,46.47277],[11.20939,46.481],[11.20876,46.49346],[11.19608,46.50241],[11.1924,46.501],[11.18686,46.50734],[11.18002,46.49823],[11.17014,46.49635],[11.16095,46.4878],[11.12934,46.48058],[11.1103,46.49643],[11.10449,46.4948],[11.08812,46.50128],[11.08173,46.53021],[11.05915,46.51508],[11.03795,46.51357],[11.05006,46.50784],[11.05773,46.49235],[11.06278,46.4894],[11.06894,46.46619],[11.07625,46.45487],[11.0778,46.44569],[11.07301,46.44042],[11.05394,46.44849],[11.0414,46.44569],[11.02817,46.46116],[11.00952,46.46917],[11.00462,46.47607],[10.98695,46.48289],[10.96543,46.48103],[10.95791,46.46983],[10.93819,46.46578],[10.9325,46.45831],[10.93332,46.4528],[10.91305,46.44284],[10.89161,46.44366],[10.88324,46.44995],[10.88093,46.44579],[10.87162,46.4438],[10.86174,46.43509],[10.85113,46.43817],[10.80034,46.44185],[10.78906,46.45164],[10.77835,46.47112],[10.76934,46.47609],[10.76463,46.4848],[10.75906,46.48547],[10.74422,46.48333],[10.71753,46.46022],[10.69667,46.4573],[10.68293,46.44846],[10.66821,46.45122],[10.63303,46.44309],[10.61439,46.45098],[10.60128,46.46139],[10.59995,46.46766],[10.57672,46.47237],[10.55875,46.48187],[10.54986,46.49123],[10.53685,46.49062],[10.52657,46.49425],[10.49366,46.49719],[10.48141,46.49337],[10.45714,46.5096],[10.45124,46.53083],[10.45814,46.54215],[10.47056,46.54377],[10.46954,46.54856],[10.47617,46.55749],[10.47321,46.56701],[10.48305,46.5777],[10.48575,46.58921],[10.48221,46.59199],[10.48576,46.59805],[10.48291,46.60512],[10.49055,46.61394],[10.44632,46.63989],[10.40935,46.63389],[10.40011,46.63648],[10.39873,46.6455],[10.38946,46.65862],[10.39057,46.67089],[10.3803,46.68399],[10.38615,46.68821]]],"terms_url":"http://geoservices.buergernetz.bz.it/geokatalog/","terms_text":"© Autonomen Provinz Bozen/Provincia Autonoma di Bolzano"},{"id":"Bern-bern2016-tms","name":"Stadt Bern 10cm (2016)","type":"tms","template":"http://mapproxy.osm.ch:8080/tiles/bern2016/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[8,21],"polygon":[[[7.2943145,46.9237564],[7.2982665,46.9274715],[7.3061586,46.9309487],[7.3043338,46.9362344],[7.3068603,46.9403709],[7.3246431,46.9432765],[7.3284525,46.946409],[7.3414051,46.9460797],[7.3438454,46.9473713],[7.3434554,46.9487937],[7.3513567,46.9485481],[7.3505628,46.950213],[7.3530901,46.9519266],[7.3582028,46.9511773],[7.3685031,46.9566244],[7.3715097,46.9607339],[7.37503,46.959835],[7.3785111,46.9614686],[7.3806232,46.9654741],[7.3832097,46.9663014],[7.3937998,46.9669268],[7.4000528,46.9691779],[7.4082922,46.9686857],[7.4281713,46.9738041],[7.4327053,46.972689],[7.4353602,46.9684345],[7.4378522,46.9684302],[7.4412474,46.9767865],[7.4456893,46.9747939],[7.4483835,46.9756393],[7.4477006,46.9790125],[7.4440468,46.9780682],[7.4412738,46.9798224],[7.4506732,46.9901527],[7.4522112,46.9896803],[7.454649,46.9778182],[7.4680382,46.9758258],[7.4707923,46.969998],[7.4701907,46.9674116],[7.4781618,46.9711823],[7.4845237,46.9701571],[7.4861275,46.9679018],[7.4857945,46.9646828],[7.4784708,46.9629043],[7.4802865,46.9606768],[7.4789304,46.9587841],[7.4797786,46.9566019],[7.4770135,46.9544586],[7.4840504,46.9499938],[7.4833925,46.9451977],[7.4955563,46.9396169],[7.4935119,46.9376594],[7.4908036,46.9387617],[7.4894997,46.9368667],[7.4766667,46.9369496],[7.4781093,46.9362489],[7.4746986,46.9339187],[7.4753537,46.9329898],[7.4691047,46.9292427],[7.4707683,46.9255044],[7.4585674,46.934836],[7.4476373,46.9304297],[7.435418,46.9349668],[7.4338022,46.9331237],[7.4376403,46.9307415],[7.4146941,46.9368183],[7.413844,46.9315682],[7.4070798,46.9303824],[7.408065,46.9256296],[7.4021268,46.9241992],[7.4014835,46.9211927],[7.3875736,46.9304506],[7.3823129,46.927282],[7.3800187,46.9298929],[7.3808694,46.9324085],[7.3748669,46.9314306],[7.3748901,46.9327104],[7.368066,46.9323929],[7.3683058,46.930426],[7.3604074,46.9285884],[7.3605592,46.9272018],[7.338783,46.9245357],[7.3393683,46.9196675],[7.3274574,46.9190326],[7.3269178,46.9235974],[7.324374,46.9251891],[7.3082264,46.9222857],[7.2943145,46.9237564]]],"terms_text":"Orthophoto 2016, Vermessungsamt Stadt Bern ","best":true},{"id":"Uster-2008","name":"Stadt Uster Orthophoto 2008 10cm","type":"tms","template":"http://mapproxy.sosm.ch:8080/tiles/uster/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","polygon":[[[8.6,47.31],[8.6,47.39],[8.77,47.39],[8.77,47.31],[8.6,47.31]]],"terms_text":"Stadt Uster Vermessung Orthophoto 2008"},{"id":"Zuerich-zh_luftbild2011-tms","name":"Stadt Zürich Luftbild 2011","type":"tms","template":"http://mapproxy.sosm.ch:8080/tiles/zh_luftbild2011/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","polygon":[[[8.4441,47.3141],[8.4441,47.4411],[8.6284,47.4411],[8.6284,47.3141],[8.4441,47.3141]]],"terms_text":"Stadt Zürich Luftbild 2011"},{"id":"Zuerich-city_map","name":"Stadtplan Zürich","type":"tms","template":"http://mapproxy.sosm.ch:8080/tiles/zh_stadtplan/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","polygon":[[[8.4482,47.321],[8.4482,47.4339],[8.6248,47.4339],[8.6248,47.321],[8.4482,47.321]]],"terms_text":"Stadt Zürich Open Government Data"},{"id":"stamen-terrain-background","name":"Stamen Terrain","type":"tms","template":"http://{switch:a,b,c,d}.tile.stamen.com/terrain-background/{zoom}/{x}/{y}.jpg","scaleExtent":[4,18],"terms_url":"http://maps.stamen.com/#terrain","terms_text":"Map tiles by Stamen Design, under CC BY 3.0"},{"id":"Stevns_Denmark","name":"Stevns (Denmark)","type":"tms","template":"http://{switch:a,b,c}.tile.openstreetmap.dk/stevns/2009/{zoom}/{x}/{y}.png","scaleExtent":[0,20],"polygon":[[[12.0913942,55.3491574],[12.0943104,55.3842256],[12.1573875,55.3833103],[12.1587287,55.4013326],[12.1903468,55.400558],[12.1931411,55.4364665],[12.2564251,55.4347995],[12.2547073,55.4168882],[12.3822489,55.4134349],[12.3795942,55.3954143],[12.4109213,55.3946958],[12.409403,55.3766417],[12.4407807,55.375779],[12.4394142,55.3578314],[12.4707413,55.3569971],[12.4629475,55.2672214],[12.4315633,55.2681491],[12.430045,55.2502103],[12.3672011,55.2519673],[12.3656858,55.2340267],[12.2714604,55.2366031],[12.2744467,55.272476],[12.2115654,55.2741475],[12.2130078,55.2920322],[12.1815665,55.2928638],[12.183141,55.3107091],[12.2144897,55.3100981],[12.2159927,55.3279764],[12.1214458,55.3303379],[12.1229489,55.3483291],[12.0913942,55.3491574]]],"terms_text":"Stevns Kommune"},{"id":"Surrey-Air_Survey","name":"Surrey Air Survey","type":"tms","template":"http://gravitystorm.dev.openstreetmap.org/surrey/{zoom}/{x}/{y}.png","scaleExtent":[8,19],"polygon":[[[-0.752478,51.0821941],[-0.7595183,51.0856254],[-0.8014342,51.1457917],[-0.8398864,51.1440686],[-0.8357665,51.1802397],[-0.8529549,51.2011266],[-0.8522683,51.2096231],[-0.8495217,51.217903],[-0.8266907,51.2403696],[-0.8120995,51.2469248],[-0.7736474,51.2459577],[-0.7544213,51.2381127],[-0.754078,51.233921],[-0.7446366,51.2333836],[-0.7430693,51.2847178],[-0.751503,51.3069524],[-0.7664376,51.3121032],[-0.7820588,51.3270157],[-0.7815438,51.3388135],[-0.7374268,51.3720456],[-0.7192307,51.3769748],[-0.6795769,51.3847961],[-0.6807786,51.3901523],[-0.6531411,51.3917591],[-0.6301385,51.3905808],[-0.6291085,51.3970074],[-0.6234437,51.3977572],[-0.613144,51.4295552],[-0.6002471,51.4459121],[-0.5867081,51.4445365],[-0.5762368,51.453202],[-0.5626755,51.4523462],[-0.547741,51.4469972],[-0.5372697,51.4448575],[-0.537098,51.4526671],[-0.5439644,51.4545926],[-0.5405312,51.4698865],[-0.5309182,51.4760881],[-0.5091172,51.4744843],[-0.5086022,51.4695657],[-0.4900628,51.4682825],[-0.4526406,51.4606894],[-0.4486924,51.4429316],[-0.4414826,51.4418616],[-0.4418259,51.4369394],[-0.4112702,51.4380095],[-0.4014855,51.4279498],[-0.3807145,51.4262372],[-0.3805428,51.4161749],[-0.3491288,51.4138195],[-0.3274994,51.4037544],[-0.3039818,51.3990424],[-0.3019219,51.3754747],[-0.309475,51.369688],[-0.3111916,51.3529669],[-0.2955704,51.3541462],[-0.2923089,51.3673303],[-0.2850991,51.3680805],[-0.2787476,51.3771891],[-0.2655297,51.3837247],[-0.2411538,51.3847961],[-0.2123147,51.3628288],[-0.2107697,51.3498578],[-0.190857,51.3502867],[-0.1542931,51.3338802],[-0.1496583,51.3057719],[-0.1074296,51.2966491],[-0.0887185,51.3099571],[-0.0878602,51.3220811],[-0.0652009,51.3215448],[-0.0641709,51.3264793],[-0.0519829,51.3263721],[-0.0528412,51.334631],[-0.0330779,51.3430876],[0.0019187,51.3376339],[0.0118751,51.3281956],[0.013935,51.2994398],[0.0202865,51.2994398],[0.0240631,51.3072743],[0.0331611,51.3086694],[0.0455207,51.30545],[0.0523872,51.2877392],[0.0616569,51.2577764],[0.0640602,51.2415518],[0.0462074,51.2126342],[0.0407142,51.2109136],[0.0448341,51.1989753],[0.0494689,51.1997283],[0.0558204,51.1944573],[0.0611419,51.1790713],[0.0623435,51.1542061],[0.0577087,51.1417146],[0.0204582,51.1365447],[-0.0446015,51.1336364],[-0.1566964,51.1352522],[-0.1572114,51.1290043],[-0.2287942,51.1183379],[-0.2473336,51.1183379],[-0.2500802,51.1211394],[-0.299347,51.1137042],[-0.3221779,51.1119799],[-0.3223496,51.1058367],[-0.3596001,51.1019563],[-0.3589135,51.1113333],[-0.3863793,51.1117644],[-0.3869014,51.1062516],[-0.4281001,51.0947174],[-0.4856784,51.0951554],[-0.487135,51.0872266],[-0.5297404,51.0865404],[-0.5302259,51.0789914],[-0.61046,51.076551],[-0.6099745,51.080669],[-0.6577994,51.0792202],[-0.6582849,51.0743394],[-0.6836539,51.0707547],[-0.6997979,51.070831],[-0.7296581,51.0744919],[-0.752478,51.0821941]]]},{"id":"Szeged_2011","name":"Szeged orthophoto 2011","type":"tms","template":"http://e.tile.openstreetmap.hu/szeged-2011-10cm/{zoom}/{x}/{y}.png","scaleExtent":[10,22],"polygon":[[[20.1459914,46.2281144],[20.1332261,46.2290431],[20.1258373,46.2298686],[20.122329,46.2309893],[20.1208484,46.2317537],[20.1189709,46.2335126],[20.1131237,46.2413638],[20.1120293,46.2433005],[20.1115733,46.2449996],[20.1111871,46.247092],[20.1112944,46.2487725],[20.1115948,46.2509686],[20.1122171,46.2528047],[20.1129949,46.2542681],[20.1135421,46.2553549],[20.1147705,46.2567977],[20.1352251,46.2768529],[20.1366386,46.2775055],[20.1378939,46.2780301],[20.1393932,46.2783508],[20.1408818,46.2784583],[20.1611494,46.278159],[20.1621093,46.2781579],[20.1635894,46.277702],[20.1661777,46.2761484],[20.1687795,46.2738569],[20.1696108,46.2714413],[20.1695895,46.2704465],[20.1700871,46.2704418],[20.1739897,46.2643295],[20.1766182,46.2582878],[20.1947983,46.25492],[20.1858719,46.2448077],[20.1846595,46.2453122],[20.1780371,46.2383112],[20.1781766,46.2377101],[20.1795258,46.2370961],[20.1725666,46.2300241],[20.1698349,46.2350404],[20.1687701,46.2362946],[20.1670262,46.2378475],[20.1659431,46.2387342],[20.1654408,46.2389988],[20.1654837,46.2389988],[20.1635177,46.2401383],[20.1602051,46.2412003],[20.1592684,46.241531],[20.1592684,46.2415751],[20.1583504,46.2418505],[20.1549473,46.2422869],[20.1510796,46.2351538],[20.1493804,46.232459],[20.1459914,46.2281144]]],"terms_url":"http://www.geo.u-szeged.hu/","terms_text":"SZTE TFGT - University of Szeged","best":true},{"id":"tnris.org","name":"Texas Orthophoto","type":"tms","template":"https://txgi.tnris.org/login/path/ecology-fiona-poem-romeo/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=texas&STYLE=&FORMAT=image/png&tileMatrixSet=0to20&tileMatrix=0to20:{zoom}&tileRow={y}&tileCol={x}","scaleExtent":[0,20],"polygon":[[[-99.9985439,34.5601834],[-95.55654502453,33.99257450647],[-93.89679027134,33.61039304449],[-93.98468089634,32.04103124103],[-93.41613841587,31.02505269211],[-93.74531484297,29.57268254375],[-96.50492070332,28.23158511753],[-97.36942054453,26.95467452634],[-97.04866958924,25.80530249434],[-99.0734177889,26.32559221139],[-100.76599193149,29.02531904433],[-102.3315436893,29.8433892263],[-103.13354564242,28.88112103669],[-104.2887874222,29.28831477845],[-104.7269783935,29.94815782859],[-104.72696778796,30.23535241761],[-106.53450082091,31.78456647831],[-106.75767043939,31.78457253947],[-106.75766067978,32.04385536686],[-106.61848436611,32.04385159755],[-103.11949492759,32.04375683439],[-103.09544343487,36.50045758762],[-103.05798056071,36.54268645422],[-100.00042146824,36.54222227302],[-99.9985439,34.5601834]]],"terms_url":"https://tnris.org/maps-and-data/online-mapping-services/"},{"id":"tf-landscape","name":"Thunderforest Landscape","type":"tms","template":"https://{switch:a,b,c}.tile.thunderforest.com/landscape/{zoom}/{x}/{y}.png","scaleExtent":[0,22],"terms_url":"http://www.thunderforest.com/terms/","terms_text":"Maps © Thunderforest, Data © OpenStreetMap contributors"},{"id":"lu.geoportail.opendata.topo","name":"Topographical Map geoportail.lu","type":"tms","template":"https://{switch:wmts3,wmts4}.geoportail.lu/opendata/wmts/topo/GLOBAL_WEBMERCATOR_4_V3/{zoom}/{x}/{y}.png","scaleExtent":[0,20],"polygon":[[[5.961753,50.17631],[6.026268,50.18496],[6.033182,50.16395],[6.060695,50.15536],[6.07668,50.15913],[6.078237,50.17255],[6.101762,50.17199],[6.122501,50.16437],[6.120101,50.15594],[6.127695,50.14993],[6.113228,50.13739],[6.123691,50.13719],[6.140929,50.1305],[6.135554,50.11899],[6.138082,50.10263],[6.131085,50.09964],[6.135473,50.09119],[6.121939,50.09059],[6.126335,50.07817],[6.131858,50.07348],[6.121171,50.064],[6.114444,50.06139],[6.115631,50.05817],[6.123611,50.06323],[6.136608,50.04178],[6.130343,50.02975],[6.148207,50.02307],[6.13868,50.01572],[6.135938,50.01485],[6.131384,50.01905],[6.130243,50.01819],[6.139343,50.01116],[6.151702,50.01058],[6.145464,49.99689],[6.139657,49.9994],[6.138524,49.99829],[6.142178,49.99535],[6.150227,49.99518],[6.156247,49.98867],[6.173045,49.98589],[6.17348,49.98344],[6.170353,49.98376],[6.165487,49.97115],[6.171512,49.96298],[6.176298,49.962],[6.179954,49.95386],[6.183393,49.9548],[6.179829,49.96307],[6.183312,49.9686],[6.192774,49.97158],[6.199783,49.95352],[6.207066,49.95672],[6.212689,49.9514],[6.225023,49.95039],[6.22044,49.94369],[6.228241,49.93726],[6.22635,49.92766],[6.219133,49.92354],[6.229862,49.92125],[6.236032,49.91355],[6.231867,49.91064],[6.227694,49.91062],[6.232286,49.9072],[6.23381,49.90028],[6.246919,49.89535],[6.257809,49.88724],[6.263008,49.88101],[6.276455,49.87725],[6.281126,49.87957],[6.291661,49.87548],[6.297699,49.86673],[6.309889,49.87107],[6.315324,49.8673],[6.314651,49.86057],[6.323611,49.85188],[6.321577,49.8409],[6.327406,49.83673],[6.336561,49.83998],[6.339366,49.8507],[6.364651,49.85164],[6.402203,49.82098],[6.426434,49.81629],[6.428071,49.81186],[6.43097,49.81129],[6.441608,49.81547],[6.443442,49.81233],[6.45366,49.81275],[6.464538,49.81975],[6.47057,49.82385],[6.496805,49.81277],[6.50669,49.80993],[6.511554,49.80238],[6.51485,49.80513],[6.519604,49.81446],[6.529808,49.81048],[6.532249,49.80686],[6.530829,49.80116],[6.506225,49.78899],[6.519171,49.78344],[6.511055,49.77422],[6.520563,49.76818],[6.520516,49.76134],[6.503734,49.75086],[6.502627,49.73298],[6.507266,49.72938],[6.518092,49.7242],[6.516417,49.72129],[6.511763,49.72016],[6.504791,49.725],[6.498913,49.72639],[6.495576,49.72443],[6.507122,49.71655],[6.507884,49.71215],[6.504598,49.71227],[6.427139,49.66237],[6.439899,49.66025],[6.442511,49.65591],[6.421781,49.61809],[6.398978,49.60094],[6.379408,49.59526],[6.375507,49.58809],[6.384426,49.5801],[6.381188,49.57509],[6.369093,49.5783],[6.357913,49.57166],[6.384902,49.55817],[6.380095,49.54856],[6.358555,49.53296],[6.359322,49.52481],[6.370763,49.50545],[6.370562,49.45732],[6.333403,49.46493],[6.321894,49.47244],[6.295034,49.47928],[6.287889,49.48379],[6.271912,49.49995],[6.241327,49.50693],[6.196692,49.50331],[6.173373,49.50577],[6.160858,49.50085],[6.167099,49.49006],[6.140179,49.48525],[6.129367,49.48803],[6.127247,49.47081],[6.101403,49.46726],[6.104826,49.45076],[6.081667,49.45417],[6.077222,49.46139],[6.059167,49.46306],[6.052222,49.46028],[6.044213,49.44553],[6.025294,49.44703],[6.021545,49.45127],[6.01574,49.44885],[5.994123,49.45301],[5.976569,49.44885],[5.977725,49.45955],[5.972317,49.46087],[5.968912,49.48202],[5.9616,49.49026],[5.915781,49.49835],[5.890334,49.4948],[5.863321,49.50006],[5.84897,49.50826],[5.84828,49.51397],[5.83641,49.51817],[5.831868,49.52639],[5.84308,49.53081],[5.835622,49.54114],[5.816251,49.53325],[5.805201,49.54272],[5.859432,49.57158],[5.868663,49.587],[5.862888,49.58525],[5.851102,49.58379],[5.847116,49.58961],[5.845652,49.5981],[5.869401,49.6106],[5.881819,49.63815],[5.899978,49.63907],[5.899339,49.66239],[5.856561,49.67628],[5.856283,49.68211],[5.875703,49.71118],[5.864811,49.72331],[5.843249,49.71822],[5.82191,49.72128],[5.824894,49.73767],[5.820728,49.74878],[5.786264,49.79079],[5.765172,49.78961],[5.750937,49.79094],[5.741591,49.82126],[5.745814,49.82435],[5.737197,49.83353],[5.740531,49.84142],[5.747012,49.84048],[5.746237,49.84783],[5.753989,49.84878],[5.740663,49.85152],[5.752288,49.85922],[5.749545,49.87554],[5.775668,49.87438],[5.775053,49.88057],[5.734598,49.89341],[5.733033,49.90285],[5.757834,49.91737],[5.760393,49.93252],[5.770728,49.93711],[5.768783,49.94239],[5.768802,49.96104],[5.786724,49.96816],[5.80524,49.96677],[5.806521,49.97321],[5.831293,49.97995],[5.834616,49.98656],[5.818057,49.99936],[5.815606,50.01437],[5.847923,50.02809],[5.861889,50.04581],[5.850872,50.0563],[5.857809,50.07186],[5.880997,50.08069],[5.891965,50.12041],[5.952856,50.13384],[5.961753,50.17631]]],"terms_url":"https://data.public.lu/en/datasets/cartes-topographiques-services-wms-et-wmts/","terms_text":"Administration du Cadastre et de la Topographie"},{"id":"Toulouse-Orthophotoplan-2007","name":"Toulouse - Orthophotoplan 2007","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/toulouse_ortho2007/{zoom}/{x}/{y}","scaleExtent":[0,22],"polygon":[[[1.1919978,43.6328791],[1.2015377,43.6329729],[1.2011107,43.6554932],[1.2227985,43.6557029],[1.2226231,43.6653353],[1.2275341,43.6653849],[1.2275417,43.6656387],[1.2337568,43.6656883],[1.2337644,43.6650153],[1.2351218,43.6650319],[1.2350913,43.6670729],[1.2443566,43.6671556],[1.2441584,43.6743925],[1.2493973,43.6744256],[1.2493973,43.6746628],[1.2555666,43.6747234],[1.2555742,43.6744532],[1.2569545,43.6744697],[1.2568782,43.678529],[1.2874873,43.6788257],[1.2870803,43.7013229],[1.3088219,43.7014632],[1.3086493,43.7127673],[1.3303262,43.7129544],[1.3300242,43.7305221],[1.3367106,43.7305845],[1.3367322,43.7312235],[1.3734338,43.7310456],[1.3735848,43.7245772],[1.4604504,43.7252947],[1.4607783,43.7028034],[1.4824875,43.7029516],[1.4829828,43.6692071],[1.5046832,43.6693616],[1.5048383,43.6581174],[1.5265475,43.6582656],[1.5266945,43.6470298],[1.548368,43.6471633],[1.5485357,43.6359385],[1.5702172,43.636082],[1.5705123,43.6135777],[1.5488166,43.6134276],[1.549097,43.5909479],[1.5707695,43.5910694],[1.5709373,43.5798341],[1.5793714,43.5798894],[1.5794782,43.5737682],[1.5809119,43.5737792],[1.5810859,43.5573794],[1.5712334,43.5573131],[1.5716504,43.5235497],[1.3984804,43.5222618],[1.3986509,43.5110113],[1.3120959,43.5102543],[1.3118968,43.5215192],[1.2902569,43.5213126],[1.2898637,43.5438168],[1.311517,43.5440133],[1.3113271,43.5552596],[1.3036924,43.5551924],[1.3036117,43.5595099],[1.2955449,43.5594317],[1.2955449,43.5595489],[1.2895595,43.5594473],[1.2892899,43.5775366],[1.2675698,43.5773647],[1.2673973,43.5886141],[1.25355,43.5885047],[1.2533774,43.5956282],[1.2518029,43.5956282],[1.2518029,43.5949409],[1.2350437,43.5947847],[1.2350437,43.5945972],[1.2239572,43.5945972],[1.2239357,43.5994708],[1.2139708,43.599299],[1.2138845,43.6046408],[1.2020647,43.6044846],[1.2019464,43.61048],[1.1924294,43.6103695],[1.1919978,43.6328791]]],"terms_url":"https://wiki.openstreetmap.org/wiki/Toulouse/ToulouseMetropoleData","terms_text":"ToulouseMetropole"},{"id":"Toulouse-Orthophotoplan-2011","name":"Toulouse - Orthophotoplan 2011","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/toulouse_ortho2011/{zoom}/{x}/{y}","scaleExtent":[0,22],"polygon":[[[1.1135067,43.6867566],[1.1351836,43.6870842],[1.1348907,43.6983471],[1.1782867,43.6990338],[1.1779903,43.7102786],[1.1996591,43.7106144],[1.1993387,43.7218722],[1.2427356,43.7225269],[1.2424336,43.7337491],[1.2641536,43.734092],[1.2638301,43.7453588],[1.2855285,43.7456548],[1.2852481,43.756935],[1.306925,43.757231],[1.3066446,43.7684779],[1.3283431,43.7687894],[1.3280842,43.780034],[1.4367275,43.7815757],[1.4373098,43.7591004],[1.4590083,43.7593653],[1.4593318,43.7481479],[1.4810303,43.7483972],[1.4813322,43.7371777],[1.5030307,43.7374115],[1.5035915,43.7149664],[1.5253115,43.7151846],[1.5256135,43.7040057],[1.5472688,43.7042552],[1.5475708,43.6930431],[1.5692045,43.6932926],[1.5695712,43.6820316],[1.5912049,43.6822656],[1.5917441,43.6597998],[1.613421,43.6600339],[1.613723,43.6488291],[1.6353783,43.6490788],[1.6384146,43.5140731],[1.2921649,43.5094658],[1.2918629,43.5206966],[1.2702076,43.5203994],[1.2698841,43.5316437],[1.2482288,43.531331],[1.2476048,43.5537788],[1.2259628,43.5534914],[1.2256819,43.564716],[1.2039835,43.564419],[1.2033148,43.5869049],[1.1816164,43.5865611],[1.1810237,43.6090368],[1.1592821,43.6086932],[1.1589585,43.6199523],[1.1372601,43.6196244],[1.1365933,43.642094],[1.1149055,43.6417629],[1.1135067,43.6867566]]],"terms_url":"https://wiki.openstreetmap.org/wiki/Toulouse/ToulouseMetropoleData","terms_text":"ToulouseMetropole"},{"id":"Toulouse-Orthophotoplan-2013","name":"Toulouse - Orthophotoplan 2013","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/toulouse_2013/{zoom}/{x}/{y}","scaleExtent":[0,22],"polygon":[[[1.1135067,43.6867566],[1.1351836,43.6870842],[1.1348907,43.6983471],[1.1782867,43.6990338],[1.1779903,43.7102786],[1.1996591,43.7106144],[1.1993387,43.7218722],[1.2427356,43.7225269],[1.2424336,43.7337491],[1.2641536,43.734092],[1.2638301,43.7453588],[1.2855285,43.7456548],[1.2852481,43.756935],[1.306925,43.757231],[1.3066446,43.7684779],[1.3283431,43.7687894],[1.3280842,43.780034],[1.4367275,43.7815757],[1.4373098,43.7591004],[1.4590083,43.7593653],[1.4593318,43.7481479],[1.4810303,43.7483972],[1.4813322,43.7371777],[1.5030307,43.7374115],[1.5035915,43.7149664],[1.5253115,43.7151846],[1.5256135,43.7040057],[1.5472688,43.7042552],[1.5475708,43.6930431],[1.5692045,43.6932926],[1.5695712,43.6820316],[1.5912049,43.6822656],[1.5917441,43.6597998],[1.613421,43.6600339],[1.613723,43.6488291],[1.6353783,43.6490788],[1.6384146,43.5140731],[1.2921649,43.5094658],[1.2918629,43.5206966],[1.2702076,43.5203994],[1.2698841,43.5316437],[1.2482288,43.531331],[1.2476048,43.5537788],[1.2259628,43.5534914],[1.2256819,43.564716],[1.2039835,43.564419],[1.2033148,43.5869049],[1.1816164,43.5865611],[1.1810237,43.6090368],[1.1592821,43.6086932],[1.1589585,43.6199523],[1.1372601,43.6196244],[1.1365933,43.642094],[1.1149055,43.6417629],[1.1135067,43.6867566]]],"terms_url":"https://wiki.openstreetmap.org/wiki/Toulouse/ToulouseMetropoleData","terms_text":"ToulouseMetropole"},{"id":"Toulouse-Orthophotoplan-2015","name":"Toulouse - Orthophotoplan 2015","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/toulouse_2015/{zoom}/{x}/{y}","scaleExtent":[0,22],"polygon":[[[1.1135067,43.6867566],[1.1351836,43.6870842],[1.1348907,43.6983471],[1.1782867,43.6990338],[1.1779903,43.7102786],[1.1996591,43.7106144],[1.1993387,43.7218722],[1.2427356,43.7225269],[1.2424336,43.7337491],[1.2641536,43.734092],[1.2638301,43.7453588],[1.2855285,43.7456548],[1.2852481,43.756935],[1.306925,43.757231],[1.3066446,43.7684779],[1.3283431,43.7687894],[1.3280842,43.780034],[1.4367275,43.7815757],[1.4373098,43.7591004],[1.4590083,43.7593653],[1.4593318,43.7481479],[1.4810303,43.7483972],[1.4813322,43.7371777],[1.5030307,43.7374115],[1.5035915,43.7149664],[1.5253115,43.7151846],[1.5256135,43.7040057],[1.5472688,43.7042552],[1.5475708,43.6930431],[1.5692045,43.6932926],[1.5695712,43.6820316],[1.5912049,43.6822656],[1.5917441,43.6597998],[1.613421,43.6600339],[1.613723,43.6488291],[1.6353783,43.6490788],[1.6384146,43.5140731],[1.2921649,43.5094658],[1.2918629,43.5206966],[1.2702076,43.5203994],[1.2698841,43.5316437],[1.2482288,43.531331],[1.2476048,43.5537788],[1.2259628,43.5534914],[1.2256819,43.564716],[1.2039835,43.564419],[1.2033148,43.5869049],[1.1816164,43.5865611],[1.1810237,43.6090368],[1.1592821,43.6086932],[1.1589585,43.6199523],[1.1372601,43.6196244],[1.1365933,43.642094],[1.1149055,43.6417629],[1.1135067,43.6867566]]],"terms_url":"https://wiki.openstreetmap.org/wiki/Toulouse/ToulouseMetropoleData","terms_text":"ToulouseMetropole"},{"id":"Tours-Orthophoto-2008_2010","name":"Tours - Orthophotos 2008-2010","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/tours/{zoom}/{x}/{y}","scaleExtent":[0,20],"polygon":[[[0.5457462,47.465264],[0.54585,47.4608163],[0.5392188,47.4606983],[0.5393484,47.456243],[0.5327959,47.4561003],[0.5329011,47.451565],[0.52619,47.4514013],[0.5265854,47.4424884],[0.5000941,47.4420739],[0.5002357,47.4375835],[0.4936014,47.4374324],[0.4937,47.4329285],[0.4606141,47.4324593],[0.4607248,47.4279827],[0.4541016,47.4278125],[0.454932,47.4053921],[0.4615431,47.4054476],[0.4619097,47.3964924],[0.4684346,47.3966005],[0.4691319,47.3786415],[0.4757125,47.3787609],[0.4762116,47.3652018],[0.4828297,47.3653499],[0.4829611,47.3608321],[0.4763543,47.360743],[0.476654,47.3517263],[0.4700497,47.3516186],[0.4701971,47.3471313],[0.4637503,47.3470104],[0.4571425,47.3424146],[0.4572922,47.3379061],[0.4506741,47.3378081],[0.4508379,47.3333051],[0.4442212,47.3332032],[0.4443809,47.328711],[0.4311392,47.3284977],[0.4316262,47.3150004],[0.4382432,47.3151136],[0.4383815,47.3106174],[0.4714487,47.3111374],[0.4713096,47.3156565],[0.477888,47.3157542],[0.4780733,47.3112802],[0.4846826,47.3113639],[0.4848576,47.3068686],[0.4914359,47.3069803],[0.491745,47.2979733],[0.4851578,47.2978722],[0.4854269,47.2888744],[0.4788485,47.2887697],[0.4791574,47.2797818],[0.4857769,47.2799005],[0.4859107,47.2753885],[0.492539,47.2755029],[0.4926669,47.2710127],[0.4992986,47.2711066],[0.4994296,47.2666116],[0.5192658,47.2669245],[0.5194225,47.2624231],[0.5260186,47.2625205],[0.5258735,47.2670183],[0.5456972,47.2673383],[0.5455537,47.2718283],[0.5587737,47.2720366],[0.5586259,47.2765185],[0.5652252,47.2766278],[0.5650848,47.2811206],[0.5716753,47.2812285],[0.5715223,47.2857217],[0.5781436,47.2858299],[0.5779914,47.2903294],[0.5846023,47.2904263],[0.5843076,47.2994231],[0.597499,47.2996094],[0.5976637,47.2951375],[0.6571596,47.2960036],[0.6572988,47.2915091],[0.6705019,47.2917186],[0.6703475,47.2962082],[0.6836175,47.2963688],[0.6834322,47.3008929],[0.690062,47.3009558],[0.6899241,47.3054703],[0.7362019,47.3061157],[0.7360848,47.3106063],[0.7559022,47.3108935],[0.7557718,47.315392],[0.7623755,47.3154716],[0.7622314,47.3199941],[0.7754911,47.3201546],[0.77497,47.3388218],[0.7745786,47.351628],[0.7680363,47.3515901],[0.767589,47.3605298],[0.7742443,47.3606238],[0.7733465,47.3921266],[0.7667434,47.3920195],[0.7664411,47.4010837],[0.7730647,47.4011115],[0.7728868,47.4101297],[0.7661849,47.4100226],[0.7660267,47.4145044],[0.7527613,47.4143038],[0.7529788,47.4098086],[0.7462373,47.4097016],[0.7459424,47.4232208],[0.7392324,47.4231451],[0.738869,47.4366116],[0.7323267,47.4365171],[0.7321869,47.4410556],[0.7255048,47.44098],[0.7254209,47.4453479],[0.7318793,47.4454803],[0.7318514,47.4501126],[0.7384496,47.450226],[0.7383098,47.454631],[0.7449359,47.4547444],[0.7443209,47.4771985],[0.7310685,47.4769717],[0.7309008,47.4815445],[0.7176205,47.4812611],[0.7177883,47.4768394],[0.69777,47.4764993],[0.6980496,47.4719827],[0.6914514,47.4718882],[0.6917309,47.4630241],[0.6851048,47.4629295],[0.684937,47.4673524],[0.678255,47.4673335],[0.6779754,47.4762158],[0.6714051,47.4761592],[0.6710417,47.4881952],[0.6577334,47.4879685],[0.6578173,47.48504],[0.6511911,47.4848322],[0.6514707,47.4758568],[0.6448166,47.4757245],[0.6449284,47.4712646],[0.6117976,47.4707543],[0.6118815,47.4663129],[0.6052833,47.4661239],[0.6054231,47.4616631],[0.5988808,47.4615497],[0.5990206,47.4570886],[0.572488,47.4566916],[0.5721805,47.4656513],[0.5457462,47.465264]]],"terms_url":"http://wiki.openstreetmap.org/wiki/Tours/Orthophoto","terms_text":"Orthophoto Tour(s) Plus 2008"},{"id":"Tours-Orthophoto-2013","name":"Tours - Orthophotos 2013","type":"tms","template":"http://wms.openstreetmap.fr/tms/1.0.0/tours_2013/{zoom}/{x}/{y}","scaleExtent":[0,22],"polygon":[[[0.427093505859375,47.26199018174824],[0.427093505859375,47.50096732311069],[0.814361572265625,47.50096732311069],[0.814361572265625,47.26199018174824],[0.427093505859375,47.26199018174824]]],"terms_url":"http://wiki.openstreetmap.org/wiki/Tours/Orthophoto","terms_text":"Orthophoto Tour(s)plus 2013"},{"id":"US_Forest_Service_roads","name":"U.S. Forest Service roads","type":"tms","template":"http://osm.cycle.travel/forest/{zoom}/{x}/{y}.png","scaleExtent":[0,19],"polygon":[[[-124.7617886,48.4130148],[-124.6059492,45.90245],[-124.9934269,40.0557614],[-122.5369737,36.8566086],[-119.9775867,33.0064099],[-117.675935,32.4630223],[-114.8612307,32.4799891],[-111.0089311,31.336015],[-108.1992687,31.3260016],[-108.1871123,31.7755116],[-106.5307225,31.7820947],[-106.4842052,31.7464455],[-106.429317,31.7520583],[-106.2868855,31.5613291],[-106.205248,31.446704],[-105.0205259,30.5360988],[-104.5881916,29.6997856],[-103.2518856,28.8908685],[-102.7173632,29.3920567],[-102.1513983,29.7475702],[-101.2552871,29.4810523],[-100.0062436,28.0082173],[-99.2351068,26.4475962],[-98.0109067,25.9928035],[-97.435024,25.8266009],[-96.9555259,25.9821589],[-96.8061741,27.7978168],[-95.5563349,28.5876066],[-93.7405308,29.4742093],[-90.9028456,28.8564513],[-88.0156706,28.9944338],[-88.0162494,30.0038862],[-86.0277506,30.0047454],[-84.0187909,28.9961781],[-81.9971976,25.9826768],[-81.9966618,25.0134917],[-84.0165592,25.0125783],[-84.0160068,24.0052745],[-80.0199985,24.007096],[-79.8901116,26.8550713],[-80.0245309,32.0161282],[-75.4147385,35.0531894],[-74.0211163,39.5727927],[-72.002019,40.9912464],[-69.8797398,40.9920457],[-69.8489304,43.2619916],[-66.9452845,44.7104937],[-67.7596632,47.0990024],[-69.2505131,47.5122328],[-70.4614886,46.2176574],[-71.412273,45.254878],[-72.0222508,45.0059846],[-75.0798841,44.9802854],[-76.9023061,43.8024568],[-78.7623935,43.6249578],[-79.15798,43.4462589],[-79.0060087,42.8005317],[-82.662475,41.6889458],[-82.1761642,43.588535],[-83.2813977,46.138853],[-87.5064535,48.0142702],[-88.3492194,48.2963271],[-89.4353148,47.9837822],[-93.9981078,49.0067142],[-95.1105379,49.412004],[-96.0131199,49.0060547],[-123.3228926,49.0042878],[-123.2275233,48.1849927],[-124.7617886,48.4130148]],[[-160.5787616,22.5062947],[-160.5782192,21.4984647],[-158.7470604,21.2439843],[-157.5083185,20.995803],[-155.9961942,18.7790194],[-154.6217803,18.7586966],[-154.6890176,19.8805722],[-156.2927622,21.2225888],[-157.5047384,21.9984962],[-159.0093692,22.5070181],[-160.5787616,22.5062947]],[[-167.1571546,68.721974],[-164.8553982,67.0255078],[-168.002195,66.0017503],[-169.0087448,66.001546],[-169.0075381,64.9987675],[-172.5143281,63.8767267],[-173.8197023,59.74014],[-162.5018149,58.0005815],[-160.0159024,58.0012389],[-160.0149725,57.000035],[-160.5054788,56.9999017],[-165.8092575,54.824847],[-178.000097,52.2446469],[-177.9992996,51.2554252],[-171.4689067,51.8215329],[-162.40251,53.956664],[-159.0075717,55.002502],[-158.0190709,55.0027849],[-151.9963213,55.9991902],[-151.500341,57.9987853],[-151.5012894,58.9919816],[-138.5159989,58.9953194],[-138.5150471,57.9986434],[-133.9948193,54.0031685],[-130.0044418,54.0043387],[-130.0070826,57.0000507],[-131.975877,56.9995156],[-135.1229873,59.756601],[-138.0071813,59.991805],[-139.1715881,60.4127229],[-140.9874011,61.0118551],[-140.9683975,69.9535069],[-156.176891,71.5633329],[-160.413634,70.7397728],[-163.0218273,69.9707435],[-164.9717003,68.994689],[-167.1571546,68.721974]]]},{"id":"Zuerich-zh_uebersichtsplan-tms","name":"Übersichtsplan Zürich","type":"tms","template":"http://mapproxy.sosm.ch:8080/tiles/zh_uebersichtsplan/EPSG900913/{zoom}/{x}/{y}.png?origin=nw","scaleExtent":[0,21],"polygon":[[[8.4482,47.321],[8.4482,47.4339],[8.6248,47.4339],[8.6248,47.321],[8.4482,47.321]]],"terms_text":"Stadt Zürich Open Government Data"},{"id":"USGS-Large_Scale","name":"USGS Large Scale Imagery","type":"tms","template":"http://{switch:a,b,c}.tile.openstreetmap.us/usgs_large_scale/{zoom}/{x}/{y}.jpg","scaleExtent":[12,20],"polygon":[[[-123.2549305,48.7529029],[-123.2549305,48.5592263],[-123.192224,48.5592263],[-123.192224,48.4348366],[-122.9419646,48.4348366],[-122.9419646,48.3720812],[-122.8806229,48.3720812],[-122.8806229,48.3094763],[-122.8167566,48.3094763],[-122.8167566,48.1904587],[-123.0041133,48.1904587],[-123.0041133,48.1275918],[-123.058416,48.1275918],[-123.058416,48.190514],[-123.254113,48.190514],[-123.254113,48.1274982],[-123.3706593,48.1274982],[-123.3706593,48.1908403],[-124.0582632,48.1908403],[-124.0582632,48.253442],[-124.1815163,48.253442],[-124.1815163,48.3164666],[-124.4319117,48.3164666],[-124.4319117,48.3782613],[-124.5564618,48.3782613],[-124.5564618,48.4408305],[-124.7555107,48.4408305],[-124.7555107,48.1914986],[-124.8185282,48.1914986],[-124.8185282,48.1228381],[-124.7552951,48.1228381],[-124.7552951,47.5535253],[-124.3812108,47.5535253],[-124.3812108,47.1218696],[-124.1928897,47.1218696],[-124.1928897,43.7569431],[-124.4443382,43.7569431],[-124.4443382,43.1425556],[-124.6398855,43.1425556],[-124.6398855,42.6194503],[-124.4438525,42.6194503],[-124.4438525,39.8080662],[-123.8815685,39.8080662],[-123.8815685,39.1102825],[-123.75805,39.1102825],[-123.75805,38.4968799],[-123.2702803,38.4968799],[-123.2702803,37.9331905],[-122.8148084,37.9331905],[-122.8148084,37.8019606],[-122.5664316,37.8019606],[-122.5664316,36.9319611],[-121.8784026,36.9319611],[-121.8784026,36.6897596],[-122.0034748,36.6897596],[-122.0034748,36.4341056],[-121.9414159,36.4341056],[-121.9414159,35.9297636],[-121.5040977,35.9297636],[-121.5040977,35.8100273],[-121.3790276,35.8100273],[-121.3790276,35.4239164],[-120.9426515,35.4239164],[-120.9426515,35.1849683],[-120.8171978,35.1849683],[-120.8171978,35.1219894],[-120.6918447,35.1219894],[-120.6918447,34.4966794],[-120.5045898,34.4966794],[-120.5045898,34.4339651],[-120.0078775,34.4339651],[-120.0078775,34.3682626],[-119.5283517,34.3682626],[-119.5283517,34.0576434],[-119.0060985,34.0576434],[-119.0060985,33.9975267],[-118.5046259,33.9975267],[-118.5046259,33.8694631],[-118.4413209,33.8694631],[-118.4413209,33.6865253],[-118.066912,33.6865253],[-118.066912,33.3063832],[-117.5030045,33.3063832],[-117.5030045,33.0500337],[-117.3188195,33.0500337],[-117.3188195,32.6205888],[-117.1917023,32.6205888],[-117.1917023,32.4974566],[-116.746496,32.4974566],[-116.746496,32.5609161],[-115.9970138,32.5609161],[-115.9970138,32.6264942],[-114.8808125,32.6264942],[-114.8808125,32.4340796],[-114.6294474,32.4340796],[-114.6294474,32.3731636],[-114.4447437,32.3731636],[-114.4447437,32.3075418],[-114.2557628,32.3075418],[-114.2557628,32.2444561],[-114.0680274,32.2444561],[-114.0680274,32.1829113],[-113.8166499,32.1829113],[-113.8166499,32.1207622],[-113.6307421,32.1207622],[-113.6307421,32.0565099],[-113.4417495,32.0565099],[-113.4417495,31.9984372],[-113.2546027,31.9984372],[-113.2546027,31.9325434],[-113.068072,31.9325434],[-113.068072,31.8718062],[-112.8161105,31.8718062],[-112.8161105,31.8104171],[-112.6308756,31.8104171],[-112.6308756,31.7464723],[-112.4418918,31.7464723],[-112.4418918,31.6856001],[-112.257192,31.6856001],[-112.257192,31.6210352],[-112.0033787,31.6210352],[-112.0033787,31.559584],[-111.815619,31.559584],[-111.815619,31.4970238],[-111.6278586,31.4970238],[-111.6278586,31.4339867],[-111.4418978,31.4339867],[-111.4418978,31.3733859],[-111.2559708,31.3733859],[-111.2559708,31.3113225],[-108.1845822,31.3113225],[-108.1845822,31.7459502],[-106.5065055,31.7459502],[-106.5065055,31.6842308],[-106.3797265,31.6842308],[-106.3797265,31.621752],[-106.317434,31.621752],[-106.317434,31.4968167],[-106.2551769,31.4968167],[-106.2551769,31.4344889],[-106.1924698,31.4344889],[-106.1924698,31.3721296],[-106.0039212,31.3721296],[-106.0039212,31.309328],[-105.9416582,31.309328],[-105.9416582,31.2457547],[-105.8798174,31.2457547],[-105.8798174,31.1836194],[-105.8162349,31.1836194],[-105.8162349,31.1207155],[-105.6921198,31.1207155],[-105.6921198,31.0584835],[-105.6302881,31.0584835],[-105.6302881,30.9328271],[-105.5044418,30.9328271],[-105.5044418,30.8715864],[-105.4412973,30.8715864],[-105.4412973,30.808463],[-105.3781497,30.808463],[-105.3781497,30.7471828],[-105.1904658,30.7471828],[-105.1904658,30.6843231],[-105.1286244,30.6843231],[-105.1286244,30.6199737],[-105.0036504,30.6199737],[-105.0036504,30.5589058],[-104.9417962,30.5589058],[-104.9417962,30.4963236],[-104.8782018,30.4963236],[-104.8782018,30.3098261],[-104.8155257,30.3098261],[-104.8155257,30.2478305],[-104.7536079,30.2478305],[-104.7536079,29.9353916],[-104.690949,29.9353916],[-104.690949,29.8090156],[-104.6291301,29.8090156],[-104.6291301,29.6843577],[-104.5659869,29.6843577],[-104.5659869,29.6223459],[-104.5037188,29.6223459],[-104.5037188,29.5595436],[-104.4410072,29.5595436],[-104.4410072,29.4974832],[-104.2537551,29.4974832],[-104.2537551,29.3716718],[-104.1291984,29.3716718],[-104.1291984,29.3091621],[-104.0688737,29.3091621],[-104.0688737,29.2467276],[-103.8187309,29.2467276],[-103.8187309,29.1843076],[-103.755736,29.1843076],[-103.755736,29.1223174],[-103.5667542,29.1223174],[-103.5667542,29.0598119],[-103.5049819,29.0598119],[-103.5049819,28.9967506],[-103.3165753,28.9967506],[-103.3165753,28.9346923],[-103.0597572,28.9346923],[-103.0597572,29.0592965],[-102.9979694,29.0592965],[-102.9979694,29.1212855],[-102.9331397,29.1212855],[-102.9331397,29.1848575],[-102.8095989,29.1848575],[-102.8095989,29.2526154],[-102.8701345,29.2526154],[-102.8701345,29.308096],[-102.8096681,29.308096],[-102.8096681,29.3715484],[-102.7475655,29.3715484],[-102.7475655,29.5581899],[-102.684554,29.5581899],[-102.684554,29.6847655],[-102.4967764,29.6847655],[-102.4967764,29.7457694],[-102.3086647,29.7457694],[-102.3086647,29.8086627],[-102.1909323,29.8086627],[-102.1909323,29.7460097],[-101.5049914,29.7460097],[-101.5049914,29.6846777],[-101.3805796,29.6846777],[-101.3805796,29.5594459],[-101.3175057,29.5594459],[-101.3175057,29.4958934],[-101.1910075,29.4958934],[-101.1910075,29.4326115],[-101.067501,29.4326115],[-101.067501,29.308808],[-100.9418897,29.308808],[-100.9418897,29.2456231],[-100.8167271,29.2456231],[-100.8167271,29.1190449],[-100.7522672,29.1190449],[-100.7522672,29.0578214],[-100.6925358,29.0578214],[-100.6925358,28.8720431],[-100.6290158,28.8720431],[-100.6290158,28.8095363],[-100.5679901,28.8095363],[-100.5679901,28.622554],[-100.5040411,28.622554],[-100.5040411,28.5583804],[-100.4421832,28.5583804],[-100.4421832,28.4968266],[-100.379434,28.4968266],[-100.379434,28.3092865],[-100.3171942,28.3092865],[-100.3171942,28.1835681],[-100.254483,28.1835681],[-100.254483,28.1213885],[-100.1282282,28.1213885],[-100.1282282,28.059215],[-100.0659537,28.059215],[-100.0659537,27.9966087],[-100.0023855,27.9966087],[-100.0023855,27.9332152],[-99.9426497,27.9332152],[-99.9426497,27.7454658],[-99.816851,27.7454658],[-99.816851,27.6834301],[-99.7541346,27.6834301],[-99.7541346,27.6221543],[-99.6291629,27.6221543],[-99.6291629,27.5588977],[-99.5672838,27.5588977],[-99.5672838,27.4353752],[-99.5041798,27.4353752],[-99.5041798,27.3774021],[-99.5671796,27.3774021],[-99.5671796,27.2463726],[-99.504975,27.2463726],[-99.504975,26.9965649],[-99.4427427,26.9965649],[-99.4427427,26.872803],[-99.3800633,26.872803],[-99.3800633,26.8068179],[-99.3190684,26.8068179],[-99.3190684,26.7473614],[-99.2537541,26.7473614],[-99.2537541,26.6210068],[-99.1910617,26.6210068],[-99.1910617,26.4956737],[-99.1300639,26.4956737],[-99.1300639,26.3713808],[-99.0029473,26.3713808],[-99.0029473,26.3093836],[-98.816572,26.3093836],[-98.816572,26.2457762],[-98.6920082,26.2457762],[-98.6920082,26.1837096],[-98.4440896,26.1837096],[-98.4440896,26.1217217],[-98.3823181,26.1217217],[-98.3823181,26.0596488],[-98.2532707,26.0596488],[-98.2532707,25.9986871],[-98.0109084,25.9986871],[-98.0109084,25.9932255],[-97.6932319,25.9932255],[-97.6932319,25.9334103],[-97.6313904,25.9334103],[-97.6313904,25.8695893],[-97.5046779,25.8695893],[-97.5046779,25.8073488],[-97.3083401,25.8073488],[-97.3083401,25.8731159],[-97.2456326,25.8731159],[-97.2456326,25.9353731],[-97.1138939,25.9353731],[-97.1138939,27.6809179],[-97.0571035,27.6809179],[-97.0571035,27.8108242],[-95.5810766,27.8108242],[-95.5810766,28.7468827],[-94.271041,28.7468827],[-94.271041,29.5594076],[-92.5029947,29.5594076],[-92.5029947,29.4974754],[-91.8776216,29.4974754],[-91.8776216,29.3727013],[-91.378418,29.3727013],[-91.378418,29.2468326],[-91.3153953,29.2468326],[-91.3153953,29.1844301],[-91.1294702,29.1844301],[-91.1294702,29.1232559],[-91.0052632,29.1232559],[-91.0052632,28.9968437],[-89.4500159,28.9968437],[-89.4500159,28.8677422],[-88.8104309,28.8677422],[-88.8104309,30.1841864],[-85.8791527,30.1841864],[-85.8791527,29.5455038],[-84.8368083,29.5455038],[-84.8368083,29.6225158],[-84.7482786,29.6225158],[-84.7482786,29.683624],[-84.685894,29.683624],[-84.685894,29.7468386],[-83.6296975,29.7468386],[-83.6296975,29.4324361],[-83.3174937,29.4324361],[-83.3174937,29.0579442],[-82.879659,29.0579442],[-82.879659,27.7453529],[-82.8182822,27.7453529],[-82.8182822,26.9290868],[-82.3796782,26.9290868],[-82.3796782,26.3694183],[-81.8777106,26.3694183],[-81.8777106,25.805971],[-81.5036862,25.805971],[-81.5036862,25.7474753],[-81.4405462,25.7474753],[-81.4405462,25.6851489],[-81.3155883,25.6851489],[-81.3155883,25.5600985],[-81.2538534,25.5600985],[-81.2538534,25.4342361],[-81.1902012,25.4342361],[-81.1902012,25.1234341],[-81.1288133,25.1234341],[-81.1288133,25.0619389],[-81.0649231,25.0619389],[-81.0649231,24.8157807],[-81.6289469,24.8157807],[-81.6289469,24.7538367],[-81.6907173,24.7538367],[-81.6907173,24.6899374],[-81.8173189,24.6899374],[-81.8173189,24.6279161],[-82.1910041,24.6279161],[-82.1910041,24.496294],[-81.6216596,24.496294],[-81.6216596,24.559484],[-81.372006,24.559484],[-81.372006,24.6220687],[-81.0593278,24.6220687],[-81.0593278,24.684826],[-80.9347147,24.684826],[-80.9347147,24.7474828],[-80.7471081,24.7474828],[-80.7471081,24.8100618],[-80.3629898,24.8100618],[-80.3629898,25.1175858],[-80.122344,25.1175858],[-80.122344,25.7472357],[-80.0588458,25.7472357],[-80.0588458,26.3708251],[-79.995837,26.3708251],[-79.995837,26.9398003],[-80.0587265,26.9398003],[-80.0587265,27.1277466],[-80.1226251,27.1277466],[-80.1226251,27.2534279],[-80.1846956,27.2534279],[-80.1846956,27.3781229],[-80.246175,27.3781229],[-80.246175,27.5658729],[-80.3094768,27.5658729],[-80.3094768,27.7530311],[-80.3721485,27.7530311],[-80.3721485,27.8774451],[-80.4351457,27.8774451],[-80.4351457,28.0033366],[-80.4966078,28.0033366],[-80.4966078,28.1277326],[-80.5587159,28.1277326],[-80.5587159,28.3723509],[-80.4966335,28.3723509],[-80.4966335,29.5160326],[-81.1213644,29.5160326],[-81.1213644,31.6846966],[-80.6018723,31.6846966],[-80.6018723,32.2475309],[-79.4921024,32.2475309],[-79.4921024,32.9970261],[-79.1116488,32.9970261],[-79.1116488,33.3729457],[-78.6153621,33.3729457],[-78.6153621,33.8097638],[-77.9316963,33.8097638],[-77.9316963,33.8718243],[-77.8692252,33.8718243],[-77.8692252,34.0552454],[-77.6826392,34.0552454],[-77.6826392,34.2974598],[-77.2453509,34.2974598],[-77.2453509,34.5598585],[-76.4973277,34.5598585],[-76.4973277,34.622796],[-76.4337602,34.622796],[-76.4337602,34.6849285],[-76.373212,34.6849285],[-76.373212,34.7467674],[-76.3059364,34.7467674],[-76.3059364,34.808551],[-76.2468017,34.808551],[-76.2468017,34.8728418],[-76.1825922,34.8728418],[-76.1825922,34.9335332],[-76.120814,34.9335332],[-76.120814,34.9952359],[-75.9979015,34.9952359],[-75.9979015,35.0578182],[-75.870338,35.0578182],[-75.870338,35.1219097],[-75.7462194,35.1219097],[-75.7462194,35.1818911],[-75.4929694,35.1818911],[-75.4929694,35.3082988],[-75.4325662,35.3082988],[-75.4325662,35.7542495],[-75.4969907,35.7542495],[-75.4969907,37.8105602],[-75.3082972,37.8105602],[-75.3082972,37.8720088],[-75.245601,37.8720088],[-75.245601,37.9954849],[-75.1828751,37.9954849],[-75.1828751,38.0585079],[-75.1184793,38.0585079],[-75.1184793,38.2469091],[-75.0592098,38.2469091],[-75.0592098,38.3704316],[-74.9948111,38.3704316],[-74.9948111,38.8718417],[-74.4878252,38.8718417],[-74.4878252,39.3089428],[-74.1766317,39.3089428],[-74.1766317,39.6224653],[-74.0567045,39.6224653],[-74.0567045,39.933178],[-73.9959035,39.933178],[-73.9959035,40.1854852],[-73.9341593,40.1854852],[-73.9341593,40.4959486],[-73.8723024,40.4959486],[-73.8723024,40.5527135],[-71.8074506,40.5527135],[-71.8074506,41.3088005],[-70.882512,41.3088005],[-70.882512,41.184978],[-70.7461947,41.184978],[-70.7461947,41.3091865],[-70.4337553,41.3091865],[-70.4337553,41.4963885],[-69.9334281,41.4963885],[-69.9334281,41.6230802],[-69.869857,41.6230802],[-69.869857,41.8776895],[-69.935791,41.8776895],[-69.935791,42.0032342],[-69.9975823,42.0032342],[-69.9975823,42.0650191],[-70.0606103,42.0650191],[-70.0606103,42.1294348],[-70.5572884,42.1294348],[-70.5572884,43.2487079],[-70.4974097,43.2487079],[-70.4974097,43.3092194],[-70.3704249,43.3092194],[-70.3704249,43.371963],[-70.3085701,43.371963],[-70.3085701,43.4969879],[-70.183921,43.4969879],[-70.183921,43.6223531],[-70.057583,43.6223531],[-70.057583,43.6850173],[-69.7455247,43.6850173],[-69.7455247,43.7476571],[-69.2472845,43.7476571],[-69.2472845,43.8107035],[-69.0560701,43.8107035],[-69.0560701,43.8717247],[-68.9950522,43.8717247],[-68.9950522,43.9982022],[-68.4963672,43.9982022],[-68.4963672,44.0597368],[-68.3081038,44.0597368],[-68.3081038,44.122137],[-68.1851802,44.122137],[-68.1851802,44.3081382],[-67.9956019,44.3081382],[-67.9956019,44.3727489],[-67.8103041,44.3727489],[-67.8103041,44.435178],[-67.4965289,44.435178],[-67.4965289,44.4968776],[-67.37102,44.4968776],[-67.37102,44.5600642],[-67.1848753,44.5600642],[-67.1848753,44.6213345],[-67.1221208,44.6213345],[-67.1221208,44.6867918],[-67.059365,44.6867918],[-67.059365,44.7473657],[-66.9311098,44.7473657],[-66.9311098,44.9406566],[-66.994683,44.9406566],[-66.994683,45.0024514],[-67.0595847,45.0024514],[-67.0595847,45.1273377],[-67.1201974,45.1273377],[-67.1201974,45.1910115],[-67.2469811,45.1910115],[-67.2469811,45.253442],[-67.3177546,45.253442],[-67.3177546,45.1898369],[-67.370749,45.1898369],[-67.370749,45.2534001],[-67.4326888,45.2534001],[-67.4326888,45.3083409],[-67.3708571,45.3083409],[-67.3708571,45.4396986],[-67.4305573,45.4396986],[-67.4305573,45.4950095],[-67.37099,45.4950095],[-67.37099,45.6264543],[-67.6214982,45.6264543],[-67.6214982,45.6896133],[-67.683828,45.6896133],[-67.683828,45.753259],[-67.7462097,45.753259],[-67.7462097,47.1268165],[-67.8700141,47.1268165],[-67.8700141,47.1900278],[-67.9323803,47.1900278],[-67.9323803,47.2539678],[-67.9959387,47.2539678],[-67.9959387,47.3149737],[-68.1206676,47.3149737],[-68.1206676,47.3780823],[-68.4423175,47.3780823],[-68.4423175,47.3166082],[-68.6314305,47.3166082],[-68.6314305,47.2544676],[-68.9978037,47.2544676],[-68.9978037,47.439895],[-69.0607223,47.439895],[-69.0607223,47.5047558],[-69.2538122,47.5047558],[-69.2538122,47.4398084],[-69.3179284,47.4398084],[-69.3179284,47.378601],[-69.4438546,47.378601],[-69.4438546,47.3156274],[-69.5038204,47.3156274],[-69.5038204,47.2525839],[-69.5667838,47.2525839],[-69.5667838,47.1910884],[-69.6303478,47.1910884],[-69.6303478,47.128701],[-69.6933103,47.128701],[-69.6933103,47.0654307],[-69.7557063,47.0654307],[-69.7557063,47.0042751],[-69.8180391,47.0042751],[-69.8180391,46.9415344],[-69.8804023,46.9415344],[-69.8804023,46.8792519],[-69.9421674,46.8792519],[-69.9421674,46.8177399],[-70.0063088,46.8177399],[-70.0063088,46.6920295],[-70.0704265,46.6920295],[-70.0704265,46.4425926],[-70.1945902,46.4425926],[-70.1945902,46.3785887],[-70.2562047,46.3785887],[-70.2562047,46.3152628],[-70.3203651,46.3152628],[-70.3203651,46.0651209],[-70.3814988,46.0651209],[-70.3814988,45.93552],[-70.3201618,45.93552],[-70.3201618,45.879479],[-70.4493131,45.879479],[-70.4493131,45.7538713],[-70.5070021,45.7538713],[-70.5070021,45.6916912],[-70.6316642,45.6916912],[-70.6316642,45.6291619],[-70.7575538,45.6291619],[-70.7575538,45.4414685],[-70.8809878,45.4414685],[-70.8809878,45.3780612],[-71.13328,45.3780612],[-71.13328,45.3151452],[-71.3830282,45.3151452],[-71.3830282,45.253416],[-71.5076448,45.253416],[-71.5076448,45.0655726],[-73.9418929,45.0655726],[-73.9418929,45.0031242],[-74.7469725,45.0031242],[-74.7469725,45.0649003],[-74.8800964,45.0649003],[-74.8800964,45.0029023],[-75.0662455,45.0029023],[-75.0662455,44.9415167],[-75.2539363,44.9415167],[-75.2539363,44.8776043],[-75.3789648,44.8776043],[-75.3789648,44.8153462],[-75.4431283,44.8153462],[-75.4431283,44.7536053],[-75.5666566,44.7536053],[-75.5666566,44.6909879],[-75.6290205,44.6909879],[-75.6290205,44.6284958],[-75.7540484,44.6284958],[-75.7540484,44.566385],[-75.817312,44.566385],[-75.817312,44.5028932],[-75.8799549,44.5028932],[-75.8799549,44.3784946],[-76.1300319,44.3784946],[-76.1300319,44.3159227],[-76.1926961,44.3159227],[-76.1926961,44.2534378],[-76.3182619,44.2534378],[-76.3182619,44.1916726],[-76.3792975,44.1916726],[-76.3792975,44.0653733],[-76.4427584,44.0653733],[-76.4427584,43.9963825],[-76.317027,43.9963825],[-76.317027,43.9414581],[-76.5076611,43.9414581],[-76.5076611,43.8723335],[-76.3829974,43.8723335],[-76.3829974,43.8091872],[-76.2534102,43.8091872],[-76.2534102,43.5665222],[-76.5064833,43.5665222],[-76.5064833,43.5033881],[-76.6331208,43.5033881],[-76.6331208,43.4432252],[-76.6951085,43.4432252],[-76.6951085,43.3786858],[-76.8177798,43.3786858],[-76.8177798,43.318066],[-77.682,43.318066],[-77.682,43.3789376],[-78.0565883,43.3789376],[-78.0565883,43.4396918],[-78.4389748,43.4396918],[-78.4389748,43.3794382],[-78.8803396,43.3794382],[-78.8803396,43.3149724],[-79.1298858,43.3149724],[-79.1298858,43.2429286],[-79.0669615,43.2429286],[-79.0669615,43.1299931],[-79.1298858,43.1299931],[-79.1298858,43.0577305],[-79.071264,43.0577305],[-79.071264,42.9294906],[-78.943264,42.9294906],[-78.943264,42.7542165],[-79.069439,42.7542165],[-79.069439,42.6941622],[-79.133439,42.6941622],[-79.133439,42.6296973],[-79.1947499,42.6296973],[-79.1947499,42.5663538],[-79.3786827,42.5663538],[-79.3786827,42.5033425],[-79.4442961,42.5033425],[-79.4442961,42.4410614],[-79.5679936,42.4410614],[-79.5679936,42.3775264],[-79.6906154,42.3775264],[-79.6906154,42.3171086],[-79.8164642,42.3171086],[-79.8164642,42.2534481],[-80.0052373,42.2534481],[-80.0052373,42.1909188],[-80.1916829,42.1909188],[-80.1916829,42.1272555],[-80.3167992,42.1272555],[-80.3167992,42.0669857],[-80.5063234,42.0669857],[-80.5063234,42.0034331],[-80.6930471,42.0034331],[-80.6930471,41.9415141],[-80.9440403,41.9415141],[-80.9440403,41.8781193],[-81.1942729,41.8781193],[-81.1942729,41.8166455],[-81.3190089,41.8166455],[-81.3190089,41.7545453],[-81.4418435,41.7545453],[-81.4418435,41.690965],[-81.5053523,41.690965],[-81.5053523,41.6301643],[-82.7470081,41.6301643],[-82.7470081,41.7536942],[-82.8839135,41.7536942],[-82.8839135,41.5656075],[-82.9957195,41.5656075],[-82.9957195,41.6270375],[-83.1257796,41.6270375],[-83.1257796,41.6878411],[-83.2474733,41.6878411],[-83.2474733,41.7536942],[-83.3737305,41.7536942],[-83.3737305,41.809276],[-83.3106019,41.809276],[-83.3106019,41.8716064],[-83.2474733,41.8716064],[-83.2474733,41.9361393],[-83.1843447,41.9361393],[-83.1843447,41.9960851],[-83.1207681,41.9960851],[-83.1207681,42.2464812],[-83.0589194,42.2464812],[-83.0589194,42.3089555],[-82.8685328,42.3089555],[-82.8685328,42.3717652],[-82.8072219,42.3717652],[-82.8072219,42.558553],[-82.7553745,42.558553],[-82.7553745,42.4954945],[-82.5599041,42.4954945],[-82.5599041,42.558553],[-82.4967755,42.558553],[-82.4967755,42.6833607],[-82.4328863,42.6833607],[-82.4328863,42.9342196],[-82.3700552,42.9342196],[-82.3700552,43.0648071],[-82.4328863,43.0648071],[-82.4328863,43.1917566],[-82.4947464,43.1917566],[-82.4947464,43.5034627],[-82.557133,43.5034627],[-82.557133,43.8160901],[-82.6197884,43.8160901],[-82.6197884,43.9422098],[-82.6839499,43.9422098],[-82.6839499,44.0022641],[-82.7465346,44.0022641],[-82.7465346,44.0670545],[-82.8708696,44.0670545],[-82.8708696,44.1291935],[-83.008517,44.1291935],[-83.008517,44.0664786],[-83.1336086,44.0664786],[-83.1336086,44.0053949],[-83.2414522,44.0053949],[-83.2414522,44.9962034],[-83.1806112,44.9962034],[-83.1806112,45.067302],[-83.2455172,45.067302],[-83.2455172,45.1287382],[-83.3065878,45.1287382],[-83.3065878,45.2551509],[-83.3706087,45.2551509],[-83.3706087,45.3165923],[-83.4325644,45.3165923],[-83.4325644,45.3792105],[-83.6178415,45.3792105],[-83.6178415,45.4419665],[-83.8084291,45.4419665],[-83.8084291,45.5036189],[-84.0550718,45.5036189],[-84.0550718,45.5647907],[-84.1235181,45.5647907],[-84.1235181,45.6287845],[-84.1807534,45.6287845],[-84.1807534,45.6914688],[-84.3111554,45.6914688],[-84.3111554,45.9337076],[-83.8209974,45.9337076],[-83.8209974,45.8725113],[-83.4968086,45.8725113],[-83.4968086,45.9337076],[-83.4338066,45.9337076],[-83.4338066,46.0016863],[-83.4962697,46.0016863],[-83.4962697,46.0668178],[-83.5599956,46.0668178],[-83.5599956,46.1261576],[-83.9954558,46.1261576],[-83.9954558,46.1931747],[-84.0591816,46.1931747],[-84.0591816,46.3814972],[-84.1152614,46.3814972],[-84.1152614,46.4953584],[-84.0591816,46.4953584],[-84.0591816,46.5682653],[-84.2579545,46.5682653],[-84.2579545,46.5051232],[-84.3071879,46.5051232],[-84.3071879,46.5682653],[-84.4415364,46.5682653],[-84.4415364,46.504525],[-84.9965729,46.504525],[-84.9965729,46.6842882],[-84.9298158,46.6842882],[-84.9298158,46.818077],[-85.3165894,46.818077],[-85.3165894,46.7535825],[-87.5562645,46.7535825],[-87.5562645,47.4407371],[-87.6825361,47.4407371],[-87.6825361,47.5035554],[-88.2560738,47.5035554],[-88.2560738,47.4433716],[-88.4417419,47.4433716],[-88.4417419,47.3789949],[-88.50683,47.3789949],[-88.50683,47.3153881],[-88.6312821,47.3153881],[-88.6312821,47.2539782],[-88.7569636,47.2539782],[-88.7569636,47.1934682],[-88.8838253,47.1934682],[-88.8838253,47.1284735],[-88.9434208,47.1284735],[-88.9434208,47.0662127],[-89.0708726,47.0662127],[-89.0708726,47.0026826],[-89.2565553,47.0026826],[-89.2565553,46.9410806],[-90.3677669,46.9410806],[-90.3677669,47.6844827],[-90.3069978,47.6844827],[-90.3069978,47.7460174],[-89.994859,47.7460174],[-89.994859,47.8082719],[-89.8048615,47.8082719],[-89.8048615,47.8700562],[-89.6797699,47.8700562],[-89.6797699,47.9339637],[-89.4933757,47.9339637],[-89.4933757,47.9957956],[-89.4284697,47.9957956],[-89.4284697,48.0656377],[-89.9932739,48.0656377],[-89.9932739,48.1282966],[-90.7455933,48.1282966],[-90.7455933,48.1893056],[-90.8087291,48.1893056],[-90.8087291,48.2522065],[-91.067763,48.2522065],[-91.067763,48.1916658],[-91.1946247,48.1916658],[-91.1946247,48.1279027],[-91.6814196,48.1279027],[-91.6814196,48.2525994],[-91.9321927,48.2525994],[-91.9321927,48.3142454],[-91.9929683,48.3142454],[-91.9929683,48.3780845],[-92.3189383,48.3780845],[-92.3189383,48.2529081],[-92.3732233,48.2529081],[-92.3732233,48.3153385],[-92.4322288,48.3153385],[-92.4322288,48.4411448],[-92.4977248,48.4411448],[-92.4977248,48.501781],[-92.5679413,48.501781],[-92.5679413,48.439579],[-92.6210462,48.439579],[-92.6210462,48.5650783],[-92.8086835,48.5650783],[-92.8086835,48.6286865],[-92.8086835,48.6267365],[-92.933185,48.6267365],[-92.933185,48.6922145],[-93.0051716,48.6922145],[-93.0051716,48.6282965],[-93.1225924,48.6282965],[-93.1225924,48.6922145],[-93.3190806,48.6922145],[-93.3190806,48.6267365],[-93.5049477,48.6267365],[-93.5049477,48.5635164],[-93.7474601,48.5635164],[-93.7474601,48.6267365],[-93.8135461,48.6267365],[-93.8135461,48.6898775],[-94.2453121,48.6898775],[-94.2453121,48.7554327],[-94.6183171,48.7554327],[-94.6183171,48.941036],[-94.6809018,48.941036],[-94.6809018,49.0029737],[-94.7441532,49.0029737],[-94.7441532,49.2536079],[-94.8084069,49.2536079],[-94.8084069,49.3784134],[-95.1192391,49.3784134],[-95.1192391,49.4425264],[-95.1934341,49.4425264],[-95.1934341,49.0035292],[-96.87069,49.0035292],[-96.87069,49.0656063],[-99.0049312,49.0656063],[-99.0049312,49.0050714],[-109.3699257,49.0050714],[-109.3699257,49.0668231],[-109.5058746,49.0668231],[-109.5058746,49.0050714],[-114.1830014,49.0050714],[-114.1830014,49.0687317],[-114.7578709,49.0687317],[-114.7578709,49.0050714],[-115.433731,49.0050714],[-115.433731,49.0671412],[-116.5062706,49.0671412],[-116.5062706,49.0050714],[-117.3089504,49.0050714],[-117.3089504,49.0659803],[-119.882945,49.0659803],[-119.882945,49.0050714],[-120.1208555,49.0050714],[-120.1208555,49.0678367],[-121.4451636,49.0678367],[-121.4451636,49.0050714],[-121.9311808,49.0050714],[-121.9311808,49.0656099],[-122.817484,49.0656099],[-122.817484,49.0029143],[-122.8795155,49.0029143],[-122.8795155,48.9347018],[-122.8174629,48.9347018],[-122.8174629,48.8101998],[-122.7538859,48.8101998],[-122.7538859,48.7533758],[-122.8712937,48.7533758],[-122.8712937,48.8153948],[-123.0055391,48.8153948],[-123.0055391,48.7529529],[-123.1296926,48.7529529],[-123.1296926,48.6902201],[-123.1838197,48.6902201],[-123.1838197,48.7529029],[-123.2549305,48.7529029]],[[-122.9341743,37.7521547],[-122.9347457,37.6842013],[-123.0679013,37.6849023],[-123.0673747,37.7475251],[-123.1292603,37.7478506],[-123.1286894,37.815685],[-123.0590687,37.8153192],[-123.0595947,37.7528143],[-122.9341743,37.7521547]],[[-71.6299464,41.2540893],[-71.4966465,41.2541393],[-71.4965596,41.122965],[-71.6298594,41.1229149],[-71.6299464,41.2540893]],[[-70.3184265,41.3775196],[-70.3183384,41.2448243],[-70.1906612,41.2448722],[-70.1906239,41.1886019],[-69.9336025,41.1886984],[-69.933729,41.3791941],[-69.9950664,41.3791712],[-69.995109,41.443159],[-70.0707828,41.4431307],[-70.0706972,41.3144915],[-70.2461667,41.3144258],[-70.2462087,41.3775467],[-70.3184265,41.3775196]],[[-68.9403374,43.9404062],[-68.6856948,43.9404977],[-68.6856475,43.8721797],[-68.7465405,43.8721577],[-68.7464976,43.8102529],[-68.8090782,43.8102304],[-68.8090343,43.746728],[-68.8773094,43.7467034],[-68.8773544,43.8117826],[-68.9402483,43.8117599],[-68.9403374,43.9404062]],[[-123.1291466,49.0645144],[-122.9954224,49.0645144],[-122.9954224,48.9343243],[-123.1291466,48.9343243],[-123.1291466,49.0645144]],[[-82.9407144,24.7535913],[-82.8719398,24.7535913],[-82.8719398,24.6905653],[-82.7446233,24.6905653],[-82.7446233,24.6214593],[-82.8088038,24.6214593],[-82.8088038,24.5594908],[-82.9407144,24.5594908],[-82.9407144,24.7535913]]]},{"id":"USGS-Scanned_Topographic","name":"USGS Topographic Maps","type":"tms","template":"http://caltopo.s3.amazonaws.com/topo/{zoom}/{x}/{y}.png","scaleExtent":[0,16],"polygon":[[[-55.9959409871,52.00107125754],[-112.02896100663,52.00107125754],[-112.03994733476,56.01308253302],[-120.0049439862,56.00592357111],[-120.01711631014,60.01202439709],[-132.00196823895,60.00239237126],[-132.01208445818,63.00193292546],[-133.96882922149,63.00050478005],[-133.97240257168,63.9922484722],[-141.04429430438,63.98726254018],[-141.06879354491,69.92045693283],[-156.24893170976,71.51583202984],[-160.44570905351,70.83527373985],[-167.08145124101,68.42906280103],[-164.08218366288,67.03913532024],[-169.01504499101,65.68268604273],[-166.57608014726,64.50777504773],[-161.82998639726,64.0500622981],[-165.08193952226,63.26030016403],[-168.02627545976,59.7862264253],[-162.53311139726,59.73089435789],[-162.35733014726,58.55904663221],[-157.83096295976,58.31752983705],[-158.00674420976,57.52404350658],[-168.22402936601,53.51022153947],[-166.55410749101,53.14277307072],[-158.77578717851,54.88541314654],[-158.68240338944,55.7496444805],[-156.55105573319,56.00847621073],[-156.15554792069,56.7746616888],[-154.70535260819,56.14336689443],[-152.07412702226,57.37034511851],[-151.62918073319,58.22653323066],[-152.00820905351,58.98055685754],[-145.98770124101,60.24740887373],[-140.38467389726,59.48634241018],[-136.53945905351,57.80610084736],[-133.79287702226,54.83482554482],[-133.33145124101,53.14277307072],[-131.46377545976,51.69838238021],[-128.52493268632,51.74602265442],[-129.79385358476,50.90159054062],[-124.56436139726,47.49785657441],[-124.03701764726,45.48627362525],[-124.69619733476,42.90428451679],[-124.49844342851,40.3414647251],[-122.80654889726,37.53929308709],[-119.99404889726,33.37084692374],[-117.24746686601,32.54119524801],[-111.13906842851,31.19770451575],[-106.70059186601,31.23528720858],[-103.20693952226,28.64618215851],[-101.84463483476,29.81580068657],[-99.20791608476,26.28743998885],[-96.79092389726,25.75431753335],[-96.92275983476,27.96911213371],[-93.47305280351,29.68226300815],[-88.94668561601,28.87732407469],[-88.61709577226,30.17736083469],[-86.20010358476,30.3671253082],[-84.96963483476,29.43379356715],[-84.09072858476,30.06332630046],[-82.97012311601,28.95425748047],[-82.97012311601,27.26823750278],[-81.25625592851,25.07956298739],[-82.09121686601,24.5610471236],[-80.06973249101,24.76073298597],[-79.85000592851,27.11188091684],[-81.27822858476,30.70777424386],[-78.99307233476,33.20554049136],[-75.03799420976,35.59830000028],[-75.85098249101,37.2425160052],[-73.74160749101,40.4585957587],[-69.89639264726,41.60224497127],[-70.68740827226,43.17628724449],[-66.93008405351,44.69516042167],[-66.53457624101,43.08006996122],[-64.20547467851,43.35229243812],[-59.50332624101,45.73220792131],[-59.51431256913,46.24761804024],[-60.00320417069,46.25901313529],[-59.99221784257,47.24505773341],[-59.00894147538,47.23759898478],[-58.99795514726,47.50266941922],[-56.51504499101,47.50266941922],[-56.52603131913,46.74770404019],[-53.99917585038,46.74770404019],[-53.97720319413,46.48358117386],[-52.49404889726,46.46354265729],[-52.50503522538,48.75360583388],[-52.99667340898,48.75451123442],[-53.01315290116,49.99551104004],[-55.00167829179,50.00610367548],[-55.03738385819,53.74720613495],[-56.00418073319,53.73421061801],[-55.9959409871,52.00107125754]],[[-59.50126630448,43.7495431608],[-60.50239545487,43.7495431608],[-60.50239545487,43.99999882251],[-59.99839765214,43.99999882251],[-59.99839765214,44.2494016836],[-59.50126630448,44.2494016836],[-59.50126630448,43.7495431608]],[[-155.95024091386,20.49523373356],[-157.3267518687,20.49153389084],[-157.32902509355,21.23181053727],[-155.95251413871,21.23549220541],[-155.95024091386,20.49523373356]],[[-157.64488202714,21.24845058596],[-158.28534362719,21.24673774522],[-158.28689557694,21.7499618541],[-157.6464339769,21.75166877943],[-157.64488202714,21.24845058596]],[[-156.12602216386,20.32469602374],[-154.7461696274,20.3284088686],[-154.74174482011,18.87578125335],[-156.12159735656,18.87203473488],[-156.12602216386,20.32469602374]],[[-159.29077130937,22.24504086823],[-159.2892966564,21.76857042389],[-160.28916841131,21.76590592196],[-160.29064306428,22.24238530626],[-159.29077130937,22.24504086823]]],"terms_url":"https://caltopo.com/","terms_text":"© Caltopo"},{"id":"sjcgis.org-General_Basemap_WM","name":"Vector Streetmap for San Juan County WA","type":"tms","template":"http://sjcgis.org/arcgis/rest/services/Basemaps/General_Basemap_WM/MapServer/tile/{zoom}/{y}/{x}","description":"Public domain street and address data from the San Juan County, WA. Updated at least quarterly.","scaleExtent":[0,19],"polygon":[[[-123.274024,48.692975],[-123.007726,48.767256],[-123.007619,48.831577],[-122.783495,48.758416],[-122.693402,48.658522],[-122.767451,48.603606],[-122.744842,48.387083],[-123.248221,48.283531],[-123.114524,48.422614],[-123.219035,48.548575],[-123.274024,48.692975]]],"best":true},{"id":"Vejmidte_Denmark","name":"Vejmidte (Denmark)","type":"tms","template":"http://{switch:a,b,c}.tile.openstreetmap.dk/danmark/vejmidte/{zoom}/{x}/{y}.png","scaleExtent":[0,20],"polygon":[[[8.3743941,54.9551655],[8.3683809,55.4042149],[8.2103997,55.4039795],[8.2087314,55.4937345],[8.0502655,55.4924731],[8.0185123,56.7501399],[8.1819161,56.7509948],[8.1763274,57.0208898],[8.3413329,57.0219872],[8.3392467,57.1119574],[8.5054433,57.1123212],[8.5033923,57.2020499],[9.3316304,57.2027636],[9.3319079,57.2924835],[9.4978864,57.2919578],[9.4988593,57.3820608],[9.6649749,57.3811615],[9.6687295,57.5605591],[9.8351961,57.5596265],[9.8374896,57.6493322],[10.1725726,57.6462818],[10.1754245,57.7367768],[10.5118282,57.7330269],[10.5152095,57.8228945],[10.6834853,57.8207722],[10.6751613,57.6412021],[10.5077045,57.6433097],[10.5039992,57.5535088],[10.671038,57.5514113],[10.6507805,57.1024538],[10.4857673,57.1045138],[10.4786236,56.9249051],[10.3143981,56.9267573],[10.3112341,56.8369269],[10.4750295,56.83509],[10.4649016,56.5656681],[10.9524239,56.5589761],[10.9479249,56.4692243],[11.1099335,56.4664675],[11.1052639,56.376833],[10.9429901,56.3795284],[10.9341235,56.1994768],[10.7719685,56.2020244],[10.7694751,56.1120103],[10.6079695,56.1150259],[10.4466742,56.116717],[10.2865948,56.118675],[10.2831527,56.0281851],[10.4439274,56.0270388],[10.4417713,55.7579243],[10.4334961,55.6693533],[10.743814,55.6646861],[10.743814,55.5712253],[10.8969041,55.5712253],[10.9051793,55.3953852],[11.0613726,55.3812841],[11.0593038,55.1124061],[11.0458567,55.0318621],[11.2030844,55.0247474],[11.2030844,55.117139],[11.0593038,55.1124061],[11.0613726,55.3812841],[11.0789572,55.5712253],[10.8969041,55.5712253],[10.9258671,55.6670198],[10.743814,55.6646861],[10.7562267,55.7579243],[10.4417713,55.7579243],[10.4439274,56.0270388],[10.4466742,56.116717],[10.6079695,56.1150259],[10.6052053,56.0247462],[10.9258671,56.0201215],[10.9197132,55.9309388],[11.0802782,55.92792],[11.0858066,56.0178284],[11.7265047,56.005058],[11.7319981,56.0952142],[12.0540333,56.0871256],[12.0608477,56.1762576],[12.7023469,56.1594405],[12.6611131,55.7114318],[12.9792318,55.7014026],[12.9612912,55.5217294],[12.3268659,55.5412096],[12.3206071,55.4513655],[12.4778226,55.447067],[12.4702432,55.3570479],[12.6269738,55.3523837],[12.6200898,55.2632576],[12.4627339,55.26722],[12.4552949,55.1778223],[12.2987046,55.1822303],[12.2897344,55.0923641],[12.6048608,55.0832904],[12.5872011,54.9036285],[12.2766618,54.9119031],[12.2610181,54.7331602],[12.1070691,54.7378161],[12.0858621,54.4681655],[11.7794953,54.4753579],[11.7837381,54.5654783],[11.1658525,54.5782155],[11.1706443,54.6686508],[10.8617173,54.6733956],[10.8651245,54.7634667],[10.7713646,54.7643888],[10.7707276,54.7372807],[10.7551428,54.7375776],[10.7544039,54.7195666],[10.7389074,54.7197588],[10.7384368,54.7108482],[10.7074486,54.7113045],[10.7041094,54.6756741],[10.5510973,54.6781698],[10.5547184,54.7670245],[10.2423994,54.7705935],[10.2459845,54.8604673],[10.0902268,54.8622134],[10.0873731,54.7723851],[9.1555798,54.7769557],[9.1562752,54.8675369],[8.5321973,54.8663765],[8.531432,54.95516],[8.3743941,54.9551655]],[[11.4577738,56.819554],[11.7849181,56.8127385],[11.7716715,56.6332796],[11.4459621,56.6401087],[11.4577738,56.819554]],[[11.3274736,57.3612962],[11.3161808,57.1818004],[11.1508692,57.1847276],[11.1456628,57.094962],[10.8157703,57.1001693],[10.8290599,57.3695272],[11.3274736,57.3612962]],[[11.5843266,56.2777928],[11.5782882,56.1880397],[11.7392309,56.1845765],[11.7456428,56.2743186],[11.5843266,56.2777928]],[[14.6825922,55.3639405],[14.8395247,55.3565231],[14.8263755,55.2671261],[15.1393406,55.2517359],[15.1532015,55.3410836],[15.309925,55.3330556],[15.295719,55.2437356],[15.1393406,55.2517359],[15.1255631,55.1623802],[15.2815819,55.1544167],[15.2535578,54.9757646],[14.6317464,55.0062496],[14.6825922,55.3639405]]],"terms_url":"http://wiki.openstreetmap.org/wiki/Vejmidte","terms_text":"Danish municipalities"},{"id":"wien.gv.at-labels","name":"Vienna: Beschriftungen (annotations)","type":"tms","template":"https://maps.wien.gv.at/wmts/beschriftung/normal/google3857/{zoom}/{y}/{x}.png","scaleExtent":[12,19],"polygon":[[[16.17,48.1],[16.17,48.33],[16.58,48.33],[16.58,48.1],[16.17,48.1]]],"terms_url":"https://data.wien.gv.at/","terms_text":"Stadt Wien"},{"id":"wien.gv.at-gp","name":"Vienna: Mehrzweckkarte (general purpose)","type":"tms","template":"https://maps.wien.gv.at/wmts/fmzk/pastell/google3857/{zoom}/{y}/{x}.jpeg","scaleExtent":[10,19],"polygon":[[[16.17,48.1],[16.17,48.33],[16.58,48.33],[16.58,48.1],[16.17,48.1]]],"terms_url":"https://data.wien.gv.at/","terms_text":"Stadt Wien"},{"id":"wien.gv.at-aerial_image","name":"Vienna: Orthofoto (aerial image)","type":"tms","template":"https://maps.wien.gv.at/wmts/lb/farbe/google3857/{zoom}/{y}/{x}.jpeg","scaleExtent":[10,19],"polygon":[[[16.17,48.1],[16.17,48.33],[16.58,48.33],[16.58,48.1],[16.17,48.1]]],"terms_url":"https://data.wien.gv.at/","terms_text":"Stadt Wien"}];
18626
18627 var presets = {"aerialway":{"fields":["aerialway"],"geometry":["point","vertex","line"],"tags":{"aerialway":"*"},"terms":["ski lift","funifor","funitel"],"searchable":false,"name":"Aerialway"},"aeroway":{"icon":"airport","fields":["aeroway"],"geometry":["point","vertex","line","area"],"tags":{"aeroway":"*"},"searchable":false,"name":"Aeroway"},"amenity":{"fields":["amenity"],"geometry":["point","vertex","area"],"tags":{"amenity":"*"},"searchable":false,"name":"Amenity"},"highway":{"fields":["highway"],"geometry":["point","vertex","line","area"],"tags":{"highway":"*"},"searchable":false,"name":"Highway"},"place":{"fields":["place"],"geometry":["point","vertex","area"],"tags":{"place":"*"},"searchable":false,"name":"Place"},"power":{"geometry":["point","vertex","line","area"],"tags":{"power":"*"},"fields":["power"],"searchable":false,"name":"Power"},"railway":{"fields":["railway"],"geometry":["point","vertex","line","area"],"tags":{"railway":"*"},"searchable":false,"name":"Railway"},"roundabout":{"geometry":["vertex","line"],"tags":{"junction":"roundabout"},"name":"Roundabout","searchable":false},"waterway":{"fields":["waterway"],"geometry":["point","vertex","line","area"],"tags":{"waterway":"*"},"searchable":false,"name":"Waterway"},"address":{"fields":["address"],"geometry":["point"],"tags":{"addr:housenumber":"*"},"addTags":{},"removeTags":{},"matchScore":0.2,"name":"Address"},"advertising/billboard":{"fields":["parallel_direction","lit"],"geometry":["point","vertex","line"],"tags":{"advertising":"billboard"},"name":"Billboard"},"aerialway/cable_car":{"geometry":["line"],"terms":["tramway","ropeway"],"fields":["aerialway/occupancy","aerialway/capacity","aerialway/duration","aerialway/heating"],"tags":{"aerialway":"cable_car"},"name":"Cable Car"},"aerialway/chair_lift":{"geometry":["line"],"fields":["aerialway/occupancy","aerialway/capacity","aerialway/duration","aerialway/bubble","aerialway/heating"],"tags":{"aerialway":"chair_lift"},"name":"Chair Lift"},"aerialway/drag_lift":{"geometry":["line"],"fields":["aerialway/capacity","aerialway/duration"],"tags":{"aerialway":"drag_lift"},"name":"Drag Lift"},"aerialway/gondola":{"geometry":["line"],"fields":["aerialway/occupancy","aerialway/capacity","aerialway/duration","aerialway/bubble","aerialway/heating"],"tags":{"aerialway":"gondola"},"name":"Gondola"},"aerialway/goods":{"geometry":["line"],"fields":["aerialway/capacity","aerialway/duration"],"tags":{"aerialway":"goods"},"name":"Goods Aerialway"},"aerialway/magic_carpet":{"geometry":["line"],"fields":["aerialway/capacity","aerialway/duration","aerialway/heating"],"tags":{"aerialway":"magic_carpet"},"name":"Magic Carpet Lift"},"aerialway/mixed_lift":{"geometry":["line"],"fields":["aerialway/occupancy","aerialway/capacity","aerialway/duration","aerialway/bubble","aerialway/heating"],"tags":{"aerialway":"mixed_lift"},"name":"Mixed Lift"},"aerialway/platter":{"geometry":["line"],"terms":["button lift","poma lift"],"fields":["aerialway/capacity","aerialway/duration"],"tags":{"aerialway":"platter"},"name":"Platter Lift"},"aerialway/pylon":{"geometry":["point","vertex"],"fields":["ref"],"tags":{"aerialway":"pylon"},"name":"Aerialway Pylon"},"aerialway/rope_tow":{"geometry":["line"],"terms":["handle tow","bugel lift"],"fields":["aerialway/capacity","aerialway/duration"],"tags":{"aerialway":"rope_tow"},"name":"Rope Tow Lift"},"aerialway/station":{"icon":"aerialway","geometry":["point","vertex"],"fields":["aerialway/access","aerialway/summer/access","elevation"],"tags":{"aerialway":"station"},"name":"Aerialway Station"},"aerialway/t-bar":{"geometry":["line"],"fields":["aerialway/capacity","aerialway/duration"],"tags":{"aerialway":"t-bar"},"name":"T-bar Lift"},"aeroway/aerodrome":{"icon":"airport","geometry":["point","area"],"fields":["ref","iata","icao","operator","internet_access","internet_access/fee","internet_access/ssid"],"terms":["airplane","airport","aerodrome"],"tags":{"aeroway":"aerodrome"},"name":"Airport"},"aeroway/apron":{"icon":"airport","geometry":["area"],"terms":["ramp"],"fields":["ref","surface"],"tags":{"aeroway":"apron"},"name":"Apron"},"aeroway/gate":{"icon":"airport","geometry":["point"],"fields":["ref"],"tags":{"aeroway":"gate"},"name":"Airport Gate"},"aeroway/hangar":{"geometry":["area"],"fields":["building_area"],"tags":{"aeroway":"hangar"},"name":"Hangar"},"aeroway/helipad":{"icon":"heliport","geometry":["point","area"],"fields":["ref"],"terms":["helicopter","helipad","heliport"],"tags":{"aeroway":"helipad"},"name":"Helipad"},"aeroway/runway":{"geometry":["line","area"],"terms":["landing strip"],"fields":["ref","surface","length","width"],"tags":{"aeroway":"runway"},"name":"Runway"},"aeroway/taxiway":{"geometry":["line"],"fields":["ref","surface"],"tags":{"aeroway":"taxiway"},"name":"Taxiway"},"aeroway/terminal":{"icon":"airport","geometry":["point","area"],"terms":["airport","aerodrome"],"fields":["operator","building_area"],"tags":{"aeroway":"terminal"},"name":"Airport Terminal"},"amenity/coworking_space":{"icon":"commercial","fields":["address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"amenity":"coworking_space"},"name":"Coworking Space","searchable":false},"amenity/nursing_home":{"icon":"wheelchair","fields":["operator","address","building_area","social_facility","social_facility_for","opening_hours","wheelchair"],"geometry":["point","area"],"tags":{"amenity":"nursing_home"},"reference":{"key":"social_facility","value":"nursing_home"},"name":"Nursing Home","searchable":false},"amenity/register_office":{"icon":"town-hall","fields":["address","building_area","opening_hours","operator"],"geometry":["point","area"],"tags":{"amenity":"register_office"},"reference":{"key":"government","value":"register_office"},"name":"Register Office","searchable":false},"amenity/swimming_pool":{"icon":"swimming","geometry":["point","vertex","area"],"tags":{"amenity":"swimming_pool"},"reference":{"key":"leisure","value":"swimming_pool"},"name":"Swimming Pool","searchable":false},"amenity/animal_boarding":{"icon":"veterinary","fields":["operator","address","building_area","opening_hours","animal_boarding"],"geometry":["point","area"],"terms":["boarding","cat","dog","horse","kitten","pet boarding","pet care","pet hotel","puppy","reptile"],"tags":{"amenity":"animal_boarding"},"name":"Animal Boarding Facility"},"amenity/animal_breeding":{"icon":"veterinary","fields":["operator","address","building_area","opening_hours","animal_breeding"],"geometry":["point","area"],"terms":["breeding","bull","cat","cow","dog","horse","husbandry","kitten","livestock","pet breeding","puppy","reptile"],"tags":{"amenity":"animal_breeding"},"name":"Animal Breeding Facility"},"amenity/animal_shelter":{"icon":"veterinary","fields":["operator","address","building_area","opening_hours","animal_shelter"],"geometry":["point","area"],"terms":["adoption","aspca","cat","dog","horse","kitten","pet care","pet rescue","puppy","raptor","reptile","rescue","spca"],"tags":{"amenity":"animal_shelter"},"name":"Animal Shelter"},"amenity/arts_centre":{"icon":"theatre","fields":["address","building_area","opening_hours"],"geometry":["point","area"],"terms":[],"tags":{"amenity":"arts_centre"},"name":"Arts Center"},"amenity/atm":{"icon":"bank","fields":["operator","currency_multi","drive_through"],"geometry":["point","vertex"],"terms":["money","cash","machine"],"tags":{"amenity":"atm"},"name":"ATM"},"amenity/bank":{"icon":"bank","fields":["atm","operator","address","building_area","opening_hours","drive_through"],"geometry":["point","area"],"terms":["credit union","check","deposit","fund","investment","repository","reserve","safe","savings","stock","treasury","trust","vault"],"tags":{"amenity":"bank"},"name":"Bank"},"amenity/bar":{"icon":"bar","fields":["operator","address","building_area","opening_hours","smoking","outdoor_seating"],"geometry":["point","area"],"terms":["dive","beer","bier","booze"],"tags":{"amenity":"bar"},"name":"Bar"},"amenity/bbq":{"icon":"bbq","fields":["covered","fuel"],"geometry":["point"],"terms":["bbq","grill"],"tags":{"amenity":"bbq"},"name":"Barbecue/Grill"},"amenity/bench":{"icon":"poi-bench","fields":["backrest"],"geometry":["point","vertex","line"],"terms":["seat"],"tags":{"amenity":"bench"},"name":"Bench"},"amenity/bicycle_parking":{"icon":"bicycle","fields":["bicycle_parking","capacity","operator","covered","access_simple"],"geometry":["point","vertex","area"],"terms":["bike"],"tags":{"amenity":"bicycle_parking"},"name":"Bicycle Parking"},"amenity/bicycle_rental":{"icon":"bicycle","fields":["capacity","network","operator"],"geometry":["point","vertex","area"],"terms":["bike"],"tags":{"amenity":"bicycle_rental"},"name":"Bicycle Rental"},"amenity/bicycle_repair_station":{"icon":"bicycle","fields":["operator","brand","opening_hours","fee","service/bicycle"],"geometry":["point","vertex","area"],"terms":["bike","repair","chain","pump"],"tags":{"amenity":"bicycle_repair_station"},"name":"Bicycle Repair Tool Stand"},"amenity/biergarten":{"icon":"beer","fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"geometry":["point","area"],"tags":{"amenity":"biergarten"},"terms":["beer","bier","booze"],"name":"Beer Garden"},"amenity/boat_rental":{"fields":["operator"],"geometry":["point","area"],"tags":{"amenity":"boat_rental"},"name":"Boat Rental"},"amenity/bureau_de_change":{"icon":"bank","fields":["operator","currency_multi"],"geometry":["point","vertex"],"terms":["bureau de change","money changer"],"tags":{"amenity":"bureau_de_change"},"name":"Currency Exchange"},"amenity/bus_station":{"icon":"bus","fields":["building_area","operator","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"amenity":"bus_station"},"name":"Bus Station"},"amenity/cafe":{"icon":"cafe","fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"geometry":["point","area"],"terms":["bistro","coffee","tea"],"tags":{"amenity":"cafe"},"name":"Cafe"},"amenity/car_rental":{"icon":"car","fields":["operator"],"geometry":["point","area"],"tags":{"amenity":"car_rental"},"name":"Car Rental"},"amenity/car_sharing":{"icon":"car","fields":["operator","capacity"],"geometry":["point","area"],"tags":{"amenity":"car_sharing"},"name":"Car Sharing"},"amenity/car_wash":{"icon":"car","fields":["address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"amenity":"car_wash"},"name":"Car Wash"},"amenity/casino":{"icon":"poi-dice","fields":["operator","address","building_area","opening_hours","smoking"],"geometry":["point","area"],"terms":["gambling","roulette","craps","poker","blackjack"],"tags":{"amenity":"casino"},"name":"Casino"},"amenity/charging_station":{"icon":"car","fields":["operator","capacity"],"geometry":["point","area"],"tags":{"amenity":"charging_station"},"terms":["EV","Electric Vehicle","Supercharger"],"name":"Charging Station"},"amenity/childcare":{"icon":"school","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["daycare","orphanage","playgroup"],"tags":{"amenity":"childcare"},"name":"Nursery/Childcare"},"amenity/cinema":{"icon":"cinema","fields":["address","building_area","opening_hours"],"geometry":["point","area"],"terms":["drive-in","film","flick","movie","theater","picture","show","screen"],"tags":{"amenity":"cinema"},"name":"Cinema"},"amenity/clinic":{"icon":"hospital","fields":["address","building_area","opening_hours"],"geometry":["point","area"],"terms":["medical","urgentcare"],"tags":{"amenity":"clinic"},"name":"Clinic"},"amenity/clock":{"icon":"poi-clock","fields":["support","display","visibility","date"],"geometry":["point","vertex"],"tags":{"amenity":"clock"},"name":"Clock"},"amenity/college":{"icon":"college","fields":["operator","address","internet_access","internet_access/ssid"],"geometry":["point","area"],"terms":["university"],"tags":{"amenity":"college"},"name":"College Grounds"},"amenity/community_centre":{"icon":"town-hall","fields":["operator","address","building_area"],"geometry":["point","area"],"terms":["event","hall"],"tags":{"amenity":"community_centre"},"name":"Community Center"},"amenity/compressed_air":{"icon":"car","geometry":["point","area"],"tags":{"amenity":"compressed_air"},"name":"Compressed Air"},"amenity/courthouse":{"icon":"town-hall","fields":["operator","address","building_area"],"geometry":["point","area"],"tags":{"amenity":"courthouse"},"name":"Courthouse"},"amenity/crematorium":{"icon":"cemetery","fields":["website","phone","opening_hours","wheelchair"],"geometry":["area","point"],"tags":{"amenity":"crematorium"},"terms":["cemetery","funeral"],"name":"Crematorium"},"amenity/dentist":{"icon":"dentist","fields":["address","building_area","opening_hours"],"geometry":["point","area"],"terms":["tooth","teeth"],"tags":{"amenity":"dentist"},"name":"Dentist"},"amenity/doctors":{"icon":"hospital","fields":["address","building_area","opening_hours"],"geometry":["point","area"],"terms":["medic*"],"tags":{"amenity":"doctors"},"name":"Doctor"},"amenity/dojo":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["martial arts","dojang"],"tags":{"amenity":"dojo"},"name":"Dojo / Martial Arts Academy"},"amenity/drinking_water":{"icon":"drinking-water","geometry":["point"],"tags":{"amenity":"drinking_water"},"terms":["fountain","potable"],"name":"Drinking Water"},"amenity/driving_school":{"icon":"car","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"amenity":"driving_school"},"name":"Driving School"},"amenity/embassy":{"icon":"embassy","fields":["country","address","building_area"],"geometry":["point","area"],"tags":{"amenity":"embassy"},"name":"Embassy"},"amenity/fast_food":{"icon":"fast-food","fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"geometry":["point","area"],"tags":{"amenity":"fast_food"},"terms":["restaurant","takeaway"],"name":"Fast Food"},"amenity/ferry_terminal":{"icon":"ferry","fields":["network","operator","address","building_area"],"geometry":["point","vertex","area"],"terms":[],"tags":{"amenity":"ferry_terminal"},"name":"Ferry Terminal"},"amenity/fire_station":{"icon":"fire-station","fields":["operator","address","building_area"],"geometry":["point","area"],"terms":[],"tags":{"amenity":"fire_station"},"name":"Fire Station"},"amenity/food_court":{"icon":"restaurant","fields":["operator","address","building_area","opening_hours","smoking","outdoor_seating"],"geometry":["point","area"],"terms":["fast food","restaurant","food"],"tags":{"amenity":"food_court"},"name":"Food Court"},"amenity/fountain":{"icon":"poi-fountain","geometry":["point","area"],"tags":{"amenity":"fountain"},"name":"Fountain"},"amenity/fuel":{"icon":"fuel","fields":["operator","address","opening_hours","fuel_multi"],"geometry":["point","area"],"terms":["petrol","fuel","gasoline","propane","diesel","lng","cng","biodiesel"],"tags":{"amenity":"fuel"},"name":"Gas Station"},"amenity/grave_yard":{"icon":"cemetery","fields":["religion","denomination"],"geometry":["point","area"],"tags":{"amenity":"grave_yard"},"name":"Graveyard"},"amenity/grit_bin":{"fields":["access_simple"],"geometry":["point","vertex"],"tags":{"amenity":"grit_bin"},"terms":["salt","sand"],"name":"Grit Bin"},"amenity/hospital":{"icon":"hospital","fields":["operator","address","emergency"],"geometry":["point","area"],"terms":["clinic","doctor","emergency room","health","infirmary","institution","sanatorium","sanitarium","sick","surgery","ward"],"tags":{"amenity":"hospital"},"name":"Hospital Grounds"},"amenity/hunting_stand":{"icon":"poi-binoculars","geometry":["point","vertex","area"],"terms":["game","gun","lookout","rifle","shoot*","wild","watch"],"tags":{"amenity":"hunting_stand"},"name":"Hunting Stand"},"amenity/ice_cream":{"icon":"ice-cream","fields":["address","building_area","opening_hours","takeaway","delivery","outdoor_seating"],"geometry":["point","area"],"terms":["gelato","sorbet","sherbet","frozen","yogurt"],"tags":{"amenity":"ice_cream"},"name":"Ice Cream Shop"},"amenity/internet_cafe":{"icon":"poi-mast","fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"geometry":["point","area"],"terms":["cybercafe","taxiphone","teleboutique","coffee","cafe","net","lanhouse"],"tags":{"amenity":"internet_cafe"},"name":"Internet Cafe"},"amenity/kindergarten":{"icon":"school","fields":["operator","address"],"geometry":["point","area"],"terms":["kindergarden","pre-school"],"tags":{"amenity":"kindergarten"},"name":"Preschool/Kindergarten Grounds"},"amenity/library":{"icon":"library","fields":["operator","building_area","address","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"terms":["book"],"tags":{"amenity":"library"},"name":"Library"},"amenity/marketplace":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"amenity":"marketplace"},"name":"Marketplace"},"amenity/motorcycle_parking":{"icon":"scooter","fields":["capacity","operator","covered","access_simple"],"geometry":["point","vertex","area"],"tags":{"amenity":"motorcycle_parking"},"name":"Motorcycle Parking"},"amenity/nightclub":{"icon":"bar","fields":["operator","address","building_area","opening_hours","smoking"],"geometry":["point","area"],"tags":{"amenity":"nightclub"},"terms":["disco*","night club","dancing","dance club"],"name":"Nightclub"},"amenity/parking_entrance":{"icon":"entrance-alt1","fields":["access_simple","ref"],"geometry":["vertex"],"tags":{"amenity":"parking_entrance"},"name":"Parking Garage Entrance/Exit"},"amenity/parking_space":{"fields":["capacity"],"geometry":["point","vertex","area"],"terms":[],"tags":{"amenity":"parking_space"},"matchScore":0.95,"name":"Parking Space"},"amenity/parking":{"icon":"parking","fields":["operator","parking","capacity","fee","access_simple","supervised","park_ride","surface","maxstay","address"],"geometry":["point","vertex","area"],"tags":{"amenity":"parking"},"terms":[],"name":"Car Parking"},"amenity/pavilion":{"icon":"shelter","fields":["bin","bench"],"geometry":["point","vertex","area"],"tags":{"amenity":"shelter","shelter_type":"pavilion"},"name":"Pavilion"},"amenity/pharmacy":{"icon":"pharmacy","fields":["operator","address","building_area","opening_hours","drive_through"],"geometry":["point","area"],"tags":{"amenity":"pharmacy"},"terms":["drug*","med*","prescription"],"name":"Pharmacy"},"amenity/place_of_worship":{"icon":"place-of-worship","fields":["religion","denomination","address","building_area","service_times"],"geometry":["point","area"],"terms":["abbey","basilica","bethel","cathedral","chancel","chantry","chapel","church","fold","house of God","house of prayer","house of worship","minster","mission","mosque","oratory","parish","sacellum","sanctuary","shrine","synagogue","tabernacle","temple"],"tags":{"amenity":"place_of_worship"},"name":"Place of Worship"},"amenity/place_of_worship/buddhist":{"icon":"buddhism","fields":["denomination","building_area","address","service_times"],"geometry":["point","area"],"terms":["stupa","vihara","monastery","temple","pagoda","zendo","dojo"],"tags":{"amenity":"place_of_worship","religion":"buddhist"},"reference":{"key":"amenity","value":"place_of_worship"},"name":"Buddhist Temple"},"amenity/place_of_worship/christian":{"icon":"religious-christian","fields":["denomination","building_area","address","service_times"],"geometry":["point","area"],"terms":["christian","abbey","basilica","bethel","cathedral","chancel","chantry","chapel","fold","house of God","house of prayer","house of worship","minster","mission","oratory","parish","sacellum","sanctuary","shrine","tabernacle","temple"],"tags":{"amenity":"place_of_worship","religion":"christian"},"reference":{"key":"amenity","value":"place_of_worship"},"name":"Church"},"amenity/place_of_worship/jewish":{"icon":"religious-jewish","fields":["denomination","building_area","address","service_times"],"geometry":["point","area"],"terms":["jewish"],"tags":{"amenity":"place_of_worship","religion":"jewish"},"reference":{"key":"amenity","value":"place_of_worship"},"name":"Synagogue"},"amenity/place_of_worship/muslim":{"icon":"religious-muslim","fields":["denomination","building_area","address","service_times"],"geometry":["point","area"],"terms":["muslim"],"tags":{"amenity":"place_of_worship","religion":"muslim"},"reference":{"key":"amenity","value":"place_of_worship"},"name":"Mosque"},"amenity/planetarium":{"icon":"museum","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["museum","astronomy","observatory"],"tags":{"amenity":"planetarium"},"name":"Planetarium"},"amenity/police":{"icon":"police","fields":["operator","address","building_area"],"geometry":["point","area"],"terms":["badge","constable","constabulary","cop","detective","fed","law","enforcement","officer","patrol"],"tags":{"amenity":"police"},"name":"Police"},"amenity/post_box":{"icon":"post","fields":["operator","collection_times","drive_through","ref"],"geometry":["point","vertex"],"tags":{"amenity":"post_box"},"terms":["letter","post"],"name":"Mailbox"},"amenity/post_office":{"icon":"post","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["letter","mail"],"tags":{"amenity":"post_office"},"name":"Post Office"},"amenity/prison":{"icon":"prison","fields":["operator","address"],"geometry":["point","area"],"terms":["cell","jail"],"tags":{"amenity":"prison"},"name":"Prison Grounds"},"amenity/pub":{"icon":"beer","fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"geometry":["point","area"],"tags":{"amenity":"pub"},"terms":["alcohol","drink","dive","beer","bier","booze"],"name":"Pub"},"amenity/public_bath":{"icon":"water","fields":["bath/type","bath/open_air","bath/sand_bath","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"amenity":"public_bath"},"terms":["onsen","foot bath","hot springs"],"name":"Public Bath"},"amenity/public_bookcase":{"icon":"library","fields":["name","operator","capacity","website"],"geometry":["point","area"],"terms":["library","bookcrossing"],"tags":{"amenity":"public_bookcase"},"name":"Public Bookcase"},"amenity/ranger_station":{"fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["visitor center","visitor centre","permit center","permit centre","backcountry office","warden office","warden center"],"tags":{"amenity":"ranger_station"},"name":"Ranger Station"},"amenity/recycling_centre":{"icon":"waste-basket","fields":["operator","address","opening_hours","recycling_accepts"],"geometry":["point","area"],"terms":["bottle","can","dump","glass","garbage","rubbish","scrap","trash"],"tags":{"amenity":"recycling","recycling_type":"centre"},"name":"Recycling Center"},"amenity/recycling":{"icon":"recycling","fields":["recycling_type","recycling_accepts","collection_times"],"geometry":["point","area"],"terms":["bin","can","bottle","glass","garbage","rubbish","scrap","trash"],"tags":{"amenity":"recycling"},"name":"Recycling"},"amenity/restaurant":{"icon":"restaurant","fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"geometry":["point","area"],"terms":["bar","breakfast","cafe","café","canteen","coffee","dine","dining","dinner","drive-in","eat","grill","lunch","table"],"tags":{"amenity":"restaurant"},"name":"Restaurant"},"amenity/sanitary_dump_station":{"icon":"poi-storage-tank","fields":["operator","access_toilets","fee","water_point"],"geometry":["point","vertex","area"],"terms":["Motor Home","Camper","Sanitary","Dump Station","Elsan","CDP","CTDP","Chemical Toilet"],"tags":{"amenity":"sanitary_dump_station"},"name":"RV Toilet Disposal"},"amenity/school":{"icon":"school","fields":["operator","address"],"geometry":["point","area"],"terms":["academy","elementary school","middle school","high school"],"tags":{"amenity":"school"},"name":"School Grounds"},"amenity/shelter":{"icon":"shelter","fields":["shelter_type","bin"],"geometry":["point","vertex","area"],"terms":["lean-to","gazebo","picnic"],"tags":{"amenity":"shelter"},"name":"Shelter"},"amenity/social_facility":{"icon":"poi-social-facility","fields":["operator","address","building_area","social_facility","social_facility_for","opening_hours","wheelchair"],"geometry":["point","area"],"terms":[],"tags":{"amenity":"social_facility"},"name":"Social Facility"},"amenity/social_facility/food_bank":{"icon":"poi-social-facility","fields":["operator","address","building_area","social_facility","social_facility_for","opening_hours"],"geometry":["point","area"],"terms":[],"tags":{"amenity":"social_facility","social_facility":"food_bank"},"reference":{"key":"social_facility","value":"food_bank"},"name":"Food Bank"},"amenity/social_facility/group_home":{"icon":"wheelchair","fields":["operator","address","building_area","social_facility","social_facility_for","opening_hours","wheelchair"],"geometry":["point","area"],"terms":["old","senior","living"],"tags":{"amenity":"social_facility","social_facility":"group_home","social_facility:for":"senior"},"reference":{"key":"social_facility","value":"group_home"},"name":"Elderly Group Home"},"amenity/social_facility/homeless_shelter":{"icon":"poi-social-facility","fields":["operator","address","building_area","social_facility","social_facility_for","opening_hours","wheelchair","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"terms":["houseless","unhoused","displaced"],"tags":{"amenity":"social_facility","social_facility":"shelter","social_facility:for":"homeless"},"reference":{"key":"social_facility","value":"shelter"},"name":"Homeless Shelter"},"amenity/social_facility/nursing_home":{"icon":"wheelchair","fields":["operator","address","building_area","social_facility","social_facility_for","opening_hours","wheelchair"],"geometry":["point","area"],"terms":["elderly","living","nursing","old","senior"],"tags":{"amenity":"social_facility","social_facility":"nursing_home","social_facility:for":"senior"},"reference":{"key":"social_facility","value":"nursing_home"},"name":"Nursing Home"},"amenity/studio":{"icon":"karaoke","fields":["studio","address","building_area"],"geometry":["point","area"],"terms":["recording","radio","television"],"tags":{"amenity":"studio"},"name":"Studio"},"amenity/taxi":{"icon":"car","fields":["operator","capacity"],"geometry":["point","vertex","area"],"terms":["cab"],"tags":{"amenity":"taxi"},"name":"Taxi Stand"},"amenity/telephone":{"icon":"telephone","geometry":["point","vertex"],"tags":{"amenity":"telephone"},"terms":["phone"],"name":"Telephone"},"amenity/theatre":{"icon":"theatre","fields":["operator","address","building_area"],"geometry":["point","area"],"terms":["theatre","performance","play","musical"],"tags":{"amenity":"theatre"},"name":"Theater"},"amenity/toilets":{"icon":"toilet","fields":["toilets/disposal","operator","building_area","access_toilets","gender","fee","diaper"],"geometry":["point","vertex","area"],"terms":["bathroom","restroom","outhouse","privy","head","lavatory","latrine","water closet","WC","W.C."],"tags":{"amenity":"toilets"},"name":"Toilets"},"amenity/townhall":{"icon":"town-hall","fields":["operator","address","building_area"],"geometry":["point","area"],"terms":["village","city","government","courthouse","municipal"],"tags":{"amenity":"townhall"},"name":"Town Hall"},"amenity/university":{"icon":"college","fields":["operator","address","internet_access","internet_access/ssid"],"geometry":["point","area"],"terms":["college"],"tags":{"amenity":"university"},"name":"University Grounds"},"amenity/vending_machine":{"icon":"poi-vending-machine","fields":["vending","operator","payment_multi","currency_multi"],"geometry":["point"],"terms":[],"tags":{"amenity":"vending_machine"},"name":"Vending Machine"},"amenity/vending_machine/news_papers":{"icon":"poi-vending-machine","fields":["operator","fee","payment_multi","currency_multi"],"geometry":["point"],"terms":["newspaper"],"tags":{"amenity":"vending_machine","vending":"news_papers"},"reference":{"key":"vending","value":"newspapers"},"name":"Newspaper Vending Machine","searchable":false},"amenity/vending_machine/cigarettes":{"icon":"poi-vending-machine","fields":["operator","payment_multi","currency_multi"],"geometry":["point"],"terms":["cigarette"],"tags":{"amenity":"vending_machine","vending":"cigarettes"},"reference":{"key":"vending","value":"cigarettes"},"name":"Cigarette Vending Machine"},"amenity/vending_machine/condoms":{"icon":"poi-vending-machine","fields":["operator","payment_multi","currency_multi"],"geometry":["point"],"terms":["condom"],"tags":{"amenity":"vending_machine","vending":"condoms"},"reference":{"key":"vending","value":"condoms"},"name":"Condom Vending Machine"},"amenity/vending_machine/drinks":{"icon":"poi-vending-machine","fields":["operator","payment_multi","currency_multi"],"geometry":["point"],"terms":["drink","soda","beverage","juice","pop"],"tags":{"amenity":"vending_machine","vending":"drinks"},"reference":{"key":"vending","value":"drinks"},"name":"Drink Vending Machine"},"amenity/vending_machine/excrement_bags":{"icon":"poi-vending-machine","fields":["operator","fee","bin","payment_multi","currency_multi"],"geometry":["point"],"terms":["excrement bags","poop","dog","animal"],"tags":{"amenity":"vending_machine","vending":"excrement_bags"},"reference":{"key":"vending","value":"excrement_bags"},"name":"Excrement Bag Vending Machine"},"amenity/vending_machine/newspapers":{"icon":"poi-vending-machine","fields":["operator","fee","payment_multi","currency_multi"],"geometry":["point"],"terms":["newspaper"],"tags":{"amenity":"vending_machine","vending":"newspapers"},"reference":{"key":"vending","value":"newspapers"},"name":"Newspaper Vending Machine"},"amenity/vending_machine/parcel_pickup_dropoff":{"icon":"poi-vending-machine","fields":["operator","payment_multi","currency_multi"],"geometry":["point"],"terms":["parcel","mail","pickup"],"tags":{"amenity":"vending_machine","vending":"parcel_pickup;parcel_mail_in"},"reference":{"key":"vending","value":"parcel_pickup;parcel_mail_in"},"name":"Parcel Pickup/Dropoff Vending Machine"},"amenity/vending_machine/parking_tickets":{"icon":"poi-vending-machine","fields":["operator","payment_multi","currency_multi"],"geometry":["point"],"terms":["parking","ticket"],"tags":{"amenity":"vending_machine","vending":"parking_tickets"},"reference":{"key":"vending","value":"parking_tickets"},"matchScore":0.94,"name":"Parking Ticket Vending Machine"},"amenity/vending_machine/public_transport_tickets":{"icon":"poi-vending-machine","fields":["operator","payment_multi","currency_multi"],"geometry":["point"],"terms":["bus","train","ferry","rail","ticket","transportation"],"tags":{"amenity":"vending_machine","vending":"public_transport_tickets"},"reference":{"key":"vending","value":"public_transport_tickets"},"name":"Transit Ticket Vending Machine"},"amenity/vending_machine/sweets":{"icon":"poi-vending-machine","fields":["operator","payment_multi","currency_multi"],"geometry":["point"],"terms":["candy","gum","chip","pretzel","cookie","cracker"],"tags":{"amenity":"vending_machine","vending":"sweets"},"reference":{"key":"vending","value":"sweets"},"name":"Snack Vending Machine"},"amenity/veterinary":{"icon":"veterinary","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["pet clinic","veterinarian","animal hospital","pet doctor"],"tags":{"amenity":"veterinary"},"name":"Veterinary"},"amenity/waste_basket":{"icon":"waste-basket","fields":["collection_times"],"geometry":["point","vertex","area"],"tags":{"amenity":"waste_basket"},"terms":["bin","garbage","rubbish","litter","trash"],"name":"Waste Basket"},"amenity/waste_disposal":{"icon":"waste-basket","fields":["collection_times"],"geometry":["point","vertex","area"],"tags":{"amenity":"waste_disposal"},"terms":["garbage","rubbish","litter","trash"],"name":"Garbage Dumpster"},"amenity/waste_transfer_station":{"icon":"waste-basket","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["dump","garbage","recycling","rubbish","scrap","trash"],"tags":{"amenity":"waste_transfer_station"},"name":"Waste Transfer Station"},"amenity/water_point":{"icon":"drinking-water","geometry":["area","vertex","point"],"tags":{"amenity":"water_point"},"name":"RV Drinking Water"},"amenity/watering_place":{"icon":"drinking-water","geometry":["area","vertex","point"],"tags":{"amenity":"watering_place"},"name":"Animal Watering Place"},"area":{"name":"Area","tags":{"area":"yes"},"geometry":["area"],"matchScore":0.1},"area/highway":{"fields":["area/highway"],"geometry":["area"],"tags":{"area:highway":"*"},"name":"Road Surface"},"barrier":{"icon":"roadblock","geometry":["point","vertex","line","area"],"tags":{"barrier":"*"},"fields":["barrier"],"name":"Barrier","matchScore":0.4},"barrier/entrance":{"icon":"entrance-alt1","geometry":["vertex"],"tags":{"barrier":"entrance"},"name":"Entrance","searchable":false},"barrier/block":{"icon":"roadblock","fields":["access"],"geometry":["point","vertex"],"tags":{"barrier":"block"},"name":"Block"},"barrier/bollard":{"icon":"roadblock","fields":["access"],"geometry":["point","vertex","line"],"tags":{"barrier":"bollard"},"name":"Bollard"},"barrier/border_control":{"icon":"roadblock","fields":["access","building_area"],"geometry":["vertex","area"],"tags":{"barrier":"border_control"},"name":"Border Control"},"barrier/cattle_grid":{"icon":"barrier","geometry":["vertex"],"tags":{"barrier":"cattle_grid"},"name":"Cattle Grid"},"barrier/city_wall":{"icon":"barrier","fields":["height"],"geometry":["line","area"],"tags":{"barrier":"city_wall"},"name":"City Wall"},"barrier/cycle_barrier":{"icon":"roadblock","fields":["access"],"geometry":["vertex"],"tags":{"barrier":"cycle_barrier"},"name":"Cycle Barrier"},"barrier/ditch":{"icon":"roadblock","geometry":["line","area"],"tags":{"barrier":"ditch"},"name":"Trench","matchScore":0.25},"barrier/fence":{"icon":"fence","fields":["fence_type","height"],"geometry":["line"],"tags":{"barrier":"fence"},"name":"Fence","matchScore":0.25},"barrier/gate":{"icon":"barrier","fields":["access"],"geometry":["point","vertex","line"],"tags":{"barrier":"gate"},"name":"Gate"},"barrier/hedge":{"fields":["height"],"geometry":["line","area"],"tags":{"barrier":"hedge"},"name":"Hedge","matchScore":0.25},"barrier/kissing_gate":{"icon":"barrier","fields":["access"],"geometry":["vertex"],"tags":{"barrier":"kissing_gate"},"name":"Kissing Gate"},"barrier/lift_gate":{"icon":"roadblock","fields":["access"],"geometry":["point","vertex"],"tags":{"barrier":"lift_gate"},"name":"Lift Gate"},"barrier/retaining_wall":{"geometry":["line","area"],"tags":{"barrier":"retaining_wall"},"name":"Retaining Wall"},"barrier/stile":{"icon":"roadblock","fields":["access"],"geometry":["point","vertex"],"tags":{"barrier":"stile"},"name":"Stile"},"barrier/toll_booth":{"icon":"roadblock","fields":["access","building_area"],"geometry":["vertex","area"],"tags":{"barrier":"toll_booth"},"name":"Toll Booth"},"barrier/wall":{"icon":"barrier","fields":["wall","height"],"geometry":["line","area"],"tags":{"barrier":"wall"},"name":"Wall","matchScore":0.25},"boundary/administrative":{"name":"Administrative Boundary","geometry":["line"],"tags":{"boundary":"administrative"},"fields":["admin_level"]},"building":{"icon":"home","fields":["building","levels","address"],"geometry":["point","area"],"tags":{"building":"*"},"matchScore":0.6,"terms":[],"name":"Building"},"building/bunker":{"fields":["address","levels"],"geometry":["area"],"tags":{"building":"bunker"},"matchScore":0.5,"name":"Bunker","searchable":false},"building/entrance":{"icon":"entrance-alt1","geometry":["vertex"],"tags":{"building":"entrance"},"name":"Entrance/Exit","searchable":false},"building/train_station":{"icon":"building","fields":["address","levels"],"geometry":["point","vertex","area"],"tags":{"building":"train_station"},"matchScore":0.5,"name":"Train Station","searchable":false},"building/apartments":{"icon":"building","fields":["address","levels"],"geometry":["area"],"tags":{"building":"apartments"},"matchScore":0.5,"name":"Apartments"},"building/barn":{"icon":"farm","fields":["address","levels"],"geometry":["area"],"tags":{"building":"barn"},"matchScore":0.5,"name":"Barn"},"building/cabin":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"cabin"},"matchScore":0.5,"name":"Cabin"},"building/cathedral":{"icon":"place-of-worship","fields":["address","levels"],"geometry":["area"],"tags":{"building":"cathedral"},"matchScore":0.5,"name":"Cathedral Building"},"building/chapel":{"icon":"place-of-worship","fields":["address","levels"],"geometry":["area"],"tags":{"building":"chapel"},"matchScore":0.5,"name":"Chapel Building"},"building/church":{"icon":"place-of-worship","fields":["address","levels"],"geometry":["area"],"tags":{"building":"church"},"matchScore":0.5,"name":"Church Building"},"building/college":{"icon":"building","fields":["address","levels"],"geometry":["area"],"terms":["university"],"tags":{"building":"college"},"matchScore":0.5,"name":"College Building"},"building/commercial":{"icon":"commercial","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"commercial"},"matchScore":0.5,"name":"Commercial Building"},"building/construction":{"icon":"building","fields":["address","levels"],"geometry":["area"],"tags":{"building":"construction"},"matchScore":0.5,"name":"Building Under Construction"},"building/detached":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"detached"},"terms":["home","single","family","residence","dwelling"],"matchScore":0.5,"name":"Detached House"},"building/dormitory":{"icon":"building","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"dormitory"},"matchScore":0.5,"name":"Dormitory"},"building/garage":{"icon":"warehouse","fields":["capacity"],"geometry":["area"],"tags":{"building":"garage"},"matchScore":0.5,"name":"Garage"},"building/garages":{"icon":"warehouse","fields":["capacity"],"geometry":["area"],"tags":{"building":"garages"},"matchScore":0.5,"name":"Garages"},"building/greenhouse":{"icon":"garden-center","fields":["address","levels"],"geometry":["area"],"tags":{"building":"greenhouse"},"matchScore":0.5,"name":"Greenhouse"},"building/hospital":{"icon":"building","fields":["address","levels"],"geometry":["area"],"tags":{"building":"hospital"},"matchScore":0.5,"name":"Hospital Building"},"building/hotel":{"icon":"building","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"hotel"},"matchScore":0.5,"name":"Hotel Building"},"building/house":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"house"},"terms":["home","family","residence","dwelling"],"matchScore":0.5,"name":"House"},"building/hut":{"geometry":["area"],"tags":{"building":"hut"},"matchScore":0.5,"name":"Hut"},"building/industrial":{"icon":"industry","fields":["address","levels"],"geometry":["area"],"tags":{"building":"industrial"},"matchScore":0.5,"name":"Industrial Building"},"building/kindergarten":{"icon":"building","fields":["address","levels"],"geometry":["area"],"terms":["kindergarden","pre-school"],"tags":{"building":"kindergarten"},"matchScore":0.5,"name":"Preschool/Kindergarten Building"},"building/public":{"icon":"building","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"public"},"matchScore":0.5,"name":"Public Building"},"building/residential":{"icon":"residential-community","fields":["address","levels"],"geometry":["area"],"tags":{"building":"residential"},"matchScore":0.5,"name":"Residential Building"},"building/retail":{"icon":"commercial","fields":["address","levels","smoking"],"geometry":["area"],"tags":{"building":"retail"},"matchScore":0.5,"name":"Retail Building"},"building/roof":{"icon":"shelter","fields":["address"],"geometry":["area"],"tags":{"building":"roof"},"matchScore":0.5,"name":"Roof"},"building/school":{"icon":"building","fields":["address","levels"],"geometry":["area"],"terms":["academy","elementary school","middle school","high school"],"tags":{"building":"school"},"matchScore":0.5,"name":"School Building"},"building/semidetached_house":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"semidetached_house"},"terms":["home","double","duplex","twin","family","residence","dwelling"],"matchScore":0.5,"name":"Semi-Detached House"},"building/shed":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"shed"},"matchScore":0.5,"name":"Shed"},"building/stable":{"icon":"horse-riding","fields":["address","levels"],"geometry":["area"],"tags":{"building":"stable"},"matchScore":0.5,"name":"Stable"},"building/static_caravan":{"icon":"home","fields":["address","levels"],"geometry":["area"],"tags":{"building":"static_caravan"},"matchScore":0.5,"name":"Static Mobile Home"},"building/terrace":{"icon":"building","fields":["address","levels"],"geometry":["area"],"tags":{"building":"terrace"},"terms":["home","terrace","brownstone","family","residence","dwelling"],"matchScore":0.5,"name":"Row Houses"},"building/university":{"icon":"building","fields":["address","levels"],"geometry":["area"],"terms":["college"],"tags":{"building":"university"},"matchScore":0.5,"name":"University Building"},"building/warehouse":{"icon":"warehouse","fields":["address","levels"],"geometry":["area"],"tags":{"building":"warehouse"},"matchScore":0.5,"name":"Warehouse"},"camp_site/camp_pitch":{"icon":"campsite","fields":["ref"],"geometry":["point","area"],"terms":["tent","rv"],"tags":{"camp_site":"camp_pitch"},"name":"Camp Pitch"},"club":{"icon":"heart","fields":["club","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"club":"*"},"terms":["social"],"name":"Club"},"craft":{"icon":"poi-tool","fields":["craft","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"*"},"terms":[],"name":"Craft"},"craft/jeweler":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"jeweler"},"reference":{"key":"shop","value":"jewelry"},"name":"Jeweler","searchable":false},"craft/locksmith":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"locksmith"},"reference":{"key":"shop","value":"locksmith"},"name":"Locksmith","searchable":false},"craft/optician":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"optician"},"reference":{"key":"shop","value":"optician"},"name":"Optician","searchable":false},"craft/tailor":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["clothes","suit"],"tags":{"craft":"tailor"},"reference":{"key":"shop","value":"tailor"},"name":"Tailor","searchable":false},"craft/basket_maker":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"basket_maker"},"name":"Basket Maker"},"craft/beekeeper":{"icon":"farm","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"beekeeper"},"name":"Beekeeper"},"craft/blacksmith":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"blacksmith"},"name":"Blacksmith"},"craft/boatbuilder":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"boatbuilder"},"name":"Boat Builder"},"craft/bookbinder":{"icon":"library","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["book repair"],"tags":{"craft":"bookbinder"},"name":"Bookbinder"},"craft/brewery":{"icon":"beer","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["beer","bier"],"tags":{"craft":"brewery"},"name":"Brewery"},"craft/carpenter":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["woodworker"],"tags":{"craft":"carpenter"},"name":"Carpenter"},"craft/carpet_layer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"carpet_layer"},"name":"Carpet Layer"},"craft/caterer":{"icon":"restaurant","fields":["cuisine","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"caterer"},"name":"Caterer"},"craft/clockmaker":{"icon":"poi-clock","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"clockmaker"},"name":"Clockmaker"},"craft/confectionery":{"icon":"bakery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["sweets","candy"],"tags":{"craft":"confectionery"},"name":"Confectionery"},"craft/dressmaker":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["seamstress"],"tags":{"craft":"dressmaker"},"name":"Dressmaker"},"craft/electrician":{"icon":"poi-power","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["power","wire"],"tags":{"craft":"electrician"},"name":"Electrician"},"craft/gardener":{"icon":"garden","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["landscaper","grounds keeper"],"tags":{"craft":"gardener"},"name":"Gardener"},"craft/glaziery":{"icon":"fire-station","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["glass","stained-glass","window"],"tags":{"craft":"glaziery"},"name":"Glaziery"},"craft/handicraft":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"handicraft"},"name":"Handicraft"},"craft/hvac":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["heat*","vent*","air conditioning"],"tags":{"craft":"hvac"},"name":"HVAC"},"craft/insulator":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"insulation"},"name":"Insulator"},"craft/key_cutter":{"icon":"marker-stroked","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"key_cutter"},"name":"Key Cutter"},"craft/metal_construction":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"metal_construction"},"name":"Metal Construction"},"craft/painter":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"painter"},"name":"Painter"},"craft/photographer":{"icon":"attraction","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"photographer"},"name":"Photographer"},"craft/photographic_laboratory":{"icon":"attraction","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["film"],"tags":{"craft":"photographic_laboratory"},"name":"Photographic Laboratory"},"craft/plasterer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"plasterer"},"name":"Plasterer"},"craft/plumber":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["pipe"],"tags":{"craft":"plumber"},"name":"Plumber"},"craft/pottery":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["ceramic"],"tags":{"craft":"pottery"},"name":"Pottery"},"craft/rigger":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"rigger"},"name":"Rigger"},"craft/roofer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"roofer"},"name":"Roofer"},"craft/saddler":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"saddler"},"name":"Saddler"},"craft/sailmaker":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"sailmaker"},"name":"Sailmaker"},"craft/sawmill":{"icon":"logging","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["lumber"],"tags":{"craft":"sawmill"},"name":"Sawmill"},"craft/scaffolder":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"scaffolder"},"name":"Scaffolder"},"craft/sculpter":{"icon":"art-gallery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"sculpter"},"name":"Sculpter"},"craft/shoemaker":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["cobbler"],"tags":{"craft":"shoemaker"},"name":"Shoemaker"},"craft/stonemason":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["masonry"],"tags":{"craft":"stonemason"},"name":"Stonemason"},"craft/sweep":{"icon":"poi-chimney","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"sweep"},"name":"Chimney Sweep"},"craft/tiler":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"tiler"},"name":"Tiler"},"craft/tinsmith":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"tinsmith"},"name":"Tinsmith"},"craft/upholsterer":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"upholsterer"},"name":"Upholsterer"},"craft/watchmaker":{"icon":"poi-clock","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"watchmaker"},"name":"Watchmaker"},"craft/window_construction":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["glass"],"tags":{"craft":"window_construction"},"name":"Window Construction"},"craft/winery":{"icon":"alcohol-shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"winery"},"name":"Winery"},"embankment":{"geometry":["line"],"tags":{"embankment":"yes"},"name":"Embankment","matchScore":0.2},"emergency/designated":{"fields":[],"geometry":["line"],"tags":{"emergency":"designated"},"terms":[],"name":"Emergency Access Designated","searchable":false,"matchScore":0.01},"emergency/destination":{"fields":[],"geometry":["line"],"tags":{"emergency":"destination"},"terms":[],"name":"Emergency Access Destination","searchable":false,"matchScore":0.01},"emergency/no":{"fields":[],"geometry":["line"],"tags":{"emergency":"no"},"terms":[],"name":"Emergency Access No","searchable":false,"matchScore":0.01},"emergency/official":{"fields":[],"geometry":["line"],"tags":{"emergency":"official"},"terms":[],"name":"Emergency Access Official","searchable":false,"matchScore":0.01},"emergency/private":{"fields":[],"geometry":["line"],"tags":{"emergency":"private"},"terms":[],"name":"Emergency Access Private","searchable":false,"matchScore":0.01},"emergency/yes":{"fields":[],"geometry":["line"],"tags":{"emergency":"yes"},"terms":[],"name":"Emergency Access Yes","searchable":false,"matchScore":0.01},"emergency/ambulance_station":{"icon":"hospital","fields":["operator","building_area","address"],"geometry":["point","area"],"terms":["EMS","EMT","rescue"],"tags":{"emergency":"ambulance_station"},"name":"Ambulance Station"},"emergency/defibrillator":{"icon":"defibrillator","fields":["access","opening_hours","indoor","phone"],"geometry":["point"],"terms":["AED"],"tags":{"emergency":"defibrillator"},"name":"Defibrillator"},"emergency/fire_hydrant":{"icon":"poi-fire-hydrant","fields":["fire_hydrant/type","fire_hydrant/position","ref","operator"],"geometry":["point","vertex"],"terms":["fire plug"],"tags":{"emergency":"fire_hydrant"},"name":"Fire Hydrant"},"emergency/phone":{"icon":"emergency-phone","fields":["operator"],"geometry":["point","vertex"],"tags":{"emergency":"phone"},"name":"Emergency Phone"},"entrance":{"icon":"entrance-alt1","geometry":["vertex"],"tags":{"entrance":"*"},"fields":["entrance","access_simple","address"],"name":"Entrance/Exit"},"footway/crossing":{"fields":["crossing","access","surface","kerb","tactile_paving"],"geometry":["line"],"tags":{"highway":"footway","footway":"crossing"},"reference":{"key":"footway","value":"crossing"},"terms":[],"name":"Street Crossing"},"footway/crosswalk":{"icon":"highway-footway","fields":["crossing","access","surface","kerb","tactile_paving"],"geometry":["line"],"tags":{"highway":"footway","footway":"crossing","crossing":"zebra"},"reference":{"key":"highway","value":"crossing"},"terms":["zebra crossing"],"name":"Pedestrian Crosswalk"},"footway/sidewalk":{"icon":"highway-footway","fields":["surface","lit","width","structure","access"],"geometry":["line"],"tags":{"highway":"footway","footway":"sidewalk"},"reference":{"key":"footway","value":"sidewalk"},"terms":[],"name":"Sidewalk"},"ford":{"geometry":["vertex"],"tags":{"ford":"yes"},"name":"Ford"},"golf/bunker":{"icon":"golf","geometry":["area"],"tags":{"golf":"bunker","natural":"sand"},"terms":["hazard","bunker"],"reference":{"key":"golf","value":"bunker"},"name":"Sand Trap"},"golf/fairway":{"icon":"golf","geometry":["area"],"tags":{"golf":"fairway","landuse":"grass"},"reference":{"key":"golf","value":"fairway"},"name":"Fairway"},"golf/green":{"icon":"golf","geometry":["area"],"tags":{"golf":"green","landuse":"grass","leisure":"pitch","sport":"golf"},"reference":{"key":"golf","value":"green"},"name":"Putting Green"},"golf/hole":{"icon":"golf","fields":["golf_hole","par","handicap"],"geometry":["line"],"tags":{"golf":"hole"},"name":"Golf Hole"},"golf/lateral_water_hazard_area":{"icon":"golf","geometry":["area"],"tags":{"golf":"lateral_water_hazard","natural":"water"},"reference":{"key":"golf","value":"lateral_water_hazard"},"name":"Lateral Water Hazard"},"golf/lateral_water_hazard_line":{"icon":"golf","geometry":["line"],"tags":{"golf":"lateral_water_hazard"},"name":"Lateral Water Hazard"},"golf/rough":{"icon":"golf","geometry":["area"],"tags":{"golf":"rough","landuse":"grass"},"reference":{"key":"golf","value":"rough"},"name":"Rough"},"golf/tee":{"icon":"golf","geometry":["area"],"tags":{"golf":"tee","landuse":"grass"},"terms":["teeing ground"],"reference":{"key":"golf","value":"tee"},"name":"Tee Box"},"golf/water_hazard_area":{"icon":"golf","geometry":["area"],"tags":{"golf":"water_hazard","natural":"water"},"reference":{"key":"golf","value":"water_hazard"},"name":"Water Hazard"},"golf/water_hazard_line":{"icon":"golf","geometry":["line"],"tags":{"golf":"water_hazard"},"name":"Water Hazard"},"healthcare/blood_donation":{"icon":"blood-bank","fields":["operator","address","blood_components","opening_hours","ref"],"geometry":["point","area"],"terms":["blood bank","blood donation","blood transfusion","apheresis","plasmapheresis","plateletpheresis","stem cell donation"],"tags":{"healthcare":"blood_donation"},"name":"Blood Donor Center"},"highway/bridleway":{"fields":["surface","width","structure","access"],"icon":"highway-bridleway","geometry":["line"],"tags":{"highway":"bridleway"},"terms":["bridleway","equestrian","horse"],"name":"Bridle Path"},"highway/bus_stop":{"icon":"bus","fields":["network","operator","bench","shelter"],"geometry":["point","vertex"],"tags":{"highway":"bus_stop"},"terms":[],"name":"Bus Stop"},"highway/corridor":{"icon":"highway-footway","fields":["width","level","access_simple"],"geometry":["line"],"tags":{"highway":"corridor"},"terms":["gallery","hall","hallway","indoor","passage","passageway"],"name":"Indoor Corridor"},"highway/crossing":{"fields":["crossing","kerb","tactile_paving"],"geometry":["vertex"],"tags":{"highway":"crossing"},"reference":{"key":"footway","value":"crossing"},"terms":[],"name":"Street Crossing"},"highway/crosswalk":{"icon":"poi-foot","fields":["crossing","kerb","tactile_paving"],"geometry":["vertex"],"tags":{"highway":"crossing","crossing":"zebra"},"reference":{"key":"highway","value":"crossing"},"terms":["zebra crossing"],"name":"Pedestrian Crosswalk"},"highway/cycleway":{"icon":"highway-cycleway","fields":["oneway","surface","lit","width","structure","access"],"geometry":["line"],"tags":{"highway":"cycleway"},"terms":["bike"],"name":"Cycle Path"},"highway/footway":{"icon":"highway-footway","fields":["surface","lit","width","structure","access"],"geometry":["line","area"],"terms":["hike","hiking","trackway","trail","walk"],"tags":{"highway":"footway"},"name":"Foot Path"},"highway/give_way":{"icon":"poi-yield","fields":["parallel_direction"],"geometry":["vertex"],"tags":{"highway":"give_way"},"terms":["give way","yield","sign"],"name":"Yield Sign"},"highway/living_street":{"icon":"highway-living-street","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","access","cycleway"],"geometry":["line"],"tags":{"highway":"living_street"},"name":"Living Street"},"highway/mini_roundabout":{"icon":"circle-stroked","geometry":["vertex"],"tags":{"highway":"mini_roundabout"},"fields":["clock_direction"],"name":"Mini-Roundabout"},"highway/motorway_junction":{"icon":"poi-junction","geometry":["vertex"],"tags":{"highway":"motorway_junction"},"fields":["ref"],"name":"Motorway Junction / Exit"},"highway/motorway_link":{"icon":"highway-motorway-link","fields":["ref","oneway_yes","maxspeed","lanes","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"motorway_link"},"addTags":{"highway":"motorway_link","oneway":"yes"},"removeTags":{"highway":"motorway_link","oneway":"yes"},"terms":["ramp","on ramp","off ramp"],"name":"Motorway Link"},"highway/motorway":{"icon":"highway-motorway","fields":["ref","oneway_yes","maxspeed","lanes","surface","structure","maxheight","toll","access"],"geometry":["line"],"tags":{"highway":"motorway"},"terms":["autobahn","expressway","freeway","highway","interstate","parkway","thruway","turnpike"],"name":"Motorway"},"highway/path":{"icon":"highway-path","fields":["surface","width","structure","access","incline","sac_scale","trail_visibility","mtb/scale","mtb/scale/uphill","mtb/scale/imba","ref"],"geometry":["line"],"terms":["hike","hiking","trackway","trail","walk"],"tags":{"highway":"path"},"name":"Path"},"highway/pedestrian":{"icon":"highway-footway","fields":["surface","lit","width","oneway","structure","access"],"geometry":["line","area"],"tags":{"highway":"pedestrian"},"terms":[],"name":"Pedestrian Street"},"highway/primary_link":{"icon":"highway-primary-link","fields":["oneway","maxspeed","lanes","surface","maxheight","ref","cycleway","structure","access"],"geometry":["line"],"tags":{"highway":"primary_link"},"terms":["ramp","on ramp","off ramp"],"name":"Primary Link"},"highway/primary":{"icon":"highway-primary","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"primary"},"terms":[],"name":"Primary Road"},"highway/raceway":{"icon":"highway-unclassified","fields":["oneway","surface","sport_racing_motor","lit","width","lanes","structure"],"geometry":["point","line","area"],"tags":{"highway":"raceway"},"addTags":{"highway":"raceway","sport":"motor"},"terms":["auto*","formula one","kart","motocross","nascar","race*","track"],"name":"Racetrack (Motorsport)"},"highway/residential":{"icon":"highway-residential","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","cycleway","access"],"geometry":["line"],"tags":{"highway":"residential"},"terms":[],"name":"Residential Road"},"highway/rest_area":{"icon":"car","geometry":["point","vertex","area"],"tags":{"highway":"rest_area"},"terms":["rest stop"],"name":"Rest Area"},"highway/road":{"icon":"highway-road","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"road"},"terms":[],"name":"Unknown Road"},"highway/secondary_link":{"icon":"highway-secondary-link","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"secondary_link"},"terms":["ramp","on ramp","off ramp"],"name":"Secondary Link"},"highway/secondary":{"icon":"highway-secondary","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"secondary"},"terms":[],"name":"Secondary Road"},"highway/service":{"icon":"highway-service","fields":["service","oneway","maxspeed","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"service"},"terms":[],"name":"Service Road"},"highway/service/alley":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"alley"},"reference":{"key":"service","value":"alley"},"name":"Alley"},"highway/service/drive-through":{"icon":"highway-service","fields":["oneway","covered","maxheight","maxspeed","structure","access","surface"],"geometry":["line"],"tags":{"highway":"service","service":"drive-through"},"reference":{"key":"service","value":"drive-through"},"name":"Drive-Through"},"highway/service/driveway":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"driveway"},"reference":{"key":"service","value":"driveway"},"name":"Driveway"},"highway/service/emergency_access":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"emergency_access"},"reference":{"key":"service","value":"emergency_access"},"name":"Emergency Access"},"highway/service/parking_aisle":{"icon":"highway-service","fields":["oneway","maxspeed","structure","access","surface","maxheight"],"geometry":["line"],"tags":{"highway":"service","service":"parking_aisle"},"reference":{"key":"service","value":"parking_aisle"},"name":"Parking Aisle"},"highway/services":{"icon":"car","geometry":["point","vertex","area"],"tags":{"highway":"services"},"terms":["services","travel plaza","service station"],"name":"Service Area"},"highway/speed_camera":{"icon":"attraction","geometry":["point"],"fields":["ref"],"tags":{"highway":"speed_camera"},"terms":[],"name":"Speed Camera"},"highway/steps":{"icon":"highway-steps","fields":["surface","lit","width","incline_steps","handrail","step_count"],"geometry":["line"],"tags":{"highway":"steps"},"terms":["stairs","staircase"],"name":"Steps"},"highway/stop":{"icon":"poi-stop","fields":["stop","parallel_direction"],"geometry":["vertex"],"tags":{"highway":"stop"},"terms":["stop","halt","sign"],"name":"Stop Sign"},"highway/street_lamp":{"icon":"poi-street-lamp","geometry":["point","vertex"],"tags":{"highway":"street_lamp"},"fields":["lamp_type","ref"],"terms":["streetlight","street light","lamp","light","gaslight"],"name":"Street Lamp"},"highway/tertiary_link":{"icon":"highway-tertiary-link","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"tertiary_link"},"terms":["ramp","on ramp","off ramp"],"name":"Tertiary Link"},"highway/tertiary":{"icon":"highway-tertiary","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","ref","cycleway","access"],"geometry":["line"],"tags":{"highway":"tertiary"},"terms":[],"name":"Tertiary Road"},"highway/track":{"icon":"highway-track","fields":["tracktype","surface","width","structure","access","incline","smoothness","mtb/scale","mtb/scale/uphill","mtb/scale/imba"],"geometry":["line"],"tags":{"highway":"track"},"terms":["woods road","forest road","logging road","fire road","farm road","agricultural road","ranch road","carriage road","primitive","unmaintained","rut","offroad","4wd","4x4","four wheel drive","atv","quad","jeep","double track","two track"],"name":"Unmaintained Track Road"},"highway/traffic_mirror":{"geometry":["point"],"tags":{"highway":"traffic_mirror"},"terms":["blind spot","convex","corner","curved","roadside","round","safety","sphere","visibility"],"name":"Traffic Mirror"},"highway/traffic_signals":{"icon":"poi-traffic-signals","geometry":["vertex"],"tags":{"highway":"traffic_signals"},"fields":["traffic_signals"],"terms":["light","stoplight","traffic light"],"name":"Traffic Signals"},"highway/trunk_link":{"icon":"highway-trunk-link","fields":["ref","oneway","maxspeed","lanes","surface","structure","maxheight","access"],"geometry":["line"],"tags":{"highway":"trunk_link"},"terms":["ramp","on ramp","off ramp"],"name":"Trunk Link"},"highway/trunk":{"icon":"highway-trunk","fields":["ref","oneway","maxspeed","lanes","surface","structure","maxheight","toll","access"],"geometry":["line"],"tags":{"highway":"trunk"},"terms":[],"name":"Trunk Road"},"highway/turning_circle":{"icon":"circle-stroked","geometry":["vertex"],"tags":{"highway":"turning_circle"},"terms":["cul-de-sac"],"name":"Turning Circle"},"highway/turning_loop":{"icon":"circle","geometry":["vertex"],"tags":{"highway":"turning_loop"},"terms":["cul-de-sac"],"name":"Turning Loop (Island)"},"highway/unclassified":{"icon":"highway-unclassified","fields":["oneway","maxspeed","lanes","surface","structure","maxheight","cycleway","access"],"geometry":["line"],"tags":{"highway":"unclassified"},"terms":[],"name":"Minor/Unclassified Road"},"historic":{"icon":"poi-ruins","fields":["historic","inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"*"},"name":"Historic Site"},"historic/archaeological_site":{"icon":"poi-ruins","fields":["historic/civilization","inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"archaeological_site"},"name":"Archaeological Site"},"historic/boundary_stone":{"icon":"monument","fields":["inscription"],"geometry":["point","vertex"],"tags":{"historic":"boundary_stone"},"name":"Boundary Stone"},"historic/castle":{"icon":"castle","fields":["castle_type","building_area","historic/civilization"],"geometry":["point","area"],"tags":{"historic":"castle"},"name":"Castle"},"historic/memorial":{"icon":"monument","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"memorial"},"name":"Memorial"},"historic/monument":{"icon":"monument","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"monument"},"name":"Monument"},"historic/ruins":{"icon":"poi-ruins","fields":["historic/civilization","inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"ruins"},"name":"Ruins"},"historic/tomb":{"icon":"cemetery","fields":["tomb","building_area","inscription"],"geometry":["point","area"],"tags":{"historic":"tomb"},"name":"Tomb"},"historic/wayside_cross":{"icon":"religious-christian","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"wayside_cross"},"name":"Wayside Cross"},"historic/wayside_shrine":{"icon":"landmark","fields":["inscription"],"geometry":["point","vertex","area"],"tags":{"historic":"wayside_shrine"},"name":"Wayside Shrine"},"junction":{"icon":"poi-junction","geometry":["vertex","area"],"tags":{"junction":"yes"},"name":"Junction"},"landuse":{"fields":["landuse"],"geometry":["area"],"tags":{"landuse":"*"},"matchScore":0.9,"name":"Land Use"},"landuse/farm":{"icon":"farm","fields":["operator","crop"],"geometry":["point","area"],"tags":{"landuse":"farm"},"terms":[],"name":"Farmland","searchable":false},"landuse/allotments":{"geometry":["area"],"tags":{"landuse":"allotments"},"terms":["allotment","garden"],"name":"Community Garden"},"landuse/aquaculture":{"icon":"aquarium","fields":["operator","produce"],"geometry":["area"],"tags":{"landuse":"aquaculture"},"terms":["fish farm","crustacean","algae","aquafarming","shrimp farm","oyster farm","mariculture","algaculture"],"name":"Aquaculture"},"landuse/basin":{"icon":"water","geometry":["area"],"tags":{"landuse":"basin"},"terms":[],"name":"Basin"},"landuse/cemetery":{"icon":"cemetery","fields":["religion","denomination"],"geometry":["area"],"tags":{"landuse":"cemetery"},"terms":[],"name":"Cemetery"},"landuse/churchyard":{"fields":["religion","denomination"],"geometry":["area"],"tags":{"landuse":"churchyard"},"terms":[],"name":"Churchyard"},"landuse/commercial":{"icon":"commercial","geometry":["area"],"tags":{"landuse":"commercial"},"terms":[],"name":"Commercial Area"},"landuse/construction":{"fields":["construction","operator"],"geometry":["area"],"tags":{"landuse":"construction"},"terms":[],"name":"Construction"},"landuse/farmland":{"icon":"farm","fields":["operator","crop","produce"],"geometry":["area"],"tags":{"landuse":"farmland"},"terms":["crop","grow","plant"],"name":"Farmland"},"landuse/farmyard":{"icon":"farm","fields":["operator","crop"],"geometry":["area"],"tags":{"landuse":"farmyard"},"terms":["crop","grow","plant"],"name":"Farmyard"},"landuse/forest":{"icon":"park-alt1","fields":["leaf_type","leaf_cycle","produce"],"geometry":["area"],"tags":{"landuse":"forest"},"terms":["tree"],"name":"Forest"},"landuse/garages":{"geometry":["area"],"tags":{"landuse":"garages"},"terms":[],"name":"Garages"},"landuse/grass":{"geometry":["area"],"tags":{"landuse":"grass"},"terms":[],"name":"Grass"},"landuse/harbour":{"icon":"harbor","fields":["operator"],"geometry":["area"],"terms":["boat"],"tags":{"landuse":"harbour"},"name":"Harbor"},"landuse/industrial":{"icon":"industry","geometry":["area"],"tags":{"landuse":"industrial"},"terms":[],"matchScore":0.9,"name":"Industrial Area"},"landuse/landfill":{"geometry":["area"],"tags":{"landuse":"landfill"},"terms":["dump"],"name":"Landfill"},"landuse/meadow":{"geometry":["area"],"tags":{"landuse":"meadow"},"terms":[],"name":"Meadow"},"landuse/military":{"icon":"poi-military","geometry":["area"],"tags":{"landuse":"military"},"terms":[],"matchScore":0.9,"name":"Military Area"},"landuse/military/airfield":{"icon":"airfield","fields":["ref","iata","icao"],"geometry":["point","area"],"tags":{"military":"airfield"},"addTags":{"landuse":"military","military":"airfield"},"removeTags":{"landuse":"military","military":"airfield"},"terms":["air force","army","base","bomb","fight","force","guard","heli*","jet","marine","navy","plane","troop","war"],"name":"Military Airfield"},"landuse/military/barracks":{"icon":"poi-military","fields":["building_area"],"geometry":["point","area"],"tags":{"military":"barracks"},"addTags":{"landuse":"military","military":"barracks"},"removeTags":{"landuse":"military","military":"barracks"},"terms":["air force","army","base","fight","force","guard","marine","navy","troop","war"],"name":"Barracks"},"landuse/military/bunker":{"icon":"poi-military","fields":["bunker_type","building_area"],"geometry":["point","area"],"tags":{"military":"bunker"},"addTags":{"building":"bunker","landuse":"military","military":"bunker"},"removeTags":{"building":"bunker","landuse":"military","military":"bunker"},"terms":["air force","army","base","fight","force","guard","marine","navy","troop","war"],"name":"Military Bunker"},"landuse/military/checkpoint":{"icon":"barrier","geometry":["point","vertex","area"],"tags":{"military":"checkpoint"},"addTags":{"landuse":"military","military":"checkpoint"},"removeTags":{"landuse":"military","military":"checkpoint"},"terms":["air force","army","base","force","guard","marine","navy","troop","war"],"name":"Checkpoint"},"landuse/military/danger_area":{"icon":"danger","geometry":["point","vertex","area"],"tags":{"military":"danger_area"},"addTags":{"landuse":"military","military":"danger_area"},"removeTags":{"landuse":"military","military":"danger_area"},"terms":["air force","army","base","blast","bomb","explo*","force","guard","mine","marine","navy","troop","war"],"name":"Danger Area"},"landuse/military/naval_base":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"naval_base"},"addTags":{"landuse":"military","military":"naval_base"},"removeTags":{"landuse":"military","military":"naval_base"},"terms":["base","fight","force","guard","marine","navy","ship","sub","troop","war"],"name":"Naval Base"},"landuse/military/nuclear_explosion_site":{"icon":"danger","geometry":["point","vertex","area"],"tags":{"military":"nuclear_explosion_site"},"addTags":{"landuse":"military","military":"nuclear_explosion_site"},"removeTags":{"landuse":"military","military":"nuclear_explosion_site"},"terms":["atom","blast","bomb","detonat*","nuke","site","test"],"name":"Nuclear Explosion Site"},"landuse/military/obstacle_course":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"obstacle_course"},"addTags":{"landuse":"military","military":"obstacle_course"},"removeTags":{"landuse":"military","military":"obstacle_course"},"terms":["army","base","force","guard","marine","navy","troop","war"],"name":"Obstacle Course"},"landuse/military/office":{"icon":"poi-military","fields":["building_area"],"geometry":["point","area"],"tags":{"military":"office"},"addTags":{"landuse":"military","military":"office"},"removeTags":{"landuse":"military","military":"office"},"terms":["air force","army","base","enlist","fight","force","guard","marine","navy","recruit","troop","war"],"name":"Military Office"},"landuse/military/range":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"range"},"addTags":{"landuse":"military","military":"range"},"removeTags":{"landuse":"military","military":"range"},"terms":["air force","army","base","fight","fire","force","guard","gun","marine","navy","rifle","shoot*","snip*","train","troop","war"],"name":"Military Range"},"landuse/military/training_area":{"icon":"poi-military","geometry":["point","area"],"tags":{"military":"training_area"},"addTags":{"landuse":"military","military":"training_area"},"removeTags":{"landuse":"military","military":"training_area"},"terms":["air force","army","base","fight","fire","force","guard","gun","marine","navy","rifle","shoot*","snip*","train","troop","war"],"name":"Training Area"},"landuse/orchard":{"icon":"park-alt1","fields":["operator","trees"],"geometry":["area"],"tags":{"landuse":"orchard"},"terms":["fruit"],"name":"Orchard"},"landuse/plant_nursery":{"icon":"garden","fields":["operator","plant"],"geometry":["area"],"tags":{"landuse":"plant_nursery"},"terms":["flower","garden","grow","vivero"],"name":"Plant Nursery"},"landuse/quarry":{"geometry":["area"],"tags":{"landuse":"quarry"},"terms":[],"name":"Quarry"},"landuse/railway":{"icon":"rail","fields":["operator"],"geometry":["area"],"tags":{"landuse":"railway"},"terms":["rail","train","track"],"name":"Railway Corridor"},"landuse/recreation_ground":{"icon":"pitch","geometry":["area"],"tags":{"landuse":"recreation_ground"},"terms":["playing fields"],"name":"Recreation Ground"},"landuse/residential":{"icon":"building","geometry":["area"],"tags":{"landuse":"residential"},"terms":[],"name":"Residential Area"},"landuse/retail":{"icon":"shop","geometry":["area"],"tags":{"landuse":"retail"},"name":"Retail Area"},"landuse/vineyard":{"fields":["operator","grape_variety"],"geometry":["area"],"tags":{"landuse":"vineyard"},"addTags":{"landuse":"vineyard","crop":"grape"},"removeTags":{"landuse":"vineyard","crop":"grape","grape_variety":"*"},"terms":["grape","wine"],"name":"Vineyard"},"leisure":{"icon":"pitch","fields":["leisure"],"geometry":["point","vertex","area"],"tags":{"leisure":"*"},"name":"Leisure"},"leisure/adult_gaming_centre":{"icon":"poi-dice","fields":["operator","address","building_area","opening_hours","smoking"],"geometry":["point","area"],"terms":["gambling","slot machine"],"tags":{"leisure":"adult_gaming_centre"},"name":"Adult Gaming Center"},"leisure/bird_hide":{"icon":"poi-binoculars","fields":["building_area"],"geometry":["point","area"],"tags":{"leisure":"bird_hide"},"terms":["machan","ornithology"],"name":"Bird Hide"},"leisure/bowling_alley":{"icon":"poi-bowling","fields":["operator","address","building_area","opening_hours","smoking"],"geometry":["point","area"],"terms":[],"tags":{"leisure":"bowling_alley"},"name":"Bowling Alley"},"leisure/common":{"icon":"poi-foot","geometry":["point","area"],"terms":["open space"],"tags":{"leisure":"common"},"name":"Common"},"leisure/dance":{"icon":"music","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["ballroom","jive","swing","tango","waltz"],"tags":{"leisure":"dance"},"name":"Dance Hall"},"leisure/dog_park":{"icon":"dog-park","geometry":["point","area"],"terms":[],"tags":{"leisure":"dog_park"},"name":"Dog Park"},"leisure/firepit":{"icon":"fire-station","geometry":["point","area"],"tags":{"leisure":"firepit"},"terms":["fireplace","campfire"],"name":"Firepit"},"leisure/fitness_centre":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"fitness_centre"},"terms":["health","gym","leisure","studio"],"name":"Gym / Fitness Center"},"leisure/fitness_centre/yoga":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["studio"],"tags":{"leisure":"fitness_centre","sport":"yoga"},"reference":{"key":"sport","value":"yoga"},"name":"Yoga Studio"},"leisure/fitness_station":{"icon":"pitch","fields":["sport","address","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"fitness_station"},"terms":["fitness","gym"],"name":"Outdoor Fitness Station"},"leisure/garden":{"icon":"garden","fields":["access_simple"],"geometry":["point","vertex","area"],"tags":{"leisure":"garden"},"name":"Garden"},"leisure/golf_course":{"icon":"golf","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["links"],"tags":{"leisure":"golf_course"},"name":"Golf Course"},"leisure/horse_riding":{"icon":"horse-riding","fields":["access_simple","operator","address","building"],"geometry":["point","area"],"terms":["equestrian","stable"],"tags":{"leisure":"horse_riding"},"name":"Horseback Riding Facility"},"leisure/ice_rink":{"icon":"pitch","fields":["seasonal","sport_ice","operator","address","building","opening_hours"],"geometry":["point","area"],"terms":["hockey","skating","curling"],"tags":{"leisure":"ice_rink"},"name":"Ice Rink"},"leisure/marina":{"icon":"harbor","fields":["operator","address","capacity","fee","sanitary_dump_station","power_supply","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"terms":["boat"],"tags":{"leisure":"marina"},"name":"Marina"},"leisure/miniature_golf":{"icon":"golf","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["crazy golf","mini golf","putt-putt"],"tags":{"leisure":"miniature_golf"},"name":"Miniature Golf"},"leisure/nature_reserve":{"icon":"park","geometry":["point","area"],"tags":{"leisure":"nature_reserve"},"terms":["protected","wildlife"],"name":"Nature Reserve"},"leisure/park":{"icon":"park","geometry":["point","area"],"terms":["esplanade","estate","forest","garden","grass","green","grounds","lawn","lot","meadow","parkland","place","playground","plaza","pleasure garden","recreation area","square","tract","village green","woodland"],"tags":{"leisure":"park"},"name":"Park"},"leisure/picnic_table":{"icon":"picnic-site","geometry":["point"],"tags":{"leisure":"picnic_table"},"terms":["bench"],"name":"Picnic Table"},"leisure/pitch":{"icon":"pitch","fields":["sport","surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch"},"terms":["field"],"name":"Sport Pitch"},"leisure/pitch/american_football":{"icon":"america-football","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"american_football"},"reference":{"key":"sport","value":"american_football"},"terms":[],"name":"American Football Field"},"leisure/pitch/baseball":{"icon":"baseball","fields":["lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"baseball"},"reference":{"key":"sport","value":"baseball"},"terms":[],"name":"Baseball Diamond"},"leisure/pitch/basketball":{"icon":"basketball","fields":["surface","hoops","lit","access_simple"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"basketball"},"reference":{"key":"sport","value":"basketball"},"terms":[],"name":"Basketball Court"},"leisure/pitch/beachvolleyball":{"icon":"basketball","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"beachvolleyball"},"addTags":{"leisure":"pitch","sport":"beachvolleyball","surface":"sand"},"removeTags":{"leisure":"pitch","sport":"beachvolleyball","surface":"sand"},"reference":{"key":"sport","value":"beachvolleyball"},"terms":["volleyball"],"name":"Beach Volleyball Court"},"leisure/pitch/bowls":{"icon":"pitch","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"bowls"},"reference":{"key":"sport","value":"bowls"},"terms":[],"name":"Bowling Green"},"leisure/pitch/cricket":{"icon":"cricket","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"cricket"},"reference":{"key":"sport","value":"cricket"},"terms":[],"name":"Cricket Field"},"leisure/pitch/equestrian":{"icon":"horse-riding","fields":["surface","lit","building"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"equestrian"},"reference":{"key":"sport","value":"equestrian"},"terms":["dressage","equestrian","horse","horseback","riding"],"name":"Riding Arena"},"leisure/pitch/rugby_league":{"icon":"america-football","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"rugby_league"},"reference":{"key":"sport","value":"rugby_league"},"terms":[],"name":"Rugby League Field"},"leisure/pitch/rugby_union":{"icon":"america-football","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"rugby_union"},"reference":{"key":"sport","value":"rugby_union"},"terms":[],"name":"Rugby Union Field"},"leisure/pitch/skateboard":{"icon":"pitch","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"skateboard"},"reference":{"key":"sport","value":"skateboard"},"terms":[],"name":"Skate Park"},"leisure/pitch/soccer":{"icon":"soccer","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"soccer"},"reference":{"key":"sport","value":"soccer"},"terms":[],"name":"Soccer Field"},"leisure/pitch/table_tennis":{"icon":"tennis","fields":["lit","access_simple"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"table_tennis"},"reference":{"key":"sport","value":"table_tennis"},"terms":["table tennis","ping pong"],"name":"Ping Pong Table"},"leisure/pitch/tennis":{"icon":"tennis","fields":["surface","lit","access_simple"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"tennis"},"reference":{"key":"sport","value":"tennis"},"terms":[],"name":"Tennis Court"},"leisure/pitch/volleyball":{"icon":"basketball","fields":["surface","lit"],"geometry":["point","area"],"tags":{"leisure":"pitch","sport":"volleyball"},"reference":{"key":"sport","value":"volleyball"},"terms":[],"name":"Volleyball Court"},"leisure/playground":{"icon":"playground","geometry":["point","area"],"terms":["jungle gym","play area"],"tags":{"leisure":"playground"},"name":"Playground"},"leisure/resort":{"icon":"lodging","fields":["operator","address","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"resort"},"name":"Resort"},"leisure/running_track":{"icon":"pitch","fields":["surface","sport_racing_nonmotor","lit","width","lanes"],"geometry":["point","line","area"],"tags":{"leisure":"track","sport":"running"},"terms":["race*","running","sprint","track"],"name":"Racetrack (Running)"},"leisure/slipway":{"icon":"poi-beach","geometry":["point","line"],"terms":["boat launch","boat ramp"],"tags":{"leisure":"slipway"},"name":"Slipway"},"leisure/sports_centre":{"icon":"pitch","fields":["sport","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"leisure":"sports_centre"},"terms":[],"name":"Sports Center / Complex"},"leisure/sports_centre/swimming":{"icon":"swimming","fields":["access_simple","operator","address","building"],"geometry":["point","area"],"terms":["dive","water"],"tags":{"leisure":"sports_centre","sport":"swimming"},"reference":{"key":"sport","value":"swimming"},"name":"Swimming Pool Facility"},"leisure/stadium":{"icon":"pitch","fields":["sport","address"],"geometry":["point","area"],"tags":{"leisure":"stadium"},"name":"Stadium"},"leisure/swimming_pool":{"icon":"swimming","fields":["access_simple","operator","address"],"geometry":["point","area"],"terms":["dive","water"],"tags":{"leisure":"swimming_pool"},"name":"Swimming Pool"},"leisure/track":{"icon":"highway-road","fields":["surface","sport_racing_nonmotor","lit","width","lanes"],"geometry":["point","line","area"],"tags":{"leisure":"track"},"terms":["cycle","dog","greyhound","horse","race*","track"],"name":"Racetrack (Non-Motorsport)"},"leisure/water_park":{"icon":"swimming","fields":["operator","address"],"geometry":["point","area"],"terms":["swim","pool","dive"],"tags":{"leisure":"water_park"},"name":"Water Park"},"line":{"name":"Line","tags":{},"geometry":["line"],"matchScore":0.1},"man_made":{"icon":"poi-storage-tank","fields":["man_made"],"geometry":["point","vertex","line","area"],"tags":{"man_made":"*"},"name":"Man Made"},"man_made/embankment":{"geometry":["line"],"tags":{"man_made":"embankment"},"name":"Embankment","searchable":false},"man_made/adit":{"icon":"triangle","geometry":["point","area"],"fields":["operator"],"terms":["entrance","underground","mine","cave"],"tags":{"man_made":"adit"},"name":"Adit"},"man_made/breakwater":{"geometry":["line","area"],"tags":{"man_made":"breakwater"},"name":"Breakwater"},"man_made/bridge":{"geometry":["area"],"tags":{"man_made":"bridge"},"name":"Bridge"},"man_made/chimney":{"icon":"poi-chimney","geometry":["point","area"],"tags":{"man_made":"chimney"},"name":"Chimney"},"man_made/cutline":{"geometry":["line"],"tags":{"man_made":"cutline"},"name":"Cut line"},"man_made/flagpole":{"icon":"embassy","geometry":["point"],"tags":{"man_made":"flagpole"},"name":"Flagpole"},"man_made/gasometer":{"icon":"poi-storage-tank","geometry":["point","area"],"terms":["gas holder"],"tags":{"man_made":"gasometer"},"name":"Gasometer"},"man_made/groyne":{"geometry":["line","area"],"tags":{"man_made":"groyne"},"name":"Groyne"},"man_made/lighthouse":{"icon":"lighthouse","fields":["building_area"],"geometry":["point","area"],"tags":{"man_made":"lighthouse"},"name":"Lighthouse"},"man_made/mast":{"icon":"poi-mast","fields":["tower/type","tower/construction","height","communication_multi"],"geometry":["point"],"terms":["antenna","broadcast tower","cell phone tower","cell tower","communication mast","communication tower","guyed tower","mobile phone tower","radio mast","radio tower","television tower","transmission mast","transmission tower","tv tower"],"tags":{"man_made":"mast"},"name":"Mast"},"man_made/observation":{"icon":"poi-tower","geometry":["point","area"],"terms":["lookout tower","fire tower"],"tags":{"man_made":"tower","tower:type":"observation"},"name":"Observation Tower"},"man_made/petroleum_well":{"icon":"poi-storage-tank","geometry":["point"],"terms":["drilling rig","oil derrick","oil drill","oil horse","oil rig","oil pump","petroleum well","pumpjack"],"tags":{"man_made":"petroleum_well"},"name":"Oil Well"},"man_made/pier":{"geometry":["line","area"],"terms":["dock"],"tags":{"man_made":"pier"},"name":"Pier"},"man_made/pipeline":{"icon":"pipeline-line","fields":["location","operator"],"geometry":["line"],"tags":{"man_made":"pipeline"},"name":"Pipeline"},"man_made/pumping_station":{"icon":"water","geometry":["point","area"],"tags":{"man_made":"pumping_station"},"name":"Pumping Station"},"man_made/silo":{"icon":"poi-silo","fields":["building_area","crop"],"geometry":["point","area"],"terms":["grain","corn","wheat"],"tags":{"man_made":"silo"},"name":"Silo"},"man_made/storage_tank":{"icon":"poi-storage-tank","fields":["building_area","content"],"geometry":["point","area"],"terms":["water","oil","gas","petrol"],"tags":{"man_made":"storage_tank"},"name":"Storage Tank"},"man_made/surveillance_camera":{"icon":"attraction","geometry":["point"],"fields":["surveillance","surveillance/type","camera/type","camera/mount","camera/direction","surveillance/zone","contact/webcam"],"terms":["anpr","alpr","camera","car plate recognition","cctv","guard","license plate recognition","monitoring","number plate recognition","security","video","webcam"],"tags":{"man_made":"surveillance","surveillance:type":"camera"},"name":"Surveillance Camera"},"man_made/surveillance":{"icon":"attraction","geometry":["point"],"fields":["surveillance","surveillance/type","surveillance/zone"],"terms":["anpr","alpr","camera","car plate recognition","cctv","guard","license plate recognition","monitoring","number plate recognition","security","video","webcam"],"tags":{"man_made":"surveillance"},"name":"Surveillance"},"man_made/survey_point":{"icon":"monument","fields":["ref"],"geometry":["point","vertex"],"tags":{"man_made":"survey_point"},"name":"Survey Point"},"man_made/tower":{"icon":"poi-tower","fields":["tower/type","tower/construction","height"],"geometry":["point","area"],"tags":{"man_made":"tower"},"name":"Tower"},"man_made/wastewater_plant":{"icon":"water","fields":["operator","address"],"geometry":["point","area"],"terms":["sewage*","water treatment plant","reclamation plant"],"tags":{"man_made":"wastewater_plant"},"name":"Wastewater Plant"},"man_made/water_tower":{"icon":"water","fields":["operator"],"geometry":["point","area"],"tags":{"man_made":"water_tower"},"name":"Water Tower"},"man_made/water_well":{"icon":"water","fields":["operator"],"geometry":["point","area"],"tags":{"man_made":"water_well"},"name":"Water Well"},"man_made/water_works":{"icon":"water","fields":["operator","address"],"geometry":["point","area"],"tags":{"man_made":"water_works"},"name":"Water Works"},"man_made/works":{"icon":"industry","fields":["operator","address","building_area","product"],"geometry":["point","area"],"terms":["assembly","build","brewery","car","plant","plastic","processing","manufacture","refinery"],"tags":{"man_made":"works"},"name":"Factory"},"natural":{"icon":"natural","fields":["natural"],"geometry":["point","vertex","area"],"tags":{"natural":"*"},"name":"Natural"},"natural/bare_rock":{"geometry":["area"],"tags":{"natural":"bare_rock"},"terms":["rock"],"name":"Bare Rock"},"natural/bay":{"icon":"poi-beach","geometry":["point","area"],"tags":{"natural":"bay"},"terms":[],"name":"Bay"},"natural/beach":{"icon":"poi-beach","fields":["surface"],"geometry":["point","area"],"tags":{"natural":"beach"},"terms":["shore"],"name":"Beach"},"natural/cave_entrance":{"icon":"triangle","geometry":["point","area"],"fields":["fee","access_simple"],"tags":{"natural":"cave_entrance"},"terms":["cavern","hollow","grotto","shelter","cavity"],"name":"Cave Entrance"},"natural/cliff":{"icon":"triangle","geometry":["point","vertex","line","area"],"tags":{"natural":"cliff"},"terms":["escarpment"],"name":"Cliff"},"natural/coastline":{"geometry":["line"],"tags":{"natural":"coastline"},"terms":["shore"],"name":"Coastline"},"natural/fell":{"geometry":["area"],"tags":{"natural":"fell"},"terms":[],"name":"Fell"},"natural/glacier":{"geometry":["area"],"tags":{"natural":"glacier"},"terms":[],"name":"Glacier"},"natural/grassland":{"geometry":["area"],"tags":{"natural":"grassland"},"terms":["prairie","savanna"],"name":"Grassland"},"natural/heath":{"geometry":["area"],"tags":{"natural":"heath"},"terms":[],"name":"Heath"},"natural/peak":{"icon":"mountain","fields":["elevation"],"geometry":["point","vertex"],"tags":{"natural":"peak"},"terms":["acme","aiguille","alp","climax","crest","crown","hill","mount","mountain","pinnacle","summit","tip","top"],"name":"Peak"},"natural/ridge":{"geometry":["line"],"tags":{"natural":"ridge"},"terms":["crest"],"name":"Ridge"},"natural/saddle":{"icon":"triangle-stroked","fields":["elevation"],"geometry":["point","vertex"],"tags":{"natural":"saddle"},"terms":["pass","mountain pass","top"],"name":"Saddle"},"natural/sand":{"geometry":["area"],"tags":{"natural":"sand"},"terms":["desert"],"name":"Sand"},"natural/scree":{"geometry":["area"],"tags":{"natural":"scree"},"terms":["loose rocks"],"name":"Scree"},"natural/scrub":{"geometry":["area"],"tags":{"natural":"scrub"},"terms":["bush","shrubs"],"name":"Scrub"},"natural/spring":{"icon":"water","geometry":["point","vertex"],"tags":{"natural":"spring"},"terms":[],"name":"Spring"},"natural/tree_row":{"icon":"park","fields":["leaf_type","leaf_cycle","denotation"],"geometry":["line"],"tags":{"natural":"tree_row"},"terms":[],"name":"Tree row"},"natural/tree":{"icon":"park","fields":["leaf_type_singular","leaf_cycle_singular","denotation"],"geometry":["point","vertex"],"tags":{"natural":"tree"},"terms":[],"name":"Tree"},"natural/volcano":{"icon":"volcano","fields":["elevation"],"geometry":["point","vertex"],"tags":{"natural":"volcano"},"terms":["mountain","crater"],"name":"Volcano"},"natural/water":{"icon":"water","fields":["water"],"geometry":["area"],"tags":{"natural":"water"},"name":"Water"},"natural/water/lake":{"icon":"water","geometry":["area"],"tags":{"natural":"water","water":"lake"},"reference":{"key":"natural","value":"water"},"terms":["lakelet","loch","mere"],"name":"Lake"},"natural/water/pond":{"icon":"water","geometry":["area"],"tags":{"natural":"water","water":"pond"},"reference":{"key":"natural","value":"water"},"terms":["lakelet","millpond","tarn","pool","mere"],"name":"Pond"},"natural/water/reservoir":{"icon":"water","geometry":["area"],"tags":{"natural":"water","water":"reservoir"},"reference":{"key":"natural","value":"water"},"name":"Reservoir"},"natural/wetland":{"icon":"wetland","fields":["wetland"],"geometry":["point","area"],"tags":{"natural":"wetland"},"terms":[],"name":"Wetland"},"natural/wood":{"icon":"park-alt1","fields":["leaf_type","leaf_cycle"],"geometry":["point","area"],"tags":{"natural":"wood"},"terms":["tree"],"name":"Wood"},"noexit/yes":{"icon":"barrier","geometry":["vertex"],"terms":["no exit","road end","dead end"],"tags":{"noexit":"yes"},"reference":{"key":"noexit","value":"*"},"name":"No Exit"},"office":{"icon":"commercial","fields":["office","address","building_area","opening_hours","smoking"],"geometry":["point","vertex","area"],"tags":{"office":"*"},"terms":[],"name":"Office"},"office/travel_agent":{"icon":"suitcase","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"travel_agent"},"reference":{"key":"shop","value":"travel_agency"},"terms":[],"name":"Travel Agency","searchable":false},"office/accountant":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"accountant"},"terms":[],"name":"Accountant"},"office/administrative":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"administrative"},"terms":[],"name":"Administrative Office"},"office/architect":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"architect"},"terms":[],"name":"Architect"},"office/company":{"icon":"commercial","fields":["address","building_area","opening_hours","smoking"],"geometry":["point","vertex","area"],"tags":{"office":"company"},"terms":[],"name":"Company Office"},"office/coworking":{"icon":"commercial","fields":["address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"terms":["coworking","office"],"tags":{"office":"coworking"},"reference":{"key":"amenity","value":"coworking_space"},"name":"Coworking Space"},"office/educational_institution":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"educational_institution"},"terms":[],"name":"Educational Institution"},"office/employment_agency":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"employment_agency"},"terms":["job"],"name":"Employment Agency"},"office/estate_agent":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"estate_agent"},"terms":[],"name":"Real Estate Office"},"office/financial":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"financial"},"terms":[],"name":"Financial Office"},"office/government":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"government"},"terms":[],"name":"Government Office"},"office/government/register_office":{"icon":"town-hall","fields":["address","building_area","opening_hours","operator"],"geometry":["point","area"],"terms":["clerk","marriage","death","birth","certificate"],"tags":{"office":"government","government":"register_office"},"reference":{"key":"government","value":"register_office"},"name":"Register Office"},"office/insurance":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"insurance"},"terms":[],"name":"Insurance Office"},"office/it":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"it"},"terms":[],"name":"IT Office"},"office/lawyer":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"lawyer"},"terms":[],"name":"Law Office"},"office/lawyer/notary":{"icon":"suitcase","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"lawyer","lawyer":"notary"},"reference":{"key":"office","value":"notary"},"terms":["clerk","signature","wills","deeds","estate"],"name":"Notary Office"},"office/newspaper":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"newspaper"},"terms":[],"name":"Newspaper"},"office/ngo":{"icon":"commercial","fields":["address","building_area","opening_hours","smoking"],"geometry":["point","vertex","area"],"tags":{"office":"ngo"},"terms":[],"name":"NGO Office"},"office/physician":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"physician"},"terms":[],"name":"Physician"},"office/political_party":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"political_party"},"terms":[],"name":"Political Party"},"office/research":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"research"},"terms":[],"name":"Research Office"},"office/telecommunication":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"telecommunication"},"terms":[],"name":"Telecom Office"},"office/therapist":{"icon":"commercial","fields":["address","building_area","opening_hours"],"geometry":["point","vertex","area"],"tags":{"office":"therapist"},"terms":[],"name":"Therapist"},"piste":{"icon":"skiing","fields":["piste/type","piste/difficulty","piste/grooming","oneway","lit"],"geometry":["point","line","area"],"terms":["ski","sled","sleigh","snowboard","nordic","downhill","snowmobile"],"tags":{"piste:type":"*"},"name":"Piste/Ski Trail"},"place/farm":{"icon":"farm","geometry":["point","area"],"tags":{"place":"farm"},"name":"Farm","searchable":false},"place/city":{"icon":"city","fields":["population"],"geometry":["point","area"],"tags":{"place":"city"},"name":"City"},"place/hamlet":{"icon":"triangle-stroked","fields":["population"],"geometry":["point","area"],"tags":{"place":"hamlet"},"name":"Hamlet"},"place/island":{"icon":"mountain","geometry":["point","area"],"terms":["archipelago","atoll","bar","cay","isle","islet","key","reef"],"tags":{"place":"island"},"name":"Island"},"place/isolated_dwelling":{"icon":"home","geometry":["point","area"],"tags":{"place":"isolated_dwelling"},"name":"Isolated Dwelling"},"place/locality":{"icon":"triangle-stroked","geometry":["point","area"],"tags":{"place":"locality"},"name":"Locality"},"place/neighbourhood":{"icon":"triangle-stroked","fields":["population"],"geometry":["point","area"],"tags":{"place":"neighbourhood"},"terms":["neighbourhood"],"name":"Neighborhood"},"place/quarter":{"icon":"triangle-stroked","fields":["population"],"geometry":["point","area"],"tags":{"place":"quarter"},"terms":["boro","borough","quarter"],"name":"Sub-Borough / Quarter"},"place/square":{"icon":"poi-foot","geometry":["point","area"],"tags":{"place":"square"},"name":"Square"},"place/suburb":{"icon":"triangle-stroked","fields":["population"],"geometry":["point","area"],"tags":{"place":"suburb"},"terms":["boro","borough","quarter"],"name":"Borough / Suburb"},"place/town":{"icon":"town","fields":["population"],"geometry":["point","area"],"tags":{"place":"town"},"name":"Town"},"place/village":{"icon":"village","fields":["population"],"geometry":["point","area"],"tags":{"place":"village"},"name":"Village"},"point":{"name":"Point","tags":{},"geometry":["point"],"matchScore":0.1},"power/sub_station":{"fields":["substation","operator","building"],"geometry":["point","area"],"tags":{"power":"sub_station"},"reference":{"key":"power","value":"substation"},"name":"Substation","searchable":false},"power/generator":{"icon":"poi-power","fields":["operator","generator/source","generator/method","generator/type"],"geometry":["point","vertex","area"],"tags":{"power":"generator"},"name":"Power Generator"},"power/line":{"icon":"power-line","geometry":["line"],"tags":{"power":"line"},"name":"Power Line"},"power/minor_line":{"icon":"power-line","geometry":["line"],"tags":{"power":"minor_line"},"name":"Minor Power Line"},"power/plant":{"icon":"industry","fields":["operator"],"geometry":["area"],"tags":{"power":"plant"},"addTags":{"power":"plant","landuse":"industrial"},"removeTags":{"power":"plant","landuse":"industrial"},"terms":["coal","gas","generat*","hydro","nuclear","power","station"],"name":"Power Station Grounds"},"power/pole":{"geometry":["vertex"],"tags":{"power":"pole"},"name":"Power Pole"},"power/substation":{"icon":"poi-power","fields":["substation","operator","building"],"geometry":["point","area"],"tags":{"power":"substation"},"name":"Substation"},"power/tower":{"geometry":["vertex"],"tags":{"power":"tower"},"name":"High-Voltage Tower"},"power/transformer":{"icon":"poi-power","geometry":["point","vertex","area"],"tags":{"power":"transformer"},"name":"Transformer"},"public_transport/platform":{"icon":"bus","fields":["ref","network","operator","shelter"],"geometry":["point","vertex","line","area"],"tags":{"public_transport":"platform"},"name":"Platform"},"public_transport/stop_position":{"icon":"bus","fields":["ref","network","operator"],"geometry":["vertex"],"tags":{"public_transport":"stop_position"},"name":"Stop Position"},"railway/abandoned":{"icon":"railway-abandoned","geometry":["line"],"tags":{"railway":"abandoned"},"fields":["structure","service_rail"],"terms":[],"name":"Abandoned Railway"},"railway/crossing":{"icon":"cross","geometry":["vertex"],"tags":{"railway":"crossing"},"terms":["crossing","pedestrian crossing","railroad crossing","level crossing","grade crossing","path through railroad","train crossing"],"name":"Railway Crossing (Path)"},"railway/disused":{"icon":"railway-disused","geometry":["line"],"tags":{"railway":"disused"},"fields":["structure","service_rail"],"terms":[],"name":"Disused Railway"},"railway/funicular":{"icon":"railway-rail","geometry":["line"],"terms":["venicular","cliff railway","cable car","cable railway","funicular railway"],"fields":["structure","gauge","service_rail"],"tags":{"railway":"funicular"},"name":"Funicular"},"railway/halt":{"icon":"rail","geometry":["point","vertex"],"tags":{"railway":"halt"},"name":"Railway Halt","terms":["break","interrupt","rest","wait","interruption"]},"railway/level_crossing":{"icon":"cross","geometry":["vertex"],"tags":{"railway":"level_crossing"},"terms":["crossing","railroad crossing","level crossing","grade crossing","road through railroad","train crossing"],"name":"Railway Crossing (Road)"},"railway/monorail":{"icon":"railway-monorail","geometry":["line"],"tags":{"railway":"monorail"},"fields":["structure","electrified","service_rail"],"terms":[],"name":"Monorail"},"railway/narrow_gauge":{"icon":"railway-rail","geometry":["line"],"tags":{"railway":"narrow_gauge"},"fields":["structure","gauge","electrified","service_rail"],"terms":["narrow gauge railway","narrow gauge railroad"],"name":"Narrow Gauge Rail"},"railway/platform":{"icon":"rail","geometry":["point","vertex","line","area"],"tags":{"railway":"platform"},"name":"Railway Platform"},"railway/rail":{"icon":"railway-rail","geometry":["line"],"tags":{"railway":"rail"},"fields":["structure","gauge","electrified","maxspeed","service_rail"],"terms":[],"name":"Rail"},"railway/station":{"icon":"rail","fields":["network","operator","address","building_area","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"tags":{"railway":"station"},"terms":["train station","station"],"name":"Railway Station"},"railway/subway_entrance":{"icon":"entrance","geometry":["point"],"tags":{"railway":"subway_entrance"},"terms":[],"name":"Subway Entrance"},"railway/subway":{"icon":"railway-subway","geometry":["line"],"tags":{"railway":"subway"},"fields":["structure","gauge","electrified","service_rail"],"terms":[],"name":"Subway"},"railway/tram_stop":{"icon":"rail-light","fields":["network","operator"],"geometry":["vertex"],"tags":{"railway":"tram_stop"},"terms":["light rail","streetcar","tram","trolley"],"name":"Tram Stop"},"railway/tram":{"icon":"railway-light-rail","geometry":["line"],"tags":{"railway":"tram"},"fields":["structure","gauge","electrified","service_rail"],"terms":["light rail","streetcar","tram","trolley"],"name":"Tram"},"relation":{"name":"Relation","icon":"relation","tags":{},"geometry":["relation"],"fields":["relation"]},"route/ferry":{"icon":"ferry-line","geometry":["line"],"tags":{"route":"ferry"},"name":"Ferry Route"},"shop":{"icon":"shop","fields":["shop","operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"*"},"terms":[],"name":"Shop"},"shop/fishmonger":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"fishmonger"},"reference":{"key":"shop","value":"seafood"},"name":"Fishmonger","searchable":false},"shop/vacant":{"icon":"shop","fields":["address","building_area"],"geometry":["point","area"],"tags":{"shop":"vacant"},"name":"Vacant Shop","searchable":false},"shop/alcohol":{"icon":"alcohol-shop","fields":["operator","address","building_area","opening_hours","drive_through"],"geometry":["point","area"],"terms":["alcohol","beer","booze","wine"],"tags":{"shop":"alcohol"},"name":"Liquor Store"},"shop/anime":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"anime"},"terms":["manga","japan","cosplay","figurine","dakimakura"],"name":"Anime Shop"},"shop/antiques":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"antiques"},"name":"Antiques Shop"},"shop/art":{"icon":"shop","fields":["artwork_type","operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["art*","exhibit*","gallery"],"tags":{"shop":"art"},"name":"Art Store"},"shop/baby_goods":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"baby_goods"},"name":"Baby Goods Store"},"shop/bag":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["handbag","purse"],"tags":{"shop":"bag"},"name":"Bag/Luggage Store"},"shop/bakery":{"icon":"bakery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"bakery"},"name":"Bakery"},"shop/bathroom_furnishing":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"bathroom_furnishing"},"name":"Bathroom Furnishing Store"},"shop/beauty":{"icon":"shop","fields":["operator","address","building_area","opening_hours","beauty"],"geometry":["point","area"],"terms":["spa","salon","tanning"],"tags":{"shop":"beauty"},"name":"Beauty Shop"},"shop/beauty/nails":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["manicure","pedicure"],"tags":{"shop":"beauty","beauty":"nails"},"reference":{"key":"shop","value":"beauty"},"name":"Nail Salon"},"shop/beauty/tanning":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"beauty","beauty":"tanning"},"reference":{"key":"leisure","value":"tanning_salon"},"name":"Tanning Salon"},"shop/bed":{"icon":"lodging","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"bed"},"name":"Bedding/Mattress Store"},"shop/beverages":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"beverages"},"name":"Beverage Store"},"shop/bicycle":{"icon":"bicycle","fields":["operator","address","building_area","opening_hours","service/bicycle"],"geometry":["point","area"],"terms":["bike","repair"],"tags":{"shop":"bicycle"},"name":"Bicycle Shop"},"shop/bookmaker":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["betting"],"tags":{"shop":"bookmaker"},"name":"Bookmaker"},"shop/books":{"icon":"shop","fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"shop":"books"},"name":"Book Store"},"shop/boutique":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"boutique"},"name":"Boutique"},"shop/butcher":{"icon":"slaughterhouse","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["meat"],"tags":{"shop":"butcher"},"name":"Butcher"},"shop/candles":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"candles"},"name":"Candle Shop"},"shop/car_parts":{"icon":"car","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["auto"],"tags":{"shop":"car_parts"},"name":"Car Parts Store"},"shop/car_repair":{"icon":"car","fields":["operator","address","building_area","opening_hours","service/vehicle"],"geometry":["point","area"],"terms":["auto","garage","service"],"tags":{"shop":"car_repair"},"name":"Car Repair Shop"},"shop/car":{"icon":"car","fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"geometry":["point","area"],"terms":["auto"],"tags":{"shop":"car"},"name":"Car Dealership"},"shop/carpet":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["rug"],"tags":{"shop":"carpet"},"name":"Carpet Store"},"shop/charity":{"icon":"shop","fields":["operator","address","building_area","opening_hours","second_hand"],"geometry":["point","area"],"terms":["thrift","op shop","nonprofit"],"tags":{"shop":"charity"},"name":"Charity Store"},"shop/cheese":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"cheese"},"name":"Cheese Store"},"shop/chemist":{"icon":"grocery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"chemist"},"terms":["med*","drug*","gift"],"name":"Drugstore"},"shop/chocolate":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"chocolate"},"name":"Chocolate Store"},"shop/clothes":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"clothes"},"name":"Clothing Store"},"shop/coffee":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"coffee"},"name":"Coffee Store"},"shop/computer":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"computer"},"name":"Computer Store"},"shop/confectionery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"confectionery"},"name":"Candy Store"},"shop/convenience":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"convenience"},"name":"Convenience Store"},"shop/copyshop":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"copyshop"},"name":"Copy Store"},"shop/cosmetics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"cosmetics"},"name":"Cosmetics Store"},"shop/craft":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"craft"},"terms":["art*","paint*","frame"],"name":"Arts and Crafts Store"},"shop/curtain":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["drape*","window"],"tags":{"shop":"curtain"},"name":"Curtain Store"},"shop/dairy":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["milk","egg","cheese"],"tags":{"shop":"dairy"},"name":"Dairy Store"},"shop/deli":{"icon":"restaurant","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["lunch","meat","sandwich"],"tags":{"shop":"deli"},"name":"Deli"},"shop/department_store":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"department_store"},"name":"Department Store"},"shop/doityourself":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"doityourself"},"name":"DIY Store"},"shop/dry_cleaning":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"dry_cleaning"},"name":"Dry Cleaner"},"shop/e-cigarette":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"e-cigarette"},"terms":["electronic","vapor"],"name":"E-Cigarette Shop"},"shop/electronics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["appliance","audio","computer","tv"],"tags":{"shop":"electronics"},"name":"Electronics Store"},"shop/erotic":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["sex","porn"],"tags":{"shop":"erotic"},"name":"Erotic Store"},"shop/fabric":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["sew"],"tags":{"shop":"fabric"},"name":"Fabric Store"},"shop/farm":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["farm shop","farm stand"],"tags":{"shop":"farm"},"name":"Produce Stand"},"shop/fashion":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"fashion"},"name":"Fashion Store"},"shop/florist":{"icon":"florist","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["flower"],"tags":{"shop":"florist"},"name":"Florist"},"shop/frame":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"frame"},"terms":["art*","paint*","photo*","frame"],"name":"Framing Shop"},"shop/funeral_directors":{"icon":"cemetery","fields":["operator","address","building_area","religion","denomination"],"geometry":["point","area"],"terms":["undertaker","memorial home"],"tags":{"shop":"funeral_directors"},"name":"Funeral Home"},"shop/furnace":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["oven","stove"],"tags":{"shop":"furnace"},"name":"Furnace Store"},"shop/furniture":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["chair","sofa","table"],"tags":{"shop":"furniture"},"name":"Furniture Store"},"shop/garden_centre":{"icon":"garden-center","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["landscape","mulch","shrub","tree"],"tags":{"shop":"garden_centre"},"name":"Garden Center"},"shop/gas":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["cng","lpg","natural gas","propane","refill","tank"],"tags":{"shop":"gas"},"name":"Bottled Gas Shop"},"shop/gift":{"icon":"gift","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["souvenir"],"tags":{"shop":"gift"},"name":"Gift Shop"},"shop/greengrocer":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["fruit","vegetable"],"tags":{"shop":"greengrocer"},"name":"Greengrocer"},"shop/hairdresser":{"icon":"hairdresser","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["barber"],"tags":{"shop":"hairdresser"},"name":"Hairdresser"},"shop/hardware":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"hardware"},"name":"Hardware Store"},"shop/hearing_aids":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"hearing_aids"},"name":"Hearing Aids Store"},"shop/herbalist":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"herbalist"},"name":"Herbalist"},"shop/hifi":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["stereo","video"],"tags":{"shop":"hifi"},"name":"Hifi Store"},"shop/houseware":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["home","household"],"tags":{"shop":"houseware"},"name":"Houseware Store"},"shop/interior_decoration":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"interior_decoration"},"name":"Interior Decoration Store"},"shop/jewelry":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["diamond","gem","ring"],"tags":{"shop":"jewelry"},"name":"Jeweler"},"shop/kiosk":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"kiosk"},"name":"News Kiosk"},"shop/kitchen":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"kitchen"},"name":"Kitchen Design Store"},"shop/laundry":{"icon":"laundry","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"laundry"},"name":"Laundry"},"shop/leather":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"leather"},"name":"Leather Store"},"shop/locksmith":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["key","lockpick"],"tags":{"shop":"locksmith"},"name":"Locksmith"},"shop/lottery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"lottery"},"name":"Lottery Shop"},"shop/mall":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["shopping"],"tags":{"shop":"mall"},"name":"Mall"},"shop/massage":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"massage"},"name":"Massage Shop"},"shop/medical_supply":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"medical_supply"},"name":"Medical Supply Store"},"shop/mobile_phone":{"icon":"mobile-phone","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"mobile_phone"},"name":"Mobile Phone Store"},"shop/money_lender":{"icon":"bank","fields":["operator","address","building_area","opening_hours","currency_multi"],"geometry":["point","area"],"tags":{"shop":"money_lender"},"name":"Money Lender"},"shop/motorcycle":{"icon":"scooter","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["bike"],"tags":{"shop":"motorcycle"},"name":"Motorcycle Dealership"},"shop/music":{"icon":"music","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["CD","vinyl"],"tags":{"shop":"music"},"name":"Music Store"},"shop/musical_instrument":{"icon":"music","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["guitar"],"tags":{"shop":"musical_instrument"},"name":"Musical Instrument Store"},"shop/newsagent":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"newsagent"},"name":"Newspaper/Magazine Shop"},"shop/nutrition_supplements":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"nutrition_supplements"},"name":"Nutrition Supplements Store"},"shop/optician":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["eye","glasses"],"tags":{"shop":"optician"},"name":"Optician"},"shop/organic":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"supermarket","organic":"only"},"name":"Organic Goods Store"},"shop/outdoor":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["camping","climbing","hiking"],"tags":{"shop":"outdoor"},"name":"Outdoors Store"},"shop/paint":{"icon":"water","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"paint"},"name":"Paint Store"},"shop/pastry":{"icon":"bakery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"pastry"},"terms":["patisserie","cake shop","cakery"],"name":"Pastry Shop"},"shop/pawnbroker":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"pawnbroker"},"name":"Pawn Shop"},"shop/perfumery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"perfumery"},"name":"Perfume Store"},"shop/pet":{"icon":"dog-park","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["animal","cat","dog","fish","kitten","puppy","reptile"],"tags":{"shop":"pet"},"name":"Pet Store"},"shop/photo":{"icon":"attraction","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["camera","film"],"tags":{"shop":"photo"},"name":"Photography Store"},"shop/pyrotechnics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"pyrotechnics"},"name":"Fireworks Store"},"shop/radiotechnics":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"radiotechnics"},"name":"Radio/Electronic Component Store"},"shop/religion":{"icon":"shop","fields":["operator","address","building_area","opening_hours","religion","denomination"],"geometry":["point","area"],"tags":{"shop":"religion"},"name":"Religious Store"},"shop/scuba_diving":{"icon":"swimming","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"scuba_diving"},"name":"Scuba Diving Shop"},"shop/seafood":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["fishmonger"],"tags":{"shop":"seafood"},"name":"Seafood Shop"},"shop/second_hand":{"icon":"shop","fields":["operator","address","building_area","opening_hours","second_hand"],"geometry":["point","area"],"terms":["secondhand","second hand","resale","thrift","used"],"tags":{"shop":"second_hand"},"name":"Consignment/Thrift Store"},"shop/shoes":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"shoes"},"name":"Shoe Store"},"shop/sports":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"sports"},"name":"Sporting Goods Store"},"shop/stationery":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["card","paper"],"tags":{"shop":"stationery"},"name":"Stationery Store"},"shop/storage_rental":{"icon":"shop","fields":["operator","address","building","opening_hours"],"geometry":["point","area"],"tags":{"shop":"storage_rental"},"name":"Storage Rental"},"shop/supermarket":{"icon":"grocery","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["grocery","store","shop"],"tags":{"shop":"supermarket"},"name":"Supermarket"},"shop/tailor":{"icon":"clothing-store","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["clothes","suit"],"tags":{"shop":"tailor"},"name":"Tailor"},"shop/tattoo":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"tattoo"},"name":"Tattoo Parlor"},"shop/tea":{"icon":"teahouse","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"tea"},"name":"Tea Store"},"shop/ticket":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"ticket"},"name":"Ticket Seller"},"shop/tobacco":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"tobacco"},"name":"Tobacco Shop"},"shop/toys":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"toys"},"name":"Toy Store"},"shop/travel_agency":{"icon":"suitcase","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"travel_agency"},"name":"Travel Agency"},"shop/tyres":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"tyres"},"name":"Tire Store"},"shop/vacuum_cleaner":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"vacuum_cleaner"},"name":"Vacuum Cleaner Store"},"shop/variety_store":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"variety_store"},"name":"Variety Store"},"shop/video_games":{"icon":"gaming","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"video_games"},"name":"Video Game Store"},"shop/video":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["DVD"],"tags":{"shop":"video"},"name":"Video Store"},"shop/watches":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"watches"},"name":"Watches Shop"},"shop/water_sports":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"water_sports"},"name":"Watersport/Swim Shop"},"shop/weapons":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["ammo","gun","knife","knives"],"tags":{"shop":"weapons"},"name":"Weapon Shop"},"shop/window_blind":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"window_blind"},"name":"Window Blind Store"},"shop/wine":{"icon":"alcohol-shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"shop":"wine"},"name":"Wine Shop"},"tourism":{"icon":"attraction","fields":["tourism"],"geometry":["point","vertex","area"],"tags":{"tourism":"*"},"name":"Tourism"},"tourism/alpine_hut":{"icon":"lodging","fields":["operator","address","building_area","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"alpine_hut"},"name":"Alpine Hut"},"tourism/apartment":{"icon":"lodging","fields":["operator","address","building_area","smoking","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"apartment"},"name":"Guest Apartment / Condo"},"tourism/aquarium":{"icon":"aquarium","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["fish","sea","water"],"tags":{"tourism":"aquarium"},"name":"Aquarium"},"tourism/artwork":{"icon":"art-gallery","fields":["artwork_type","artist"],"geometry":["point","vertex","area"],"tags":{"tourism":"artwork"},"terms":["mural","sculpture","statue"],"name":"Artwork"},"tourism/attraction":{"icon":"monument","fields":["operator","address"],"geometry":["point","vertex","area"],"tags":{"tourism":"attraction"},"name":"Tourist Attraction"},"tourism/camp_site":{"icon":"campsite","fields":["operator","address","capacity","fee","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"terms":["tent","rv"],"tags":{"tourism":"camp_site"},"name":"Campground"},"tourism/caravan_site":{"icon":"bus","fields":["operator","address","capacity","fee","sanitary_dump_station","power_supply","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","vertex","area"],"terms":["Motor Home","Camper"],"tags":{"tourism":"caravan_site"},"name":"RV Park"},"tourism/chalet":{"icon":"lodging","fields":["operator","address","building_area","smoking","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"chalet"},"name":"Chalet"},"tourism/gallery":{"icon":"art-gallery","fields":["artwork_type","operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["art*","exhibit*","paint*","photo*","sculpt*"],"tags":{"tourism":"gallery"},"name":"Art Gallery"},"tourism/guest_house":{"icon":"lodging","fields":["operator","address","building_area","smoking","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"guest_house"},"terms":["B&B","Bed and Breakfast"],"name":"Guest House"},"tourism/hostel":{"icon":"lodging","fields":["operator","address","building_area","smoking","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"hostel"},"name":"Hostel"},"tourism/hotel":{"icon":"lodging","fields":["operator","address","building_area","smoking","stars","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"hotel"},"name":"Hotel"},"tourism/information":{"icon":"information","fields":["information","operator","address","building_area"],"geometry":["point","vertex","area"],"tags":{"tourism":"information"},"name":"Information"},"tourism/information/board":{"icon":"information","fields":["operator","board_type"],"geometry":["point","vertex"],"tags":{"tourism":"information","information":"board"},"reference":{"key":"information","value":"board"},"name":"Information Board"},"tourism/information/guidepost":{"icon":"information","fields":["operator","ref"],"geometry":["point","vertex"],"tags":{"tourism":"information","information":"guidepost"},"reference":{"key":"information","value":"guidepost"},"name":"Guidepost"},"tourism/information/map":{"icon":"information","fields":["operator","map_type","map_size"],"geometry":["point","vertex"],"tags":{"tourism":"information","information":"map"},"reference":{"key":"information","value":"map"},"name":"Map"},"tourism/information/office":{"icon":"information","fields":["operator","address","building_area"],"geometry":["point","vertex","area"],"tags":{"tourism":"information","information":"office"},"reference":{"key":"information","value":"office"},"name":"Tourist Information Office"},"tourism/motel":{"icon":"lodging","fields":["operator","address","building_area","smoking","rooms","internet_access","internet_access/fee","internet_access/ssid"],"geometry":["point","area"],"tags":{"tourism":"motel"},"name":"Motel"},"tourism/museum":{"icon":"museum","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["art*","exhibit*","gallery","foundation","hall","institution","paint*","photo*","sculpt*"],"tags":{"tourism":"museum"},"name":"Museum"},"tourism/picnic_site":{"icon":"picnic-site","fields":["operator","address","smoking"],"geometry":["point","vertex","area"],"terms":["camp"],"tags":{"tourism":"picnic_site"},"name":"Picnic Site"},"tourism/theme_park":{"icon":"amusement-park","fields":["operator","address","opening_hours"],"geometry":["point","area"],"tags":{"tourism":"theme_park"},"name":"Theme Park"},"tourism/viewpoint":{"icon":"poi-binoculars","geometry":["point","vertex"],"tags":{"tourism":"viewpoint"},"name":"Viewpoint"},"tourism/zoo":{"icon":"zoo","fields":["operator","address","opening_hours"],"geometry":["point","area"],"terms":["animal"],"tags":{"tourism":"zoo"},"name":"Zoo"},"traffic_calming":{"icon":"poi-warning","fields":["traffic_calming","parallel_direction"],"geometry":["vertex","line"],"tags":{"traffic_calming":"*"},"terms":["bump","hump","slow","speed"],"name":"Traffic Calming"},"traffic_calming/bump":{"icon":"poi-warning","fields":["surface","parallel_direction"],"geometry":["vertex","line"],"terms":["hump","speed","slow"],"tags":{"traffic_calming":"bump"},"name":"Speed Bump"},"traffic_calming/chicane":{"icon":"poi-warning","fields":["parallel_direction"],"geometry":["vertex","line"],"terms":["driveway link","speed","slow"],"tags":{"traffic_calming":"chicane"},"name":"Traffic Chicane"},"traffic_calming/choker":{"icon":"poi-warning","fields":["parallel_direction"],"geometry":["vertex","line"],"terms":["speed","slow"],"tags":{"traffic_calming":"choker"},"name":"Traffic Choker"},"traffic_calming/cushion":{"icon":"poi-warning","fields":["surface","parallel_direction"],"geometry":["vertex","line"],"terms":["bump","hump","speed","slow"],"tags":{"traffic_calming":"cushion"},"name":"Speed Cushion"},"traffic_calming/dip":{"icon":"poi-warning","fields":["surface","parallel_direction"],"geometry":["vertex","line"],"terms":["speed","slow"],"tags":{"traffic_calming":"dip"},"name":"Dip"},"traffic_calming/hump":{"icon":"poi-warning","fields":["surface","parallel_direction"],"geometry":["vertex","line"],"terms":["bump","speed","slow"],"tags":{"traffic_calming":"hump"},"name":"Speed Hump"},"traffic_calming/island":{"icon":"poi-warning","geometry":["vertex"],"terms":["circle","roundabout","slow"],"tags":{"traffic_calming":"island"},"name":"Traffic Island"},"traffic_calming/rumble_strip":{"icon":"poi-warning","fields":["parallel_direction"],"geometry":["vertex","line"],"terms":["audible lines","sleeper lines","growlers"],"tags":{"traffic_calming":"rumble_strip"},"name":"Rumble Strip"},"traffic_calming/table":{"icon":"poi-warning","fields":["surface"],"geometry":["vertex","line"],"terms":["flat top","hump","speed","slow"],"tags":{"highway":"crossing","traffic_calming":"table"},"name":"Raised Pedestrian Crossing"},"type/multipolygon":{"geometry":["area","relation"],"tags":{"type":"multipolygon"},"removeTags":{},"name":"Multipolygon","icon":"multipolygon","searchable":false,"matchScore":0.1},"type/boundary":{"geometry":["relation"],"tags":{"type":"boundary"},"name":"Boundary","icon":"boundary","fields":["boundary"]},"type/boundary/administrative":{"icon":"boundary","fields":["admin_level"],"geometry":["relation"],"tags":{"type":"boundary","boundary":"administrative"},"reference":{"key":"boundary","value":"administrative"},"name":"Administrative Boundary"},"type/restriction":{"geometry":["relation"],"tags":{"type":"restriction"},"name":"Restriction","icon":"restriction","fields":["restriction","except"]},"type/restriction/no_left_turn":{"name":"No Left Turn","geometry":["relation"],"tags":{"type":"restriction","restriction":"no_left_turn"},"fields":["except"],"icon":"restriction-no-left-turn"},"type/restriction/no_right_turn":{"name":"No Right Turn","geometry":["relation"],"tags":{"type":"restriction","restriction":"no_right_turn"},"fields":["except"],"icon":"restriction-no-right-turn"},"type/restriction/no_straight_on":{"name":"No Straight On","geometry":["relation"],"tags":{"type":"restriction","restriction":"no_straight_on"},"fields":["except"],"icon":"restriction-no-straight-on"},"type/restriction/no_u_turn":{"name":"No U-turn","geometry":["relation"],"tags":{"type":"restriction","restriction":"no_u_turn"},"fields":["except"],"icon":"restriction-no-u-turn"},"type/restriction/only_left_turn":{"name":"Left Turn Only","geometry":["relation"],"tags":{"type":"restriction","restriction":"only_left_turn"},"fields":["except"],"icon":"restriction-only-left-turn"},"type/restriction/only_right_turn":{"name":"Right Turn Only","geometry":["relation"],"tags":{"type":"restriction","restriction":"only_right_turn"},"fields":["except"],"icon":"restriction-only-right-turn"},"type/restriction/only_straight_on":{"name":"No Turns","geometry":["relation"],"tags":{"type":"restriction","restriction":"only_straight_on"},"fields":["except"],"icon":"restriction-only-straight-on"},"type/route_master":{"geometry":["relation"],"tags":{"type":"route_master"},"name":"Route Master","icon":"route-master","fields":["route_master","ref","operator","network"]},"type/route":{"geometry":["relation"],"tags":{"type":"route"},"name":"Route","icon":"route","fields":["route","ref","operator","network"]},"type/route/bicycle":{"geometry":["relation"],"tags":{"type":"route","route":"bicycle"},"name":"Cycle Route","icon":"route-bicycle","fields":["ref","network_bicycle","cycle_network"]},"type/route/bus":{"geometry":["relation"],"tags":{"type":"route","route":"bus"},"name":"Bus Route","icon":"route-bus","fields":["ref","operator","network"]},"type/route/detour":{"geometry":["relation"],"tags":{"type":"route","route":"detour"},"name":"Detour Route","icon":"route-detour","fields":["ref"]},"type/route/ferry":{"geometry":["relation"],"tags":{"type":"route","route":"ferry"},"name":"Ferry Route","icon":"route-ferry","fields":["ref","operator","network"]},"type/route/foot":{"geometry":["relation"],"tags":{"type":"route","route":"foot"},"name":"Foot Route","icon":"route-foot","fields":["ref","operator","network_foot"]},"type/route/hiking":{"geometry":["relation"],"tags":{"type":"route","route":"hiking"},"name":"Hiking Route","icon":"route-foot","fields":["ref","operator","network_foot"]},"type/route/horse":{"geometry":["relation"],"tags":{"type":"route","route":"horse"},"name":"Riding Route","icon":"route-horse","fields":["ref","operator","network_horse"]},"type/route/pipeline":{"geometry":["relation"],"tags":{"type":"route","route":"pipeline"},"name":"Pipeline Route","icon":"route-pipeline","fields":["ref","operator"]},"type/route/power":{"geometry":["relation"],"tags":{"type":"route","route":"power"},"name":"Power Route","icon":"route-power","fields":["ref","operator"]},"type/route/road":{"geometry":["relation"],"tags":{"type":"route","route":"road"},"name":"Road Route","icon":"route-road","fields":["ref","network_road"]},"type/route/train":{"geometry":["relation"],"tags":{"type":"route","route":"train"},"name":"Train Route","icon":"route-train","fields":["ref","operator","network"]},"type/route/tram":{"geometry":["relation"],"tags":{"type":"route","route":"tram"},"name":"Tram Route","icon":"route-tram","fields":["ref","operator","network"]},"type/site":{"geometry":["relation"],"tags":{"type":"site"},"name":"Site","icon":"relation","fields":["site"]},"vertex":{"name":"Other","tags":{},"geometry":["vertex"],"matchScore":0.1},"waterway/boatyard":{"icon":"harbor","fields":["operator"],"geometry":["area","vertex","point"],"tags":{"waterway":"boatyard"},"name":"Boatyard"},"waterway/canal":{"icon":"waterway-canal","fields":["width"],"geometry":["line"],"tags":{"waterway":"canal"},"name":"Canal"},"waterway/dam":{"icon":"dam","geometry":["point","vertex","line","area"],"tags":{"waterway":"dam"},"name":"Dam"},"waterway/ditch":{"icon":"waterway-ditch","fields":["tunnel"],"geometry":["line"],"tags":{"waterway":"ditch"},"name":"Ditch"},"waterway/dock":{"icon":"harbor","fields":["dock","operator"],"geometry":["area","vertex","point"],"terms":["boat","ship","vessel","marine"],"tags":{"waterway":"dock"},"name":"Wet Dock / Dry Dock"},"waterway/drain":{"icon":"waterway-stream","fields":["tunnel"],"geometry":["line"],"tags":{"waterway":"drain"},"name":"Drain"},"waterway/fuel":{"icon":"fuel","fields":["operator","address","opening_hours","fuel_multi"],"geometry":["point","area"],"terms":["petrol","gas","diesel","boat"],"tags":{"waterway":"fuel"},"name":"Marine Fuel Station"},"waterway/river":{"icon":"waterway-river","fields":["tunnel","width"],"geometry":["line"],"terms":["beck","branch","brook","course","creek","estuary","rill","rivulet","run","runnel","stream","tributary","watercourse"],"tags":{"waterway":"river"},"name":"River"},"waterway/riverbank":{"icon":"water","geometry":["area"],"tags":{"waterway":"riverbank"},"name":"Riverbank"},"waterway/sanitary_dump_station":{"icon":"poi-storage-tank","fields":["operator","access_toilets","fee","water_point"],"geometry":["point","vertex","area"],"terms":["Boat","Watercraft","Sanitary","Dump Station","Pumpout","Pump out","Elsan","CDP","CTDP","Chemical Toilet"],"tags":{"waterway":"sanitary_dump_station"},"name":"Marine Toilet Disposal"},"waterway/stream":{"icon":"waterway-stream","fields":["tunnel","width"],"geometry":["line"],"terms":["beck","branch","brook","burn","course","creek","current","drift","flood","flow","freshet","race","rill","rindle","rivulet","run","runnel","rush","spate","spritz","surge","tide","torrent","tributary","watercourse"],"tags":{"waterway":"stream"},"name":"Stream"},"waterway/water_point":{"icon":"drinking-water","geometry":["area","vertex","point"],"tags":{"waterway":"water_point"},"name":"Marine Drinking Water"},"waterway/waterfall":{"icon":"water","fields":["height","width"],"geometry":["vertex"],"terms":["fall"],"tags":{"waterway":"waterfall"},"name":"Waterfall"},"waterway/weir":{"icon":"dam","geometry":["vertex","line"],"tags":{"waterway":"weir"},"name":"Weir"},"amenity/fuel/76":{"tags":{"name":"76","amenity":"fuel"},"name":"76","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Neste":{"tags":{"name":"Neste","amenity":"fuel"},"name":"Neste","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/BP":{"tags":{"name":"BP","amenity":"fuel"},"name":"BP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Shell":{"tags":{"name":"Shell","amenity":"fuel"},"name":"Shell","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Agip":{"tags":{"name":"Agip","amenity":"fuel"},"name":"Agip","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Migrol":{"tags":{"name":"Migrol","amenity":"fuel"},"name":"Migrol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Avia":{"tags":{"name":"Avia","amenity":"fuel"},"name":"Avia","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Texaco":{"tags":{"name":"Texaco","amenity":"fuel"},"name":"Texaco","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Total":{"tags":{"name":"Total","amenity":"fuel"},"name":"Total","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Statoil":{"tags":{"name":"Statoil","amenity":"fuel"},"name":"Statoil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Esso":{"tags":{"name":"Esso","amenity":"fuel"},"name":"Esso","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Jet":{"tags":{"name":"Jet","amenity":"fuel"},"name":"Jet","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Avanti":{"tags":{"name":"Avanti","amenity":"fuel"},"name":"Avanti","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OMV":{"tags":{"name":"OMV","amenity":"fuel"},"name":"OMV","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Aral":{"tags":{"name":"Aral","amenity":"fuel"},"name":"Aral","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/JET":{"tags":{"name":"JET","amenity":"fuel"},"name":"JET","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/United":{"tags":{"name":"United","amenity":"fuel"},"name":"United","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Mobil":{"tags":{"name":"Mobil","amenity":"fuel"},"name":"Mobil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Caltex":{"tags":{"name":"Caltex","amenity":"fuel"},"name":"Caltex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sunoco":{"tags":{"name":"Sunoco","amenity":"fuel"},"name":"Sunoco","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Q8":{"tags":{"name":"Q8","amenity":"fuel"},"name":"Q8","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ARAL":{"tags":{"name":"ARAL","amenity":"fuel"},"name":"ARAL","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/CEPSA":{"tags":{"name":"CEPSA","amenity":"fuel"},"name":"CEPSA","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/BFT":{"tags":{"name":"BFT","amenity":"fuel"},"name":"BFT","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petron":{"tags":{"name":"Petron","amenity":"fuel"},"name":"Petron","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Total Access":{"tags":{"name":"Total Access","amenity":"fuel"},"name":"Total Access","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Elf":{"tags":{"name":"Elf","amenity":"fuel"},"name":"Elf","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Station Service E. Leclerc":{"tags":{"name":"Station Service E. Leclerc","amenity":"fuel"},"name":"Station Service E. Leclerc","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Shell Express":{"tags":{"name":"Shell Express","amenity":"fuel"},"name":"Shell Express","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Hess":{"tags":{"name":"Hess","amenity":"fuel"},"name":"Hess","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Flying V":{"tags":{"name":"Flying V","amenity":"fuel"},"name":"Flying V","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/bft":{"tags":{"name":"bft","amenity":"fuel"},"name":"bft","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Gulf":{"tags":{"name":"Gulf","amenity":"fuel"},"name":"Gulf","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/PTT":{"tags":{"name":"PTT","amenity":"fuel"},"name":"PTT","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/St1":{"tags":{"name":"St1","amenity":"fuel"},"name":"St1","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Teboil":{"tags":{"name":"Teboil","amenity":"fuel"},"name":"Teboil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/HEM":{"tags":{"name":"HEM","amenity":"fuel"},"name":"HEM","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/GALP":{"tags":{"name":"GALP","amenity":"fuel"},"name":"GALP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OK":{"tags":{"name":"OK","amenity":"fuel"},"name":"OK","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ÖMV":{"tags":{"name":"ÖMV","amenity":"fuel"},"name":"ÖMV","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Tinq":{"tags":{"name":"Tinq","amenity":"fuel"},"name":"Tinq","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OKQ8":{"tags":{"name":"OKQ8","amenity":"fuel"},"name":"OKQ8","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Repsol":{"tags":{"name":"Repsol","amenity":"fuel"},"name":"Repsol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Westfalen":{"tags":{"name":"Westfalen","amenity":"fuel"},"name":"Westfalen","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Esso Express":{"tags":{"name":"Esso Express","amenity":"fuel"},"name":"Esso Express","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Tamoil":{"tags":{"name":"Tamoil","amenity":"fuel"},"name":"Tamoil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Engen":{"tags":{"name":"Engen","amenity":"fuel"},"name":"Engen","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sasol":{"tags":{"name":"Sasol","amenity":"fuel"},"name":"Sasol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Topaz":{"tags":{"name":"Topaz","amenity":"fuel"},"name":"Topaz","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/LPG":{"tags":{"name":"LPG","amenity":"fuel"},"name":"LPG","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Orlen":{"tags":{"name":"Orlen","amenity":"fuel"},"name":"Orlen","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Oilibya":{"tags":{"name":"Oilibya","amenity":"fuel"},"name":"Oilibya","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Tango":{"tags":{"name":"Tango","amenity":"fuel"},"name":"Tango","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Star":{"tags":{"name":"Star","amenity":"fuel"},"name":"Star","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Петрол":{"tags":{"name":"Петрол","amenity":"fuel"},"name":"Петрол","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Cepsa":{"tags":{"name":"Cepsa","amenity":"fuel"},"name":"Cepsa","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OIL!":{"tags":{"name":"OIL!","amenity":"fuel"},"name":"OIL!","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Ultramar":{"tags":{"name":"Ultramar","amenity":"fuel"},"name":"Ultramar","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Irving":{"tags":{"name":"Irving","amenity":"fuel"},"name":"Irving","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Lukoil":{"tags":{"name":"Lukoil","amenity":"fuel"},"name":"Lukoil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petro-Canada":{"tags":{"name":"Petro-Canada","amenity":"fuel"},"name":"Petro-Canada","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Agrola":{"tags":{"name":"Agrola","amenity":"fuel"},"name":"Agrola","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Husky":{"tags":{"name":"Husky","amenity":"fuel"},"name":"Husky","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Slovnaft":{"tags":{"name":"Slovnaft","amenity":"fuel"},"name":"Slovnaft","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sheetz":{"tags":{"name":"Sheetz","amenity":"fuel"},"name":"Sheetz","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Mol":{"tags":{"name":"Mol","amenity":"fuel"},"name":"Mol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petronas":{"tags":{"name":"Petronas","amenity":"fuel"},"name":"Petronas","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Газпромнефть":{"tags":{"name":"Газпромнефть","amenity":"fuel"},"name":"Газпромнефть","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Лукойл":{"tags":{"name":"Лукойл","amenity":"fuel"},"name":"Лукойл","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Elan":{"tags":{"name":"Elan","amenity":"fuel"},"name":"Elan","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Роснефть":{"tags":{"name":"Роснефть","amenity":"fuel"},"name":"Роснефть","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Turmöl":{"tags":{"name":"Turmöl","amenity":"fuel"},"name":"Turmöl","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Neste A24":{"tags":{"name":"Neste A24","amenity":"fuel"},"name":"Neste A24","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Marathon":{"tags":{"name":"Marathon","amenity":"fuel"},"name":"Marathon","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Valero":{"tags":{"name":"Valero","amenity":"fuel"},"name":"Valero","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Eni":{"tags":{"name":"Eni","amenity":"fuel"},"name":"Eni","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Chevron":{"tags":{"name":"Chevron","amenity":"fuel"},"name":"Chevron","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ТНК":{"tags":{"name":"ТНК","amenity":"fuel"},"name":"ТНК","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/REPSOL":{"tags":{"name":"REPSOL","amenity":"fuel"},"name":"REPSOL","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/MOL":{"tags":{"name":"MOL","amenity":"fuel"},"name":"MOL","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Bliska":{"tags":{"name":"Bliska","amenity":"fuel"},"name":"Bliska","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Api":{"tags":{"name":"Api","amenity":"fuel"},"name":"Api","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Arco":{"tags":{"name":"Arco","amenity":"fuel"},"name":"Arco","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Pemex":{"tags":{"name":"Pemex","amenity":"fuel"},"name":"Pemex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Exxon":{"tags":{"name":"Exxon","amenity":"fuel"},"name":"Exxon","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Coles Express":{"tags":{"name":"Coles Express","amenity":"fuel"},"name":"Coles Express","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petrom":{"tags":{"name":"Petrom","amenity":"fuel"},"name":"Petrom","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/PETRONOR":{"tags":{"name":"PETRONOR","amenity":"fuel"},"name":"PETRONOR","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Rompetrol":{"tags":{"name":"Rompetrol","amenity":"fuel"},"name":"Rompetrol","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Lotos":{"tags":{"name":"Lotos","amenity":"fuel"},"name":"Lotos","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ОМВ":{"tags":{"name":"ОМВ","amenity":"fuel"},"name":"ОМВ","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/BR":{"tags":{"name":"BR","amenity":"fuel"},"name":"BR","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Copec":{"tags":{"name":"Copec","amenity":"fuel"},"name":"Copec","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petrobras":{"tags":{"name":"Petrobras","amenity":"fuel"},"name":"Petrobras","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Liberty":{"tags":{"name":"Liberty","amenity":"fuel"},"name":"Liberty","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/IP":{"tags":{"name":"IP","amenity":"fuel"},"name":"IP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Erg":{"tags":{"name":"Erg","amenity":"fuel"},"name":"Erg","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Eneos":{"tags":{"name":"Eneos","amenity":"fuel"},"name":"Eneos","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Citgo":{"tags":{"name":"Citgo","amenity":"fuel"},"name":"Citgo","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Metano":{"tags":{"name":"Metano","amenity":"fuel"},"name":"Metano","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Сургутнефтегаз":{"tags":{"name":"Сургутнефтегаз","amenity":"fuel"},"name":"Сургутнефтегаз","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/EKO":{"tags":{"name":"EKO","amenity":"fuel"},"name":"EKO","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Eko":{"tags":{"name":"Eko","amenity":"fuel"},"name":"Eko","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Indipend.":{"tags":{"name":"Indipend.","amenity":"fuel"},"name":"Indipend.","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/IES":{"tags":{"name":"IES","amenity":"fuel"},"name":"IES","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/TotalErg":{"tags":{"name":"TotalErg","amenity":"fuel"},"name":"TotalErg","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Cenex":{"tags":{"name":"Cenex","amenity":"fuel"},"name":"Cenex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ПТК":{"tags":{"name":"ПТК","amenity":"fuel"},"name":"ПТК","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/HP":{"tags":{"name":"HP","amenity":"fuel"},"name":"HP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Phillips 66":{"tags":{"name":"Phillips 66","amenity":"fuel"},"name":"Phillips 66","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/CARREFOUR":{"tags":{"name":"CARREFOUR","amenity":"fuel"},"name":"CARREFOUR","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ERG":{"tags":{"name":"ERG","amenity":"fuel"},"name":"ERG","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Speedway":{"tags":{"name":"Speedway","amenity":"fuel"},"name":"Speedway","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Benzina":{"tags":{"name":"Benzina","amenity":"fuel"},"name":"Benzina","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Татнефть":{"tags":{"name":"Татнефть","amenity":"fuel"},"name":"Татнефть","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Terpel":{"tags":{"name":"Terpel","amenity":"fuel"},"name":"Terpel","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/WOG":{"tags":{"name":"WOG","amenity":"fuel"},"name":"WOG","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Seaoil":{"tags":{"name":"Seaoil","amenity":"fuel"},"name":"Seaoil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/АЗС":{"tags":{"name":"АЗС","amenity":"fuel"},"name":"АЗС","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Kwik Trip":{"tags":{"name":"Kwik Trip","amenity":"fuel"},"name":"Kwik Trip","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Pertamina":{"tags":{"name":"Pertamina","amenity":"fuel"},"name":"Pertamina","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/COSMO":{"tags":{"name":"COSMO","amenity":"fuel"},"name":"COSMO","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Z":{"tags":{"name":"Z","amenity":"fuel"},"name":"Z","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Indian Oil":{"tags":{"name":"Indian Oil","amenity":"fuel"},"name":"Indian Oil","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/АГЗС":{"tags":{"name":"АГЗС","amenity":"fuel"},"name":"АГЗС","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/INA":{"tags":{"name":"INA","amenity":"fuel"},"name":"INA","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/JOMO":{"tags":{"name":"JOMO","amenity":"fuel"},"name":"JOMO","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Holiday":{"tags":{"name":"Holiday","amenity":"fuel"},"name":"Holiday","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/YPF":{"tags":{"name":"YPF","amenity":"fuel"},"name":"YPF","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/IDEMITSU":{"tags":{"name":"IDEMITSU","amenity":"fuel"},"name":"IDEMITSU","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ENEOS":{"tags":{"name":"ENEOS","amenity":"fuel"},"name":"ENEOS","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Bharat Petroleum":{"tags":{"name":"Bharat Petroleum","amenity":"fuel"},"name":"Bharat Petroleum","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/CAMPSA":{"tags":{"name":"CAMPSA","amenity":"fuel"},"name":"CAMPSA","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Casey's General Store":{"tags":{"name":"Casey's General Store","amenity":"fuel"},"name":"Casey's General Store","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Башнефть":{"tags":{"name":"Башнефть","amenity":"fuel"},"name":"Башнефть","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Kangaroo":{"tags":{"name":"Kangaroo","amenity":"fuel"},"name":"Kangaroo","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/コスモ石油 (COSMO)":{"tags":{"name":"コスモ石油 (COSMO)","amenity":"fuel"},"name":"コスモ石油 (COSMO)","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/MEROIL":{"tags":{"name":"MEROIL","amenity":"fuel"},"name":"MEROIL","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/1-2-3":{"tags":{"name":"1-2-3","amenity":"fuel"},"name":"1-2-3","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/出光":{"tags":{"name":"出光","name:en":"IDEMITSU","amenity":"fuel"},"name":"出光","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/НК Альянс":{"tags":{"name":"НК Альянс","amenity":"fuel"},"name":"НК Альянс","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sinclair":{"tags":{"name":"Sinclair","amenity":"fuel"},"name":"Sinclair","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Conoco":{"tags":{"name":"Conoco","amenity":"fuel"},"name":"Conoco","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/SPBU":{"tags":{"name":"SPBU","amenity":"fuel"},"name":"SPBU","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Макпетрол":{"tags":{"name":"Макпетрол","amenity":"fuel"},"name":"Макпетрол","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Posto Ipiranga":{"tags":{"name":"Posto Ipiranga","amenity":"fuel"},"name":"Posto Ipiranga","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Posto Shell":{"tags":{"name":"Posto Shell","amenity":"fuel"},"name":"Posto Shell","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Phoenix":{"tags":{"name":"Phoenix","amenity":"fuel"},"name":"Phoenix","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Ipiranga":{"tags":{"name":"Ipiranga","amenity":"fuel"},"name":"Ipiranga","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/OKKO":{"tags":{"name":"OKKO","amenity":"fuel"},"name":"OKKO","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ОККО":{"tags":{"name":"ОККО","amenity":"fuel"},"name":"ОККО","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/บางจาก":{"tags":{"name":"บางจาก","amenity":"fuel"},"name":"บางจาก","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/QuikTrip":{"tags":{"name":"QuikTrip","amenity":"fuel"},"name":"QuikTrip","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Posto BR":{"tags":{"name":"Posto BR","amenity":"fuel"},"name":"Posto BR","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ป ต ท":{"tags":{"name":"ป ต ท","amenity":"fuel"},"name":"ป ต ท","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ปตท":{"tags":{"name":"ปตท","amenity":"fuel"},"name":"ปตท","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/ANP":{"tags":{"name":"ANP","amenity":"fuel"},"name":"ANP","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Kum & Go":{"tags":{"name":"Kum & Go","amenity":"fuel"},"name":"Kum & Go","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Petrolimex":{"tags":{"name":"Petrolimex","amenity":"fuel"},"name":"Petrolimex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Sokimex":{"tags":{"name":"Sokimex","amenity":"fuel"},"name":"Sokimex","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Tela":{"tags":{"name":"Tela","amenity":"fuel"},"name":"Tela","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Posto":{"tags":{"name":"Posto","amenity":"fuel"},"name":"Posto","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Укрнафта":{"tags":{"name":"Укрнафта","amenity":"fuel"},"name":"Укрнафта","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Татнефтепродукт":{"tags":{"name":"Татнефтепродукт","amenity":"fuel"},"name":"Татнефтепродукт","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Afriquia":{"tags":{"name":"Afriquia","amenity":"fuel"},"name":"Afriquia","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/Murphy USA":{"tags":{"name":"Murphy USA","amenity":"fuel"},"name":"Murphy USA","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/昭和シェル (Showa-shell)":{"tags":{"name":"昭和シェル (Showa-shell)","amenity":"fuel"},"name":"昭和シェル (Showa-shell)","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/エネオス":{"tags":{"name":"エネオス","amenity":"fuel"},"name":"エネオス","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/fuel/CNG":{"tags":{"name":"CNG","amenity":"fuel"},"name":"CNG","icon":"fuel","geometry":["point","area"],"fields":["operator","address","opening_hours","fuel_multi"],"suggestion":true},"amenity/pub/Kings Arms":{"tags":{"name":"Kings Arms","amenity":"pub"},"name":"Kings Arms","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Ship":{"tags":{"name":"The Ship","amenity":"pub"},"name":"The Ship","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The White Horse":{"tags":{"name":"The White Horse","amenity":"pub"},"name":"The White Horse","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The White Hart":{"tags":{"name":"The White Hart","amenity":"pub"},"name":"The White Hart","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Royal Oak":{"tags":{"name":"Royal Oak","amenity":"pub"},"name":"Royal Oak","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Red Lion":{"tags":{"name":"The Red Lion","amenity":"pub"},"name":"The Red Lion","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Kings Arms":{"tags":{"name":"The Kings Arms","amenity":"pub"},"name":"The Kings Arms","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Star":{"tags":{"name":"The Star","amenity":"pub"},"name":"The Star","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Anchor":{"tags":{"name":"The Anchor","amenity":"pub"},"name":"The Anchor","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Cross Keys":{"tags":{"name":"The Cross Keys","amenity":"pub"},"name":"The Cross Keys","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Wheatsheaf":{"tags":{"name":"The Wheatsheaf","amenity":"pub"},"name":"The Wheatsheaf","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Crown Inn":{"tags":{"name":"The Crown Inn","amenity":"pub"},"name":"The Crown Inn","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Kings Head":{"tags":{"name":"The Kings Head","amenity":"pub"},"name":"The Kings Head","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Castle":{"tags":{"name":"The Castle","amenity":"pub"},"name":"The Castle","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Railway":{"tags":{"name":"The Railway","amenity":"pub"},"name":"The Railway","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The White Lion":{"tags":{"name":"The White Lion","amenity":"pub"},"name":"The White Lion","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Bell":{"tags":{"name":"The Bell","amenity":"pub"},"name":"The Bell","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Bull":{"tags":{"name":"The Bull","amenity":"pub"},"name":"The Bull","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Plough":{"tags":{"name":"The Plough","amenity":"pub"},"name":"The Plough","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The George":{"tags":{"name":"The George","amenity":"pub"},"name":"The George","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Royal Oak":{"tags":{"name":"The Royal Oak","amenity":"pub"},"name":"The Royal Oak","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Fox":{"tags":{"name":"The Fox","amenity":"pub"},"name":"The Fox","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Prince of Wales":{"tags":{"name":"Prince of Wales","amenity":"pub"},"name":"Prince of Wales","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Rising Sun":{"tags":{"name":"The Rising Sun","amenity":"pub"},"name":"The Rising Sun","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Prince of Wales":{"tags":{"name":"The Prince of Wales","amenity":"pub"},"name":"The Prince of Wales","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Crown":{"tags":{"name":"The Crown","amenity":"pub"},"name":"The Crown","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Chequers":{"tags":{"name":"The Chequers","amenity":"pub"},"name":"The Chequers","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Swan":{"tags":{"name":"The Swan","amenity":"pub"},"name":"The Swan","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Rose and Crown":{"tags":{"name":"Rose and Crown","amenity":"pub"},"name":"Rose and Crown","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Victoria":{"tags":{"name":"The Victoria","amenity":"pub"},"name":"The Victoria","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/New Inn":{"tags":{"name":"New Inn","amenity":"pub"},"name":"New Inn","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Royal Hotel":{"tags":{"name":"Royal Hotel","amenity":"pub"},"name":"Royal Hotel","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Red Lion":{"tags":{"name":"Red Lion","amenity":"pub"},"name":"Red Lion","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Cross Keys":{"tags":{"name":"Cross Keys","amenity":"pub"},"name":"Cross Keys","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Greyhound":{"tags":{"name":"The Greyhound","amenity":"pub"},"name":"The Greyhound","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Black Horse":{"tags":{"name":"The Black Horse","amenity":"pub"},"name":"The Black Horse","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The New Inn":{"tags":{"name":"The New Inn","amenity":"pub"},"name":"The New Inn","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Kings Head":{"tags":{"name":"Kings Head","amenity":"pub"},"name":"Kings Head","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Albion":{"tags":{"name":"The Albion","amenity":"pub"},"name":"The Albion","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Angel":{"tags":{"name":"The Angel","amenity":"pub"},"name":"The Angel","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Queens Head":{"tags":{"name":"The Queens Head","amenity":"pub"},"name":"The Queens Head","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/The Ship Inn":{"tags":{"name":"The Ship Inn","amenity":"pub"},"name":"The Ship Inn","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Rose & Crown":{"tags":{"name":"Rose & Crown","amenity":"pub"},"name":"Rose & Crown","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Queens Head":{"tags":{"name":"Queens Head","amenity":"pub"},"name":"Queens Head","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/pub/Irish Pub":{"tags":{"name":"Irish Pub","amenity":"pub"},"name":"Irish Pub","icon":"beer","geometry":["point","area"],"fields":["address","building_area","opening_hours","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Quick":{"tags":{"name":"Quick","amenity":"fast_food"},"name":"Quick","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/McDonald's":{"tags":{"name":"McDonald's","cuisine":"burger","amenity":"fast_food"},"name":"McDonald's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Subway":{"tags":{"name":"Subway","cuisine":"sandwich","amenity":"fast_food"},"name":"Subway","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Burger King":{"tags":{"name":"Burger King","cuisine":"burger","amenity":"fast_food"},"name":"Burger King","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Ali Baba":{"tags":{"name":"Ali Baba","amenity":"fast_food"},"name":"Ali Baba","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Hungry Jacks":{"tags":{"name":"Hungry Jacks","cuisine":"burger","amenity":"fast_food"},"name":"Hungry Jacks","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Red Rooster":{"tags":{"name":"Red Rooster","amenity":"fast_food"},"name":"Red Rooster","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/KFC":{"tags":{"name":"KFC","cuisine":"chicken","amenity":"fast_food"},"name":"KFC","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Domino's Pizza":{"tags":{"name":"Domino's Pizza","cuisine":"pizza","amenity":"fast_food"},"name":"Domino's Pizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Chowking":{"tags":{"name":"Chowking","amenity":"fast_food"},"name":"Chowking","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Jollibee":{"tags":{"name":"Jollibee","amenity":"fast_food"},"name":"Jollibee","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Hesburger":{"tags":{"name":"Hesburger","amenity":"fast_food"},"name":"Hesburger","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/肯德基":{"tags":{"name":"肯德基","amenity":"fast_food"},"name":"肯德基","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Wendy's":{"tags":{"name":"Wendy's","cuisine":"burger","amenity":"fast_food"},"name":"Wendy's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Tim Hortons":{"tags":{"name":"Tim Hortons","amenity":"fast_food"},"name":"Tim Hortons","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Steers":{"tags":{"name":"Steers","amenity":"fast_food"},"name":"Steers","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Hardee's":{"tags":{"name":"Hardee's","cuisine":"burger","amenity":"fast_food"},"name":"Hardee's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Arby's":{"tags":{"name":"Arby's","amenity":"fast_food"},"name":"Arby's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/A&W":{"tags":{"name":"A&W","amenity":"fast_food"},"name":"A&W","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Dairy Queen":{"tags":{"name":"Dairy Queen","amenity":"fast_food"},"name":"Dairy Queen","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Hallo Pizza":{"tags":{"name":"Hallo Pizza","amenity":"fast_food"},"name":"Hallo Pizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Fish & Chips":{"tags":{"name":"Fish & Chips","amenity":"fast_food"},"name":"Fish & Chips","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Harvey's":{"tags":{"name":"Harvey's","amenity":"fast_food"},"name":"Harvey's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/麥當勞":{"tags":{"name":"麥當勞","amenity":"fast_food"},"name":"麥當勞","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Pizza Pizza":{"tags":{"name":"Pizza Pizza","amenity":"fast_food"},"name":"Pizza Pizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Kotipizza":{"tags":{"name":"Kotipizza","amenity":"fast_food"},"name":"Kotipizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Jack in the Box":{"tags":{"name":"Jack in the Box","cuisine":"burger","amenity":"fast_food"},"name":"Jack in the Box","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Istanbul":{"tags":{"name":"Istanbul","amenity":"fast_food"},"name":"Istanbul","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Kochlöffel":{"tags":{"name":"Kochlöffel","amenity":"fast_food"},"name":"Kochlöffel","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Döner":{"tags":{"name":"Döner","amenity":"fast_food"},"name":"Döner","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Telepizza":{"tags":{"name":"Telepizza","amenity":"fast_food"},"name":"Telepizza","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Sibylla":{"tags":{"name":"Sibylla","amenity":"fast_food"},"name":"Sibylla","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Carl's Jr.":{"tags":{"name":"Carl's Jr.","cuisine":"burger","amenity":"fast_food"},"name":"Carl's Jr.","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Quiznos":{"tags":{"name":"Quiznos","cuisine":"sandwich","amenity":"fast_food"},"name":"Quiznos","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Wimpy":{"tags":{"name":"Wimpy","amenity":"fast_food"},"name":"Wimpy","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Sonic":{"tags":{"name":"Sonic","cuisine":"burger","amenity":"fast_food"},"name":"Sonic","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Taco Bell":{"tags":{"name":"Taco Bell","cuisine":"mexican","amenity":"fast_food"},"name":"Taco Bell","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Pizza Nova":{"tags":{"name":"Pizza Nova","amenity":"fast_food"},"name":"Pizza Nova","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Papa John's":{"tags":{"name":"Papa John's","cuisine":"pizza","amenity":"fast_food"},"name":"Papa John's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Nordsee":{"tags":{"name":"Nordsee","amenity":"fast_food"},"name":"Nordsee","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Mr. Sub":{"tags":{"name":"Mr. Sub","amenity":"fast_food"},"name":"Mr. Sub","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Макдоналдс":{"tags":{"name":"Макдоналдс","name:en":"McDonald's","amenity":"fast_food"},"name":"Макдоналдс","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Asia Imbiss":{"tags":{"name":"Asia Imbiss","amenity":"fast_food"},"name":"Asia Imbiss","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Chipotle":{"tags":{"name":"Chipotle","cuisine":"mexican","amenity":"fast_food"},"name":"Chipotle","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/マクドナルド":{"tags":{"name":"マクドナルド","name:en":"McDonald's","cuisine":"burger","amenity":"fast_food"},"name":"マクドナルド","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/In-N-Out Burger":{"tags":{"name":"In-N-Out Burger","amenity":"fast_food"},"name":"In-N-Out Burger","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Jimmy John's":{"tags":{"name":"Jimmy John's","amenity":"fast_food"},"name":"Jimmy John's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Jamba Juice":{"tags":{"name":"Jamba Juice","amenity":"fast_food"},"name":"Jamba Juice","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Робин Сдобин":{"tags":{"name":"Робин Сдобин","amenity":"fast_food"},"name":"Робин Сдобин","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Baskin Robbins":{"tags":{"name":"Baskin Robbins","amenity":"fast_food"},"name":"Baskin Robbins","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/ケンタッキーフライドチキン":{"tags":{"name":"ケンタッキーフライドチキン","name:en":"KFC","cuisine":"chicken","amenity":"fast_food"},"name":"ケンタッキーフライドチキン","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/吉野家":{"tags":{"name":"吉野家","amenity":"fast_food"},"name":"吉野家","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Taco Time":{"tags":{"name":"Taco Time","amenity":"fast_food"},"name":"Taco Time","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/松屋":{"tags":{"name":"松屋","name:en":"Matsuya","amenity":"fast_food"},"name":"松屋","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Little Caesars":{"tags":{"name":"Little Caesars","amenity":"fast_food"},"name":"Little Caesars","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/El Pollo Loco":{"tags":{"name":"El Pollo Loco","amenity":"fast_food"},"name":"El Pollo Loco","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Del Taco":{"tags":{"name":"Del Taco","amenity":"fast_food"},"name":"Del Taco","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/White Castle":{"tags":{"name":"White Castle","amenity":"fast_food"},"name":"White Castle","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Boston Market":{"tags":{"name":"Boston Market","amenity":"fast_food"},"name":"Boston Market","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Chick-fil-A":{"tags":{"name":"Chick-fil-A","cuisine":"chicken","amenity":"fast_food"},"name":"Chick-fil-A","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Panda Express":{"tags":{"name":"Panda Express","cuisine":"chinese","amenity":"fast_food"},"name":"Panda Express","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Whataburger":{"tags":{"name":"Whataburger","amenity":"fast_food"},"name":"Whataburger","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Taco John's":{"tags":{"name":"Taco John's","amenity":"fast_food"},"name":"Taco John's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Теремок":{"tags":{"name":"Теремок","amenity":"fast_food"},"name":"Теремок","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Culver's":{"tags":{"name":"Culver's","amenity":"fast_food"},"name":"Culver's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Five Guys":{"tags":{"name":"Five Guys","amenity":"fast_food"},"name":"Five Guys","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Church's Chicken":{"tags":{"name":"Church's Chicken","amenity":"fast_food"},"name":"Church's Chicken","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Popeye's":{"tags":{"name":"Popeye's","cuisine":"chicken","amenity":"fast_food"},"name":"Popeye's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Long John Silver's":{"tags":{"name":"Long John Silver's","amenity":"fast_food"},"name":"Long John Silver's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Pollo Campero":{"tags":{"name":"Pollo Campero","amenity":"fast_food"},"name":"Pollo Campero","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Zaxby's":{"tags":{"name":"Zaxby's","amenity":"fast_food"},"name":"Zaxby's","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/すき家":{"tags":{"name":"すき家","name:en":"SUKIYA","amenity":"fast_food"},"name":"すき家","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/モスバーガー":{"tags":{"name":"モスバーガー","name:en":"MOS BURGER","amenity":"fast_food"},"name":"モスバーガー","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/Русский Аппетит":{"tags":{"name":"Русский Аппетит","amenity":"fast_food"},"name":"Русский Аппетит","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/fast_food/なか卯":{"tags":{"name":"なか卯","amenity":"fast_food"},"name":"なか卯","icon":"fast-food","geometry":["point","area"],"fields":["cuisine","operator","address","building_area","opening_hours","takeaway","delivery","drive_through","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Pizza Hut":{"tags":{"name":"Pizza Hut","cuisine":"pizza","amenity":"restaurant"},"name":"Pizza Hut","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Little Chef":{"tags":{"name":"Little Chef","amenity":"restaurant"},"name":"Little Chef","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Adler":{"tags":{"name":"Adler","amenity":"restaurant"},"name":"Adler","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zur Krone":{"tags":{"name":"Zur Krone","amenity":"restaurant"},"name":"Zur Krone","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Deutsches Haus":{"tags":{"name":"Deutsches Haus","amenity":"restaurant"},"name":"Deutsches Haus","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Krone":{"tags":{"name":"Krone","amenity":"restaurant"},"name":"Krone","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Akropolis":{"tags":{"name":"Akropolis","amenity":"restaurant"},"name":"Akropolis","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Schützenhaus":{"tags":{"name":"Schützenhaus","amenity":"restaurant"},"name":"Schützenhaus","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Kreuz":{"tags":{"name":"Kreuz","amenity":"restaurant"},"name":"Kreuz","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Waldschänke":{"tags":{"name":"Waldschänke","amenity":"restaurant"},"name":"Waldschänke","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Piazza":{"tags":{"name":"La Piazza","amenity":"restaurant"},"name":"La Piazza","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Lamm":{"tags":{"name":"Lamm","amenity":"restaurant"},"name":"Lamm","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zur Sonne":{"tags":{"name":"Zur Sonne","amenity":"restaurant"},"name":"Zur Sonne","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zur Linde":{"tags":{"name":"Zur Linde","amenity":"restaurant"},"name":"Zur Linde","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Poseidon":{"tags":{"name":"Poseidon","amenity":"restaurant"},"name":"Poseidon","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Shanghai":{"tags":{"name":"Shanghai","amenity":"restaurant"},"name":"Shanghai","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Red Lobster":{"tags":{"name":"Red Lobster","amenity":"restaurant"},"name":"Red Lobster","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zum Löwen":{"tags":{"name":"Zum Löwen","amenity":"restaurant"},"name":"Zum Löwen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Swiss Chalet":{"tags":{"name":"Swiss Chalet","amenity":"restaurant"},"name":"Swiss Chalet","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Olympia":{"tags":{"name":"Olympia","amenity":"restaurant"},"name":"Olympia","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Wagamama":{"tags":{"name":"Wagamama","amenity":"restaurant"},"name":"Wagamama","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Frankie & Benny's":{"tags":{"name":"Frankie & Benny's","amenity":"restaurant"},"name":"Frankie & Benny's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hooters":{"tags":{"name":"Hooters","amenity":"restaurant"},"name":"Hooters","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sternen":{"tags":{"name":"Sternen","amenity":"restaurant"},"name":"Sternen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hirschen":{"tags":{"name":"Hirschen","amenity":"restaurant"},"name":"Hirschen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Denny's":{"tags":{"name":"Denny's","amenity":"restaurant"},"name":"Denny's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Athen":{"tags":{"name":"Athen","amenity":"restaurant"},"name":"Athen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sonne":{"tags":{"name":"Sonne","amenity":"restaurant"},"name":"Sonne","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hirsch":{"tags":{"name":"Hirsch","amenity":"restaurant"},"name":"Hirsch","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Ratskeller":{"tags":{"name":"Ratskeller","amenity":"restaurant"},"name":"Ratskeller","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Cantina":{"tags":{"name":"La Cantina","amenity":"restaurant"},"name":"La Cantina","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Gasthaus Krone":{"tags":{"name":"Gasthaus Krone","amenity":"restaurant"},"name":"Gasthaus Krone","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/El Greco":{"tags":{"name":"El Greco","amenity":"restaurant"},"name":"El Greco","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Gasthof zur Post":{"tags":{"name":"Gasthof zur Post","amenity":"restaurant"},"name":"Gasthof zur Post","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Nando's":{"tags":{"name":"Nando's","amenity":"restaurant"},"name":"Nando's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Löwen":{"tags":{"name":"Löwen","amenity":"restaurant"},"name":"Löwen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Pataterie":{"tags":{"name":"La Pataterie","amenity":"restaurant"},"name":"La Pataterie","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Bella Napoli":{"tags":{"name":"Bella Napoli","amenity":"restaurant"},"name":"Bella Napoli","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Pizza Express":{"tags":{"name":"Pizza Express","amenity":"restaurant"},"name":"Pizza Express","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mandarin":{"tags":{"name":"Mandarin","amenity":"restaurant"},"name":"Mandarin","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hong Kong":{"tags":{"name":"Hong Kong","amenity":"restaurant"},"name":"Hong Kong","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zizzi":{"tags":{"name":"Zizzi","amenity":"restaurant"},"name":"Zizzi","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Cracker Barrel":{"tags":{"name":"Cracker Barrel","amenity":"restaurant"},"name":"Cracker Barrel","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Rhodos":{"tags":{"name":"Rhodos","amenity":"restaurant"},"name":"Rhodos","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Lindenhof":{"tags":{"name":"Lindenhof","amenity":"restaurant"},"name":"Lindenhof","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Milano":{"tags":{"name":"Milano","amenity":"restaurant"},"name":"Milano","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Dolce Vita":{"tags":{"name":"Dolce Vita","amenity":"restaurant"},"name":"Dolce Vita","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Kirchenwirt":{"tags":{"name":"Kirchenwirt","amenity":"restaurant"},"name":"Kirchenwirt","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Kantine":{"tags":{"name":"Kantine","amenity":"restaurant"},"name":"Kantine","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Ochsen":{"tags":{"name":"Ochsen","amenity":"restaurant"},"name":"Ochsen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Spur":{"tags":{"name":"Spur","amenity":"restaurant"},"name":"Spur","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mykonos":{"tags":{"name":"Mykonos","amenity":"restaurant"},"name":"Mykonos","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Lotus":{"tags":{"name":"Lotus","amenity":"restaurant"},"name":"Lotus","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Applebee's":{"tags":{"name":"Applebee's","amenity":"restaurant"},"name":"Applebee's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Flunch":{"tags":{"name":"Flunch","amenity":"restaurant"},"name":"Flunch","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Zur Post":{"tags":{"name":"Zur Post","amenity":"restaurant"},"name":"Zur Post","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/China Town":{"tags":{"name":"China Town","amenity":"restaurant"},"name":"China Town","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Dolce Vita":{"tags":{"name":"La Dolce Vita","amenity":"restaurant"},"name":"La Dolce Vita","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Waffle House":{"tags":{"name":"Waffle House","amenity":"restaurant"},"name":"Waffle House","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Delphi":{"tags":{"name":"Delphi","amenity":"restaurant"},"name":"Delphi","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Linde":{"tags":{"name":"Linde","amenity":"restaurant"},"name":"Linde","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Outback Steakhouse":{"tags":{"name":"Outback Steakhouse","amenity":"restaurant"},"name":"Outback Steakhouse","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Dionysos":{"tags":{"name":"Dionysos","amenity":"restaurant"},"name":"Dionysos","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Kelsey's":{"tags":{"name":"Kelsey's","amenity":"restaurant"},"name":"Kelsey's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Boston Pizza":{"tags":{"name":"Boston Pizza","amenity":"restaurant"},"name":"Boston Pizza","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Bella Italia":{"tags":{"name":"Bella Italia","amenity":"restaurant"},"name":"Bella Italia","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sizzler":{"tags":{"name":"Sizzler","amenity":"restaurant"},"name":"Sizzler","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Grüner Baum":{"tags":{"name":"Grüner Baum","amenity":"restaurant"},"name":"Grüner Baum","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Taj Mahal":{"tags":{"name":"Taj Mahal","amenity":"restaurant"},"name":"Taj Mahal","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Rössli":{"tags":{"name":"Rössli","amenity":"restaurant"},"name":"Rössli","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Traube":{"tags":{"name":"Traube","amenity":"restaurant"},"name":"Traube","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Adria":{"tags":{"name":"Adria","amenity":"restaurant"},"name":"Adria","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Red Robin":{"tags":{"name":"Red Robin","amenity":"restaurant"},"name":"Red Robin","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Roma":{"tags":{"name":"Roma","amenity":"restaurant"},"name":"Roma","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/San Marco":{"tags":{"name":"San Marco","amenity":"restaurant"},"name":"San Marco","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hellas":{"tags":{"name":"Hellas","amenity":"restaurant"},"name":"Hellas","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Perla":{"tags":{"name":"La Perla","amenity":"restaurant"},"name":"La Perla","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Vips":{"tags":{"name":"Vips","amenity":"restaurant"},"name":"Vips","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Panera Bread":{"tags":{"name":"Panera Bread","amenity":"restaurant"},"name":"Panera Bread","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Da Vinci":{"tags":{"name":"Da Vinci","amenity":"restaurant"},"name":"Da Vinci","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hippopotamus":{"tags":{"name":"Hippopotamus","amenity":"restaurant"},"name":"Hippopotamus","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Prezzo":{"tags":{"name":"Prezzo","amenity":"restaurant"},"name":"Prezzo","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Courtepaille":{"tags":{"name":"Courtepaille","amenity":"restaurant"},"name":"Courtepaille","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Hard Rock Cafe":{"tags":{"name":"Hard Rock Cafe","amenity":"restaurant"},"name":"Hard Rock Cafe","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Panorama":{"tags":{"name":"Panorama","amenity":"restaurant"},"name":"Panorama","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/デニーズ":{"tags":{"name":"デニーズ","amenity":"restaurant"},"name":"デニーズ","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sportheim":{"tags":{"name":"Sportheim","amenity":"restaurant"},"name":"Sportheim","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/餃子の王将":{"tags":{"name":"餃子の王将","amenity":"restaurant"},"name":"餃子の王将","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Bären":{"tags":{"name":"Bären","amenity":"restaurant"},"name":"Bären","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Alte Post":{"tags":{"name":"Alte Post","amenity":"restaurant"},"name":"Alte Post","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Pizzeria Roma":{"tags":{"name":"Pizzeria Roma","amenity":"restaurant"},"name":"Pizzeria Roma","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/China Garden":{"tags":{"name":"China Garden","amenity":"restaurant"},"name":"China Garden","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Vapiano":{"tags":{"name":"Vapiano","amenity":"restaurant"},"name":"Vapiano","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mamma Mia":{"tags":{"name":"Mamma Mia","amenity":"restaurant"},"name":"Mamma Mia","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Schwarzer Adler":{"tags":{"name":"Schwarzer Adler","amenity":"restaurant"},"name":"Schwarzer Adler","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/IHOP":{"tags":{"name":"IHOP","amenity":"restaurant"},"name":"IHOP","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Chili's":{"tags":{"name":"Chili's","amenity":"restaurant"},"name":"Chili's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Asia":{"tags":{"name":"Asia","amenity":"restaurant"},"name":"Asia","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Olive Garden":{"tags":{"name":"Olive Garden","amenity":"restaurant"},"name":"Olive Garden","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/TGI Friday's":{"tags":{"name":"TGI Friday's","amenity":"restaurant"},"name":"TGI Friday's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Friendly's":{"tags":{"name":"Friendly's","amenity":"restaurant"},"name":"Friendly's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Buffalo Grill":{"tags":{"name":"Buffalo Grill","amenity":"restaurant"},"name":"Buffalo Grill","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Texas Roadhouse":{"tags":{"name":"Texas Roadhouse","amenity":"restaurant"},"name":"Texas Roadhouse","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/ガスト":{"tags":{"name":"ガスト","name:en":"Gusto","amenity":"restaurant"},"name":"ガスト","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Sakura":{"tags":{"name":"Sakura","amenity":"restaurant"},"name":"Sakura","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mensa":{"tags":{"name":"Mensa","amenity":"restaurant"},"name":"Mensa","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/The Keg":{"tags":{"name":"The Keg","amenity":"restaurant"},"name":"The Keg","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/サイゼリヤ":{"tags":{"name":"サイゼリヤ","amenity":"restaurant"},"name":"サイゼリヤ","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/La Strada":{"tags":{"name":"La Strada","amenity":"restaurant"},"name":"La Strada","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Village Inn":{"tags":{"name":"Village Inn","amenity":"restaurant"},"name":"Village Inn","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Buffalo Wild Wings":{"tags":{"name":"Buffalo Wild Wings","amenity":"restaurant"},"name":"Buffalo Wild Wings","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Peking":{"tags":{"name":"Peking","amenity":"restaurant"},"name":"Peking","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Round Table Pizza":{"tags":{"name":"Round Table Pizza","amenity":"restaurant"},"name":"Round Table Pizza","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/California Pizza Kitchen":{"tags":{"name":"California Pizza Kitchen","amenity":"restaurant"},"name":"California Pizza Kitchen","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Якитория":{"tags":{"name":"Якитория","amenity":"restaurant"},"name":"Якитория","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Golden Corral":{"tags":{"name":"Golden Corral","amenity":"restaurant"},"name":"Golden Corral","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Perkins":{"tags":{"name":"Perkins","amenity":"restaurant"},"name":"Perkins","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Ruby Tuesday":{"tags":{"name":"Ruby Tuesday","amenity":"restaurant"},"name":"Ruby Tuesday","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Shari's":{"tags":{"name":"Shari's","amenity":"restaurant"},"name":"Shari's","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Bob Evans":{"tags":{"name":"Bob Evans","amenity":"restaurant"},"name":"Bob Evans","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/바다횟집 (Bada Fish Restaurant)":{"tags":{"name":"바다횟집 (Bada Fish Restaurant)","amenity":"restaurant"},"name":"바다횟집 (Bada Fish Restaurant)","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Mang Inasal":{"tags":{"name":"Mang Inasal","amenity":"restaurant"},"name":"Mang Inasal","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Евразия":{"tags":{"name":"Евразия","amenity":"restaurant"},"name":"Евразия","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/ジョナサン":{"tags":{"name":"ジョナサン","amenity":"restaurant"},"name":"ジョナサン","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/restaurant/Longhorn Steakhouse":{"tags":{"name":"Longhorn Steakhouse","amenity":"restaurant"},"name":"Longhorn Steakhouse","icon":"restaurant","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","capacity","takeaway","delivery","smoking","outdoor_seating"],"suggestion":true},"amenity/bank/Chase":{"tags":{"name":"Chase","amenity":"bank"},"name":"Chase","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Commonwealth Bank":{"tags":{"name":"Commonwealth Bank","amenity":"bank"},"name":"Commonwealth Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Citibank":{"tags":{"name":"Citibank","amenity":"bank"},"name":"Citibank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/HSBC":{"tags":{"name":"HSBC","amenity":"bank"},"name":"HSBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Barclays":{"tags":{"name":"Barclays","amenity":"bank"},"name":"Barclays","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Westpac":{"tags":{"name":"Westpac","amenity":"bank"},"name":"Westpac","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/NAB":{"tags":{"name":"NAB","amenity":"bank"},"name":"NAB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ANZ":{"tags":{"name":"ANZ","amenity":"bank"},"name":"ANZ","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Lloyds Bank":{"tags":{"name":"Lloyds Bank","amenity":"bank"},"name":"Lloyds Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Landbank":{"tags":{"name":"Landbank","amenity":"bank"},"name":"Landbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sparkasse":{"tags":{"name":"Sparkasse","amenity":"bank"},"name":"Sparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/UCPB":{"tags":{"name":"UCPB","amenity":"bank"},"name":"UCPB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PNB":{"tags":{"name":"PNB","amenity":"bank"},"name":"PNB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Metrobank":{"tags":{"name":"Metrobank","amenity":"bank"},"name":"Metrobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BDO":{"tags":{"name":"BDO","amenity":"bank"},"name":"BDO","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Volksbank":{"tags":{"name":"Volksbank","amenity":"bank"},"name":"Volksbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BPI":{"tags":{"name":"BPI","amenity":"bank"},"name":"BPI","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Postbank":{"tags":{"name":"Postbank","amenity":"bank"},"name":"Postbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/NatWest":{"tags":{"name":"NatWest","amenity":"bank"},"name":"NatWest","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Raiffeisenbank":{"tags":{"name":"Raiffeisenbank","amenity":"bank"},"name":"Raiffeisenbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Yorkshire Bank":{"tags":{"name":"Yorkshire Bank","amenity":"bank"},"name":"Yorkshire Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ABSA":{"tags":{"name":"ABSA","amenity":"bank"},"name":"ABSA","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Standard Bank":{"tags":{"name":"Standard Bank","amenity":"bank"},"name":"Standard Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/FNB":{"tags":{"name":"FNB","amenity":"bank"},"name":"FNB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Deutsche Bank":{"tags":{"name":"Deutsche Bank","amenity":"bank"},"name":"Deutsche Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/SEB":{"tags":{"name":"SEB","amenity":"bank"},"name":"SEB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Commerzbank":{"tags":{"name":"Commerzbank","amenity":"bank"},"name":"Commerzbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Targobank":{"tags":{"name":"Targobank","amenity":"bank"},"name":"Targobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ABN AMRO":{"tags":{"name":"ABN AMRO","amenity":"bank"},"name":"ABN AMRO","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Handelsbanken":{"tags":{"name":"Handelsbanken","amenity":"bank"},"name":"Handelsbanken","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Swedbank":{"tags":{"name":"Swedbank","amenity":"bank"},"name":"Swedbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Kreissparkasse":{"tags":{"name":"Kreissparkasse","amenity":"bank"},"name":"Kreissparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/UniCredit Bank":{"tags":{"name":"UniCredit Bank","amenity":"bank"},"name":"UniCredit Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Monte dei Paschi di Siena":{"tags":{"name":"Monte dei Paschi di Siena","amenity":"bank"},"name":"Monte dei Paschi di Siena","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja Rural":{"tags":{"name":"Caja Rural","amenity":"bank"},"name":"Caja Rural","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Dresdner Bank":{"tags":{"name":"Dresdner Bank","amenity":"bank"},"name":"Dresdner Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sparda-Bank":{"tags":{"name":"Sparda-Bank","amenity":"bank"},"name":"Sparda-Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/VÚB":{"tags":{"name":"VÚB","amenity":"bank"},"name":"VÚB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Slovenská sporiteľňa":{"tags":{"name":"Slovenská sporiteľňa","amenity":"bank"},"name":"Slovenská sporiteľňa","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of Montreal":{"tags":{"name":"Bank of Montreal","amenity":"bank"},"name":"Bank of Montreal","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/KBC":{"tags":{"name":"KBC","amenity":"bank"},"name":"KBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Royal Bank of Scotland":{"tags":{"name":"Royal Bank of Scotland","amenity":"bank"},"name":"Royal Bank of Scotland","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/TSB":{"tags":{"name":"TSB","amenity":"bank"},"name":"TSB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/US Bank":{"tags":{"name":"US Bank","amenity":"bank"},"name":"US Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/HypoVereinsbank":{"tags":{"name":"HypoVereinsbank","amenity":"bank"},"name":"HypoVereinsbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank Austria":{"tags":{"name":"Bank Austria","amenity":"bank"},"name":"Bank Austria","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ING":{"tags":{"name":"ING","amenity":"bank"},"name":"ING","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Erste Bank":{"tags":{"name":"Erste Bank","amenity":"bank"},"name":"Erste Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/CIBC":{"tags":{"name":"CIBC","amenity":"bank"},"name":"CIBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Scotiabank":{"tags":{"name":"Scotiabank","amenity":"bank"},"name":"Scotiabank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caisse d'Épargne":{"tags":{"name":"Caisse d'Épargne","amenity":"bank"},"name":"Caisse d'Épargne","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Santander":{"tags":{"name":"Santander","amenity":"bank"},"name":"Santander","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of Scotland":{"tags":{"name":"Bank of Scotland","amenity":"bank"},"name":"Bank of Scotland","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/TD Canada Trust":{"tags":{"name":"TD Canada Trust","amenity":"bank"},"name":"TD Canada Trust","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BMO":{"tags":{"name":"BMO","amenity":"bank"},"name":"BMO","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Danske Bank":{"tags":{"name":"Danske Bank","amenity":"bank"},"name":"Danske Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/OTP":{"tags":{"name":"OTP","amenity":"bank"},"name":"OTP","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Crédit Agricole":{"tags":{"name":"Crédit Agricole","amenity":"bank"},"name":"Crédit Agricole","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/LCL":{"tags":{"name":"LCL","amenity":"bank"},"name":"LCL","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/VR-Bank":{"tags":{"name":"VR-Bank","amenity":"bank"},"name":"VR-Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ČSOB":{"tags":{"name":"ČSOB","amenity":"bank"},"name":"ČSOB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Česká spořitelna":{"tags":{"name":"Česká spořitelna","amenity":"bank"},"name":"Česká spořitelna","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BNP":{"tags":{"name":"BNP","amenity":"bank"},"name":"BNP","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Royal Bank":{"tags":{"name":"Royal Bank","amenity":"bank"},"name":"Royal Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Nationwide":{"tags":{"name":"Nationwide","amenity":"bank"},"name":"Nationwide","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Halifax":{"tags":{"name":"Halifax","amenity":"bank"},"name":"Halifax","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BAWAG PSK":{"tags":{"name":"BAWAG PSK","amenity":"bank"},"name":"BAWAG PSK","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/National Bank":{"tags":{"name":"National Bank","amenity":"bank"},"name":"National Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Nedbank":{"tags":{"name":"Nedbank","amenity":"bank"},"name":"Nedbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/First National Bank":{"tags":{"name":"First National Bank","amenity":"bank"},"name":"First National Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Nordea":{"tags":{"name":"Nordea","amenity":"bank"},"name":"Nordea","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Rabobank":{"tags":{"name":"Rabobank","amenity":"bank"},"name":"Rabobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sparkasse KölnBonn":{"tags":{"name":"Sparkasse KölnBonn","amenity":"bank"},"name":"Sparkasse KölnBonn","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Tatra banka":{"tags":{"name":"Tatra banka","amenity":"bank"},"name":"Tatra banka","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Berliner Sparkasse":{"tags":{"name":"Berliner Sparkasse","amenity":"bank"},"name":"Berliner Sparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Berliner Volksbank":{"tags":{"name":"Berliner Volksbank","amenity":"bank"},"name":"Berliner Volksbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Wells Fargo":{"tags":{"name":"Wells Fargo","amenity":"bank"},"name":"Wells Fargo","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Credit Suisse":{"tags":{"name":"Credit Suisse","amenity":"bank"},"name":"Credit Suisse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Société Générale":{"tags":{"name":"Société Générale","amenity":"bank"},"name":"Société Générale","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Osuuspankki":{"tags":{"name":"Osuuspankki","amenity":"bank"},"name":"Osuuspankki","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sparkasse Aachen":{"tags":{"name":"Sparkasse Aachen","amenity":"bank"},"name":"Sparkasse Aachen","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Hamburger Sparkasse":{"tags":{"name":"Hamburger Sparkasse","amenity":"bank"},"name":"Hamburger Sparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Cassa di Risparmio del Veneto":{"tags":{"name":"Cassa di Risparmio del Veneto","amenity":"bank"},"name":"Cassa di Risparmio del Veneto","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BNP Paribas":{"tags":{"name":"BNP Paribas","amenity":"bank"},"name":"BNP Paribas","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banque Populaire":{"tags":{"name":"Banque Populaire","amenity":"bank"},"name":"Banque Populaire","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BNP Paribas Fortis":{"tags":{"name":"BNP Paribas Fortis","amenity":"bank"},"name":"BNP Paribas Fortis","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Popular":{"tags":{"name":"Banco Popular","amenity":"bank"},"name":"Banco Popular","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bancaja":{"tags":{"name":"Bancaja","amenity":"bank"},"name":"Bancaja","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banesto":{"tags":{"name":"Banesto","amenity":"bank"},"name":"Banesto","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/La Caixa":{"tags":{"name":"La Caixa","amenity":"bank"},"name":"La Caixa","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Santander Consumer Bank":{"tags":{"name":"Santander Consumer Bank","amenity":"bank"},"name":"Santander Consumer Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BRD":{"tags":{"name":"BRD","amenity":"bank"},"name":"BRD","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BCR":{"tags":{"name":"BCR","amenity":"bank"},"name":"BCR","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banca Transilvania":{"tags":{"name":"Banca Transilvania","amenity":"bank"},"name":"Banca Transilvania","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BW-Bank":{"tags":{"name":"BW-Bank","amenity":"bank"},"name":"BW-Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Komerční banka":{"tags":{"name":"Komerční banka","amenity":"bank"},"name":"Komerční banka","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Pastor":{"tags":{"name":"Banco Pastor","amenity":"bank"},"name":"Banco Pastor","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Stadtsparkasse":{"tags":{"name":"Stadtsparkasse","amenity":"bank"},"name":"Stadtsparkasse","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Ulster Bank":{"tags":{"name":"Ulster Bank","amenity":"bank"},"name":"Ulster Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Sberbank":{"tags":{"name":"Sberbank","amenity":"bank"},"name":"Sberbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/CIC":{"tags":{"name":"CIC","amenity":"bank"},"name":"CIC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bancpost":{"tags":{"name":"Bancpost","amenity":"bank"},"name":"Bancpost","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja Madrid":{"tags":{"name":"Caja Madrid","amenity":"bank"},"name":"Caja Madrid","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Maybank":{"tags":{"name":"Maybank","amenity":"bank"},"name":"Maybank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/中国银行":{"tags":{"name":"中国银行","amenity":"bank"},"name":"中国银行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Unicredit Banca":{"tags":{"name":"Unicredit Banca","amenity":"bank"},"name":"Unicredit Banca","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Crédit Mutuel":{"tags":{"name":"Crédit Mutuel","amenity":"bank"},"name":"Crédit Mutuel","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BBVA":{"tags":{"name":"BBVA","amenity":"bank"},"name":"BBVA","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Intesa San Paolo":{"tags":{"name":"Intesa San Paolo","amenity":"bank"},"name":"Intesa San Paolo","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/TD Bank":{"tags":{"name":"TD Bank","amenity":"bank"},"name":"TD Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Belfius":{"tags":{"name":"Belfius","amenity":"bank"},"name":"Belfius","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of America":{"tags":{"name":"Bank of America","amenity":"bank"},"name":"Bank of America","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/RBC":{"tags":{"name":"RBC","amenity":"bank"},"name":"RBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Alpha Bank":{"tags":{"name":"Alpha Bank","amenity":"bank"},"name":"Alpha Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Сбербанк":{"tags":{"name":"Сбербанк","amenity":"bank"},"name":"Сбербанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Россельхозбанк":{"tags":{"name":"Россельхозбанк","amenity":"bank"},"name":"Россельхозбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Crédit du Nord":{"tags":{"name":"Crédit du Nord","amenity":"bank"},"name":"Crédit du Nord","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BancoEstado":{"tags":{"name":"BancoEstado","amenity":"bank"},"name":"BancoEstado","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Millennium Bank":{"tags":{"name":"Millennium Bank","amenity":"bank"},"name":"Millennium Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/State Bank of India":{"tags":{"name":"State Bank of India","amenity":"bank"},"name":"State Bank of India","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Беларусбанк":{"tags":{"name":"Беларусбанк","amenity":"bank"},"name":"Беларусбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ING Bank Śląski":{"tags":{"name":"ING Bank Śląski","amenity":"bank"},"name":"ING Bank Śląski","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caixa Geral de Depósitos":{"tags":{"name":"Caixa Geral de Depósitos","amenity":"bank"},"name":"Caixa Geral de Depósitos","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Kreissparkasse Köln":{"tags":{"name":"Kreissparkasse Köln","amenity":"bank"},"name":"Kreissparkasse Köln","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco BCI":{"tags":{"name":"Banco BCI","amenity":"bank"},"name":"Banco BCI","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco de Chile":{"tags":{"name":"Banco de Chile","amenity":"bank"},"name":"Banco de Chile","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ВТБ24":{"tags":{"name":"ВТБ24","amenity":"bank"},"name":"ВТБ24","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/UBS":{"tags":{"name":"UBS","amenity":"bank"},"name":"UBS","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PKO BP":{"tags":{"name":"PKO BP","amenity":"bank"},"name":"PKO BP","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Chinabank":{"tags":{"name":"Chinabank","amenity":"bank"},"name":"Chinabank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PSBank":{"tags":{"name":"PSBank","amenity":"bank"},"name":"PSBank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Union Bank":{"tags":{"name":"Union Bank","amenity":"bank"},"name":"Union Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/China Bank":{"tags":{"name":"China Bank","amenity":"bank"},"name":"China Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/RCBC":{"tags":{"name":"RCBC","amenity":"bank"},"name":"RCBC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Unicaja":{"tags":{"name":"Unicaja","amenity":"bank"},"name":"Unicaja","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BBK":{"tags":{"name":"BBK","amenity":"bank"},"name":"BBK","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Ibercaja":{"tags":{"name":"Ibercaja","amenity":"bank"},"name":"Ibercaja","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/RBS":{"tags":{"name":"RBS","amenity":"bank"},"name":"RBS","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Commercial Bank of Ceylon PLC":{"tags":{"name":"Commercial Bank of Ceylon PLC","amenity":"bank"},"name":"Commercial Bank of Ceylon PLC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of Ireland":{"tags":{"name":"Bank of Ireland","amenity":"bank"},"name":"Bank of Ireland","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BNL":{"tags":{"name":"BNL","amenity":"bank"},"name":"BNL","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Santander":{"tags":{"name":"Banco Santander","amenity":"bank"},"name":"Banco Santander","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Itaú":{"tags":{"name":"Banco Itaú","amenity":"bank"},"name":"Banco Itaú","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/AIB":{"tags":{"name":"AIB","amenity":"bank"},"name":"AIB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BZ WBK":{"tags":{"name":"BZ WBK","amenity":"bank"},"name":"BZ WBK","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco do Brasil":{"tags":{"name":"Banco do Brasil","amenity":"bank"},"name":"Banco do Brasil","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caixa Econômica Federal":{"tags":{"name":"Caixa Econômica Federal","amenity":"bank"},"name":"Caixa Econômica Federal","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Fifth Third Bank":{"tags":{"name":"Fifth Third Bank","amenity":"bank"},"name":"Fifth Third Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banca Popolare di Vicenza":{"tags":{"name":"Banca Popolare di Vicenza","amenity":"bank"},"name":"Banca Popolare di Vicenza","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Wachovia":{"tags":{"name":"Wachovia","amenity":"bank"},"name":"Wachovia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/OLB":{"tags":{"name":"OLB","amenity":"bank"},"name":"OLB","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/みずほ銀行":{"tags":{"name":"みずほ銀行","amenity":"bank"},"name":"みずほ銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BES":{"tags":{"name":"BES","amenity":"bank"},"name":"BES","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ICICI Bank":{"tags":{"name":"ICICI Bank","amenity":"bank"},"name":"ICICI Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/HDFC Bank":{"tags":{"name":"HDFC Bank","amenity":"bank"},"name":"HDFC Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/La Banque Postale":{"tags":{"name":"La Banque Postale","amenity":"bank"},"name":"La Banque Postale","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Pekao SA":{"tags":{"name":"Pekao SA","amenity":"bank"},"name":"Pekao SA","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Oberbank":{"tags":{"name":"Oberbank","amenity":"bank"},"name":"Oberbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bradesco":{"tags":{"name":"Bradesco","amenity":"bank"},"name":"Bradesco","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Oldenburgische Landesbank":{"tags":{"name":"Oldenburgische Landesbank","amenity":"bank"},"name":"Oldenburgische Landesbank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bendigo Bank":{"tags":{"name":"Bendigo Bank","amenity":"bank"},"name":"Bendigo Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Argenta":{"tags":{"name":"Argenta","amenity":"bank"},"name":"Argenta","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/AXA":{"tags":{"name":"AXA","amenity":"bank"},"name":"AXA","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Axis Bank":{"tags":{"name":"Axis Bank","amenity":"bank"},"name":"Axis Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Nación":{"tags":{"name":"Banco Nación","amenity":"bank"},"name":"Banco Nación","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/GE Money Bank":{"tags":{"name":"GE Money Bank","amenity":"bank"},"name":"GE Money Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Альфа-Банк":{"tags":{"name":"Альфа-Банк","amenity":"bank"},"name":"Альфа-Банк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Белагропромбанк":{"tags":{"name":"Белагропромбанк","amenity":"bank"},"name":"Белагропромбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja Círculo":{"tags":{"name":"Caja Círculo","amenity":"bank"},"name":"Caja Círculo","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Galicia":{"tags":{"name":"Banco Galicia","amenity":"bank"},"name":"Banco Galicia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Eurobank":{"tags":{"name":"Eurobank","amenity":"bank"},"name":"Eurobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banca Intesa":{"tags":{"name":"Banca Intesa","amenity":"bank"},"name":"Banca Intesa","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Canara Bank":{"tags":{"name":"Canara Bank","amenity":"bank"},"name":"Canara Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Cajamar":{"tags":{"name":"Cajamar","amenity":"bank"},"name":"Cajamar","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banamex":{"tags":{"name":"Banamex","amenity":"bank"},"name":"Banamex","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Crédit Mutuel de Bretagne":{"tags":{"name":"Crédit Mutuel de Bretagne","amenity":"bank"},"name":"Crédit Mutuel de Bretagne","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Davivienda":{"tags":{"name":"Davivienda","amenity":"bank"},"name":"Davivienda","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank Spółdzielczy":{"tags":{"name":"Bank Spółdzielczy","amenity":"bank"},"name":"Bank Spółdzielczy","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Credit Agricole":{"tags":{"name":"Credit Agricole","amenity":"bank"},"name":"Credit Agricole","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bankinter":{"tags":{"name":"Bankinter","amenity":"bank"},"name":"Bankinter","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banque Nationale":{"tags":{"name":"Banque Nationale","amenity":"bank"},"name":"Banque Nationale","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank of the West":{"tags":{"name":"Bank of the West","amenity":"bank"},"name":"Bank of the West","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Key Bank":{"tags":{"name":"Key Bank","amenity":"bank"},"name":"Key Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Western Union":{"tags":{"name":"Western Union","amenity":"bank"},"name":"Western Union","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Citizens Bank":{"tags":{"name":"Citizens Bank","amenity":"bank"},"name":"Citizens Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ПриватБанк":{"tags":{"name":"ПриватБанк","amenity":"bank"},"name":"ПриватБанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Security Bank":{"tags":{"name":"Security Bank","amenity":"bank"},"name":"Security Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Millenium":{"tags":{"name":"Millenium","amenity":"bank"},"name":"Millenium","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bankia":{"tags":{"name":"Bankia","amenity":"bank"},"name":"Bankia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/三菱東京UFJ銀行":{"tags":{"name":"三菱東京UFJ銀行","amenity":"bank"},"name":"三菱東京UFJ銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caixa":{"tags":{"name":"Caixa","amenity":"bank"},"name":"Caixa","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco de Costa Rica":{"tags":{"name":"Banco de Costa Rica","amenity":"bank"},"name":"Banco de Costa Rica","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/SunTrust Bank":{"tags":{"name":"SunTrust Bank","amenity":"bank"},"name":"SunTrust Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Itaú":{"tags":{"name":"Itaú","amenity":"bank"},"name":"Itaú","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PBZ":{"tags":{"name":"PBZ","amenity":"bank"},"name":"PBZ","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/中国工商银行":{"tags":{"name":"中国工商银行","amenity":"bank"},"name":"中国工商银行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bancolombia":{"tags":{"name":"Bancolombia","amenity":"bank"},"name":"Bancolombia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Райффайзен Банк Аваль":{"tags":{"name":"Райффайзен Банк Аваль","amenity":"bank"},"name":"Райффайзен Банк Аваль","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bancomer":{"tags":{"name":"Bancomer","amenity":"bank"},"name":"Bancomer","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banorte":{"tags":{"name":"Banorte","amenity":"bank"},"name":"Banorte","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Alior Bank":{"tags":{"name":"Alior Bank","amenity":"bank"},"name":"Alior Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BOC":{"tags":{"name":"BOC","amenity":"bank"},"name":"BOC","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Банк Москвы":{"tags":{"name":"Банк Москвы","amenity":"bank"},"name":"Банк Москвы","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ВТБ":{"tags":{"name":"ВТБ","amenity":"bank"},"name":"ВТБ","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Getin Bank":{"tags":{"name":"Getin Bank","amenity":"bank"},"name":"Getin Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja Duero":{"tags":{"name":"Caja Duero","amenity":"bank"},"name":"Caja Duero","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Regions Bank":{"tags":{"name":"Regions Bank","amenity":"bank"},"name":"Regions Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Росбанк":{"tags":{"name":"Росбанк","amenity":"bank"},"name":"Росбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Estado":{"tags":{"name":"Banco Estado","amenity":"bank"},"name":"Banco Estado","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BCI":{"tags":{"name":"BCI","amenity":"bank"},"name":"BCI","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/SunTrust":{"tags":{"name":"SunTrust","amenity":"bank"},"name":"SunTrust","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/PNC Bank":{"tags":{"name":"PNC Bank","amenity":"bank"},"name":"PNC Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/신한은행":{"tags":{"name":"신한은행","name:en":"Sinhan Bank","amenity":"bank"},"name":"신한은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/우리은행":{"tags":{"name":"우리은행","name:en":"Uri Bank","amenity":"bank"},"name":"우리은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/국민은행":{"tags":{"name":"국민은행","name:en":"Gungmin Bank","amenity":"bank"},"name":"국민은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/중소기업은행":{"tags":{"name":"중소기업은행","name:en":"Industrial Bank of Korea","amenity":"bank"},"name":"중소기업은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/광주은행":{"tags":{"name":"광주은행","name:en":"Gwangju Bank","amenity":"bank"},"name":"광주은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Газпромбанк":{"tags":{"name":"Газпромбанк","amenity":"bank"},"name":"Газпромбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/M&T Bank":{"tags":{"name":"M&T Bank","amenity":"bank"},"name":"M&T Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Caja de Burgos":{"tags":{"name":"Caja de Burgos","amenity":"bank"},"name":"Caja de Burgos","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Santander Totta":{"tags":{"name":"Santander Totta","amenity":"bank"},"name":"Santander Totta","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/УкрСиббанк":{"tags":{"name":"УкрСиббанк","amenity":"bank"},"name":"УкрСиббанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Ощадбанк":{"tags":{"name":"Ощадбанк","amenity":"bank"},"name":"Ощадбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Уралсиб":{"tags":{"name":"Уралсиб","amenity":"bank"},"name":"Уралсиб","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/りそな銀行":{"tags":{"name":"りそな銀行","name:en":"Mizuho Bank","amenity":"bank"},"name":"りそな銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Ecobank":{"tags":{"name":"Ecobank","amenity":"bank"},"name":"Ecobank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Cajero Automatico Bancared":{"tags":{"name":"Cajero Automatico Bancared","amenity":"bank"},"name":"Cajero Automatico Bancared","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Промсвязьбанк":{"tags":{"name":"Промсвязьбанк","amenity":"bank"},"name":"Промсвязьбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/三井住友銀行":{"tags":{"name":"三井住友銀行","amenity":"bank"},"name":"三井住友銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Provincia":{"tags":{"name":"Banco Provincia","amenity":"bank"},"name":"Banco Provincia","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/BB&T":{"tags":{"name":"BB&T","amenity":"bank"},"name":"BB&T","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Возрождение":{"tags":{"name":"Возрождение","amenity":"bank"},"name":"Возрождение","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Capital One":{"tags":{"name":"Capital One","amenity":"bank"},"name":"Capital One","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/横浜銀行":{"tags":{"name":"横浜銀行","amenity":"bank"},"name":"横浜銀行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank Mandiri":{"tags":{"name":"Bank Mandiri","amenity":"bank"},"name":"Bank Mandiri","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco de la Nación":{"tags":{"name":"Banco de la Nación","amenity":"bank"},"name":"Banco de la Nación","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco G&T Continental":{"tags":{"name":"Banco G&T Continental","amenity":"bank"},"name":"Banco G&T Continental","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Peoples Bank":{"tags":{"name":"Peoples Bank","amenity":"bank"},"name":"Peoples Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/工商银行":{"tags":{"name":"工商银行","amenity":"bank"},"name":"工商银行","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Совкомбанк":{"tags":{"name":"Совкомбанк","amenity":"bank"},"name":"Совкомбанк","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Provincial":{"tags":{"name":"Provincial","amenity":"bank"},"name":"Provincial","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco de Desarrollo Banrural":{"tags":{"name":"Banco de Desarrollo Banrural","amenity":"bank"},"name":"Banco de Desarrollo Banrural","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banco Bradesco":{"tags":{"name":"Banco Bradesco","amenity":"bank"},"name":"Banco Bradesco","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bicentenario":{"tags":{"name":"Bicentenario","amenity":"bank"},"name":"Bicentenario","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/ლიბერთი ბანკი":{"tags":{"name":"ლიბერთი ბანკი","name:en":"Liberty Bank","amenity":"bank"},"name":"ლიბერთი ბანკი","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Banesco":{"tags":{"name":"Banesco","amenity":"bank"},"name":"Banesco","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Mercantil":{"tags":{"name":"Mercantil","amenity":"bank"},"name":"Mercantil","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Bank BRI":{"tags":{"name":"Bank BRI","amenity":"bank"},"name":"Bank BRI","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/Del Tesoro":{"tags":{"name":"Del Tesoro","amenity":"bank"},"name":"Del Tesoro","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/하나은행":{"tags":{"name":"하나은행","amenity":"bank"},"name":"하나은행","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/CityCommerce Bank":{"tags":{"name":"CityCommerce Bank","amenity":"bank"},"name":"CityCommerce Bank","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/bank/De Venezuela":{"tags":{"name":"De Venezuela","amenity":"bank"},"name":"De Venezuela","icon":"bank","geometry":["point","area"],"fields":["atm","operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/car_rental/Europcar":{"tags":{"name":"Europcar","amenity":"car_rental"},"name":"Europcar","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Budget":{"tags":{"name":"Budget","amenity":"car_rental"},"name":"Budget","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Sixt":{"tags":{"name":"Sixt","amenity":"car_rental"},"name":"Sixt","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Avis":{"tags":{"name":"Avis","amenity":"car_rental"},"name":"Avis","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Hertz":{"tags":{"name":"Hertz","amenity":"car_rental"},"name":"Hertz","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/Enterprise":{"tags":{"name":"Enterprise","amenity":"car_rental"},"name":"Enterprise","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/car_rental/stadtmobil CarSharing-Station":{"tags":{"name":"stadtmobil CarSharing-Station","amenity":"car_rental"},"name":"stadtmobil CarSharing-Station","icon":"car","geometry":["point","area"],"fields":["operator"],"suggestion":true},"amenity/pharmacy/Rowlands Pharmacy":{"tags":{"name":"Rowlands Pharmacy","amenity":"pharmacy"},"name":"Rowlands Pharmacy","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Boots":{"tags":{"name":"Boots","amenity":"pharmacy"},"name":"Boots","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Marien-Apotheke":{"tags":{"name":"Marien-Apotheke","amenity":"pharmacy"},"name":"Marien-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Mercury Drug":{"tags":{"name":"Mercury Drug","amenity":"pharmacy"},"name":"Mercury Drug","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Löwen-Apotheke":{"tags":{"name":"Löwen-Apotheke","amenity":"pharmacy"},"name":"Löwen-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Superdrug":{"tags":{"name":"Superdrug","amenity":"pharmacy"},"name":"Superdrug","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Sonnen-Apotheke":{"tags":{"name":"Sonnen-Apotheke","amenity":"pharmacy"},"name":"Sonnen-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Rathaus-Apotheke":{"tags":{"name":"Rathaus-Apotheke","amenity":"pharmacy"},"name":"Rathaus-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Engel-Apotheke":{"tags":{"name":"Engel-Apotheke","amenity":"pharmacy"},"name":"Engel-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Hirsch-Apotheke":{"tags":{"name":"Hirsch-Apotheke","amenity":"pharmacy"},"name":"Hirsch-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Stern-Apotheke":{"tags":{"name":"Stern-Apotheke","amenity":"pharmacy"},"name":"Stern-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Lloyds Pharmacy":{"tags":{"name":"Lloyds Pharmacy","amenity":"pharmacy"},"name":"Lloyds Pharmacy","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Rosen-Apotheke":{"tags":{"name":"Rosen-Apotheke","amenity":"pharmacy"},"name":"Rosen-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Stadt-Apotheke":{"tags":{"name":"Stadt-Apotheke","amenity":"pharmacy"},"name":"Stadt-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Markt-Apotheke":{"tags":{"name":"Markt-Apotheke","amenity":"pharmacy"},"name":"Markt-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Аптека":{"tags":{"name":"Аптека","amenity":"pharmacy"},"name":"Аптека","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Pharmasave":{"tags":{"name":"Pharmasave","amenity":"pharmacy"},"name":"Pharmasave","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Brunnen-Apotheke":{"tags":{"name":"Brunnen-Apotheke","amenity":"pharmacy"},"name":"Brunnen-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Shoppers Drug Mart":{"tags":{"name":"Shoppers Drug Mart","amenity":"pharmacy"},"name":"Shoppers Drug Mart","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Apotheke am Markt":{"tags":{"name":"Apotheke am Markt","amenity":"pharmacy"},"name":"Apotheke am Markt","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Alte Apotheke":{"tags":{"name":"Alte Apotheke","amenity":"pharmacy"},"name":"Alte Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Neue Apotheke":{"tags":{"name":"Neue Apotheke","amenity":"pharmacy"},"name":"Neue Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Gintarinė vaistinė":{"tags":{"name":"Gintarinė vaistinė","amenity":"pharmacy"},"name":"Gintarinė vaistinė","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Rats-Apotheke":{"tags":{"name":"Rats-Apotheke","amenity":"pharmacy"},"name":"Rats-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Adler Apotheke":{"tags":{"name":"Adler Apotheke","amenity":"pharmacy"},"name":"Adler Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Pharmacie Centrale":{"tags":{"name":"Pharmacie Centrale","amenity":"pharmacy"},"name":"Pharmacie Centrale","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Walgreens":{"tags":{"name":"Walgreens","amenity":"pharmacy"},"name":"Walgreens","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Rite Aid":{"tags":{"name":"Rite Aid","amenity":"pharmacy"},"name":"Rite Aid","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Apotheke":{"tags":{"name":"Apotheke","amenity":"pharmacy"},"name":"Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Linden-Apotheke":{"tags":{"name":"Linden-Apotheke","amenity":"pharmacy"},"name":"Linden-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Bahnhof-Apotheke":{"tags":{"name":"Bahnhof-Apotheke","amenity":"pharmacy"},"name":"Bahnhof-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Burg-Apotheke":{"tags":{"name":"Burg-Apotheke","amenity":"pharmacy"},"name":"Burg-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Jean Coutu":{"tags":{"name":"Jean Coutu","amenity":"pharmacy"},"name":"Jean Coutu","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Pharmaprix":{"tags":{"name":"Pharmaprix","amenity":"pharmacy"},"name":"Pharmaprix","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacias Ahumada":{"tags":{"name":"Farmacias Ahumada","amenity":"pharmacy"},"name":"Farmacias Ahumada","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacia Comunale":{"tags":{"name":"Farmacia Comunale","amenity":"pharmacy"},"name":"Farmacia Comunale","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacias Cruz Verde":{"tags":{"name":"Farmacias Cruz Verde","amenity":"pharmacy"},"name":"Farmacias Cruz Verde","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Cruz Verde":{"tags":{"name":"Cruz Verde","amenity":"pharmacy"},"name":"Cruz Verde","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Hubertus Apotheke":{"tags":{"name":"Hubertus Apotheke","amenity":"pharmacy"},"name":"Hubertus Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/CVS":{"tags":{"name":"CVS","amenity":"pharmacy"},"name":"CVS","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacias SalcoBrand":{"tags":{"name":"Farmacias SalcoBrand","amenity":"pharmacy"},"name":"Farmacias SalcoBrand","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Фармация":{"tags":{"name":"Фармация","amenity":"pharmacy"},"name":"Фармация","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Bären-Apotheke":{"tags":{"name":"Bären-Apotheke","amenity":"pharmacy"},"name":"Bären-Apotheke","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Clicks":{"tags":{"name":"Clicks","amenity":"pharmacy"},"name":"Clicks","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/セイジョー":{"tags":{"name":"セイジョー","amenity":"pharmacy"},"name":"セイジョー","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/マツモトキヨシ":{"tags":{"name":"マツモトキヨシ","amenity":"pharmacy"},"name":"マツモトキヨシ","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Dr. Max":{"tags":{"name":"Dr. Max","amenity":"pharmacy"},"name":"Dr. Max","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Вита":{"tags":{"name":"Вита","amenity":"pharmacy"},"name":"Вита","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/サンドラッグ":{"tags":{"name":"サンドラッグ","amenity":"pharmacy"},"name":"サンドラッグ","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Apteka":{"tags":{"name":"Apteka","amenity":"pharmacy"},"name":"Apteka","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Первая помощь":{"tags":{"name":"Первая помощь","amenity":"pharmacy"},"name":"Первая помощь","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Ригла":{"tags":{"name":"Ригла","amenity":"pharmacy"},"name":"Ригла","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Имплозия":{"tags":{"name":"Имплозия","amenity":"pharmacy"},"name":"Имплозия","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Kinney Drugs":{"tags":{"name":"Kinney Drugs","amenity":"pharmacy"},"name":"Kinney Drugs","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Классика":{"tags":{"name":"Классика","amenity":"pharmacy"},"name":"Классика","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Ljekarna":{"tags":{"name":"Ljekarna","amenity":"pharmacy"},"name":"Ljekarna","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/SalcoBrand":{"tags":{"name":"SalcoBrand","amenity":"pharmacy"},"name":"SalcoBrand","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Аптека 36,6":{"tags":{"name":"Аптека 36,6","amenity":"pharmacy"},"name":"Аптека 36,6","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Фармакор":{"tags":{"name":"Фармакор","amenity":"pharmacy"},"name":"Фармакор","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/スギ薬局":{"tags":{"name":"スギ薬局","amenity":"pharmacy"},"name":"スギ薬局","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Аптечный пункт":{"tags":{"name":"Аптечный пункт","amenity":"pharmacy"},"name":"Аптечный пункт","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Невис":{"tags":{"name":"Невис","amenity":"pharmacy"},"name":"Невис","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/トモズ (Tomod's)":{"tags":{"name":"トモズ (Tomod's)","amenity":"pharmacy"},"name":"トモズ (Tomod's)","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Eurovaistinė":{"tags":{"name":"Eurovaistinė","amenity":"pharmacy"},"name":"Eurovaistinė","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmacity":{"tags":{"name":"Farmacity","amenity":"pharmacy"},"name":"Farmacity","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/аптека":{"tags":{"name":"аптека","amenity":"pharmacy"},"name":"аптека","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/The Generics Pharmacy":{"tags":{"name":"The Generics Pharmacy","amenity":"pharmacy"},"name":"The Generics Pharmacy","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmatodo":{"tags":{"name":"Farmatodo","amenity":"pharmacy"},"name":"Farmatodo","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Duane Reade":{"tags":{"name":"Duane Reade","amenity":"pharmacy"},"name":"Duane Reade","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Фармленд":{"tags":{"name":"Фармленд","amenity":"pharmacy"},"name":"Фармленд","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/ドラッグてらしま (Drug Terashima)":{"tags":{"name":"ドラッグてらしま (Drug Terashima)","amenity":"pharmacy"},"name":"ドラッグてらしま (Drug Terashima)","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Арніка":{"tags":{"name":"Арніка","amenity":"pharmacy"},"name":"Арніка","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/ავერსი (Aversi)":{"tags":{"name":"ავერსი (Aversi)","amenity":"pharmacy"},"name":"ავერსი (Aversi)","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/pharmacy/Farmahorro":{"tags":{"name":"Farmahorro","amenity":"pharmacy"},"name":"Farmahorro","icon":"pharmacy","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"amenity/cafe/Starbucks":{"tags":{"name":"Starbucks","cuisine":"coffee_shop","amenity":"cafe"},"name":"Starbucks","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Cafeteria":{"tags":{"name":"Cafeteria","amenity":"cafe"},"name":"Cafeteria","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Costa":{"tags":{"name":"Costa","amenity":"cafe"},"name":"Costa","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Caffè Nero":{"tags":{"name":"Caffè Nero","amenity":"cafe"},"name":"Caffè Nero","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Кафе":{"tags":{"name":"Кафе","amenity":"cafe"},"name":"Кафе","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Café Central":{"tags":{"name":"Café Central","amenity":"cafe"},"name":"Café Central","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Second Cup":{"tags":{"name":"Second Cup","amenity":"cafe"},"name":"Second Cup","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Dunkin Donuts":{"tags":{"name":"Dunkin Donuts","cuisine":"donut","amenity":"cafe"},"name":"Dunkin Donuts","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Espresso House":{"tags":{"name":"Espresso House","amenity":"cafe"},"name":"Espresso House","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Segafredo":{"tags":{"name":"Segafredo","amenity":"cafe"},"name":"Segafredo","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Coffee Time":{"tags":{"name":"Coffee Time","amenity":"cafe"},"name":"Coffee Time","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Cafe Coffee Day":{"tags":{"name":"Cafe Coffee Day","amenity":"cafe"},"name":"Cafe Coffee Day","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Eiscafe Venezia":{"tags":{"name":"Eiscafe Venezia","amenity":"cafe"},"name":"Eiscafe Venezia","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/スターバックス":{"tags":{"name":"スターバックス","name:en":"Starbucks","amenity":"cafe"},"name":"スターバックス","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Шоколадница":{"tags":{"name":"Шоколадница","amenity":"cafe"},"name":"Шоколадница","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Pret A Manger":{"tags":{"name":"Pret A Manger","amenity":"cafe"},"name":"Pret A Manger","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Столовая":{"tags":{"name":"Столовая","amenity":"cafe"},"name":"Столовая","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/ドトール":{"tags":{"name":"ドトール","name:en":"DOUTOR","amenity":"cafe"},"name":"ドトール","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Tchibo":{"tags":{"name":"Tchibo","amenity":"cafe"},"name":"Tchibo","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Кофе Хауз":{"tags":{"name":"Кофе Хауз","amenity":"cafe"},"name":"Кофе Хауз","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Caribou Coffee":{"tags":{"name":"Caribou Coffee","amenity":"cafe"},"name":"Caribou Coffee","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Уют":{"tags":{"name":"Уют","amenity":"cafe"},"name":"Уют","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Шашлычная":{"tags":{"name":"Шашлычная","amenity":"cafe"},"name":"Шашлычная","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/คาเฟ่ อเมซอน":{"tags":{"name":"คาเฟ่ อเมซอน","amenity":"cafe"},"name":"คาเฟ่ อเมซอน","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Traveler's Coffee":{"tags":{"name":"Traveler's Coffee","amenity":"cafe"},"name":"Traveler's Coffee","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/カフェ・ド・クリエ":{"tags":{"name":"カフェ・ド・クリエ","name:en":"Cafe de CRIE","amenity":"cafe"},"name":"カフェ・ド・クリエ","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"amenity/cafe/Cafe Amazon":{"tags":{"name":"Cafe Amazon","amenity":"cafe"},"name":"Cafe Amazon","icon":"cafe","geometry":["point","area"],"fields":["cuisine","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid","smoking","outdoor_seating"],"suggestion":true},"shop/supermarket/Budgens":{"tags":{"name":"Budgens","shop":"supermarket"},"name":"Budgens","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Morrisons":{"tags":{"name":"Morrisons","shop":"supermarket"},"name":"Morrisons","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Interspar":{"tags":{"name":"Interspar","shop":"supermarket"},"name":"Interspar","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Merkur":{"tags":{"name":"Merkur","shop":"supermarket"},"name":"Merkur","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sainsbury's":{"tags":{"name":"Sainsbury's","shop":"supermarket"},"name":"Sainsbury's","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Lidl":{"tags":{"name":"Lidl","shop":"supermarket"},"name":"Lidl","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Edeka":{"tags":{"name":"Edeka","shop":"supermarket"},"name":"Edeka","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Coles":{"tags":{"name":"Coles","shop":"supermarket"},"name":"Coles","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Iceland":{"tags":{"name":"Iceland","shop":"supermarket"},"name":"Iceland","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Coop":{"tags":{"name":"Coop","shop":"supermarket"},"name":"Coop","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tesco":{"tags":{"name":"Tesco","shop":"supermarket"},"name":"Tesco","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Woolworths":{"tags":{"name":"Woolworths","shop":"supermarket"},"name":"Woolworths","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Zielpunkt":{"tags":{"name":"Zielpunkt","shop":"supermarket"},"name":"Zielpunkt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Nahkauf":{"tags":{"name":"Nahkauf","shop":"supermarket"},"name":"Nahkauf","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Billa":{"tags":{"name":"Billa","shop":"supermarket"},"name":"Billa","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kaufland":{"tags":{"name":"Kaufland","shop":"supermarket"},"name":"Kaufland","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Plus":{"tags":{"name":"Plus","shop":"supermarket"},"name":"Plus","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ALDI":{"tags":{"name":"ALDI","shop":"supermarket"},"name":"ALDI","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Checkers":{"tags":{"name":"Checkers","shop":"supermarket"},"name":"Checkers","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tesco Metro":{"tags":{"name":"Tesco Metro","shop":"supermarket"},"name":"Tesco Metro","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/NP":{"tags":{"name":"NP","shop":"supermarket"},"name":"NP","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Penny":{"tags":{"name":"Penny","shop":"supermarket"},"name":"Penny","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Norma":{"tags":{"name":"Norma","shop":"supermarket"},"name":"Norma","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Asda":{"tags":{"name":"Asda","shop":"supermarket"},"name":"Asda","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Netto":{"tags":{"name":"Netto","shop":"supermarket"},"name":"Netto","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Rewe":{"tags":{"name":"Rewe","shop":"supermarket"},"name":"Rewe","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Aldi Süd":{"tags":{"name":"Aldi Süd","shop":"supermarket"},"name":"Aldi Süd","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Real":{"tags":{"name":"Real","shop":"supermarket"},"name":"Real","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/King Soopers":{"tags":{"name":"King Soopers","shop":"supermarket"},"name":"King Soopers","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kiwi":{"tags":{"name":"Kiwi","shop":"supermarket"},"name":"Kiwi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Pick n Pay":{"tags":{"name":"Pick n Pay","shop":"supermarket"},"name":"Pick n Pay","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ICA":{"tags":{"name":"ICA","shop":"supermarket"},"name":"ICA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tengelmann":{"tags":{"name":"Tengelmann","shop":"supermarket"},"name":"Tengelmann","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour":{"tags":{"name":"Carrefour","shop":"supermarket"},"name":"Carrefour","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Waitrose":{"tags":{"name":"Waitrose","shop":"supermarket"},"name":"Waitrose","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Spar":{"tags":{"name":"Spar","shop":"supermarket"},"name":"Spar","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hofer":{"tags":{"name":"Hofer","shop":"supermarket"},"name":"Hofer","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/M-Preis":{"tags":{"name":"M-Preis","shop":"supermarket"},"name":"M-Preis","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/tegut":{"tags":{"name":"tegut","shop":"supermarket"},"name":"tegut","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sainsbury's Local":{"tags":{"name":"Sainsbury's Local","shop":"supermarket"},"name":"Sainsbury's Local","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/E-Center":{"tags":{"name":"E-Center","shop":"supermarket"},"name":"E-Center","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Aldi Nord":{"tags":{"name":"Aldi Nord","shop":"supermarket"},"name":"Aldi Nord","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/nahkauf":{"tags":{"name":"nahkauf","shop":"supermarket"},"name":"nahkauf","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Meijer":{"tags":{"name":"Meijer","shop":"supermarket"},"name":"Meijer","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Safeway":{"tags":{"name":"Safeway","shop":"supermarket"},"name":"Safeway","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Costco":{"tags":{"name":"Costco","shop":"supermarket"},"name":"Costco","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Albert":{"tags":{"name":"Albert","shop":"supermarket"},"name":"Albert","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Jumbo":{"tags":{"name":"Jumbo","shop":"supermarket"},"name":"Jumbo","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Shoprite":{"tags":{"name":"Shoprite","shop":"supermarket"},"name":"Shoprite","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/MPreis":{"tags":{"name":"MPreis","shop":"supermarket"},"name":"MPreis","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Penny Market":{"tags":{"name":"Penny Market","shop":"supermarket"},"name":"Penny Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tesco Extra":{"tags":{"name":"Tesco Extra","shop":"supermarket"},"name":"Tesco Extra","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Albert Heijn":{"tags":{"name":"Albert Heijn","shop":"supermarket"},"name":"Albert Heijn","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/IGA":{"tags":{"name":"IGA","shop":"supermarket"},"name":"IGA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Super U":{"tags":{"name":"Super U","shop":"supermarket"},"name":"Super U","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Metro":{"tags":{"name":"Metro","shop":"supermarket"},"name":"Metro","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Neukauf":{"tags":{"name":"Neukauf","shop":"supermarket"},"name":"Neukauf","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Migros":{"tags":{"name":"Migros","shop":"supermarket"},"name":"Migros","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Marktkauf":{"tags":{"name":"Marktkauf","shop":"supermarket"},"name":"Marktkauf","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Delikatesy Centrum":{"tags":{"name":"Delikatesy Centrum","shop":"supermarket"},"name":"Delikatesy Centrum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/C1000":{"tags":{"name":"C1000","shop":"supermarket"},"name":"C1000","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hoogvliet":{"tags":{"name":"Hoogvliet","shop":"supermarket"},"name":"Hoogvliet","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Food Basics":{"tags":{"name":"Food Basics","shop":"supermarket"},"name":"Food Basics","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Casino":{"tags":{"name":"Casino","shop":"supermarket"},"name":"Casino","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Penny Markt":{"tags":{"name":"Penny Markt","shop":"supermarket"},"name":"Penny Markt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Giant":{"tags":{"name":"Giant","shop":"supermarket"},"name":"Giant","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Rema 1000":{"tags":{"name":"Rema 1000","shop":"supermarket"},"name":"Rema 1000","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kaufpark":{"tags":{"name":"Kaufpark","shop":"supermarket"},"name":"Kaufpark","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ALDI SÜD":{"tags":{"name":"ALDI SÜD","shop":"supermarket"},"name":"ALDI SÜD","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Simply Market":{"tags":{"name":"Simply Market","shop":"supermarket"},"name":"Simply Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Konzum":{"tags":{"name":"Konzum","shop":"supermarket"},"name":"Konzum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour Express":{"tags":{"name":"Carrefour Express","shop":"supermarket"},"name":"Carrefour Express","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Eurospar":{"tags":{"name":"Eurospar","shop":"supermarket"},"name":"Eurospar","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Mercator":{"tags":{"name":"Mercator","shop":"supermarket"},"name":"Mercator","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Famila":{"tags":{"name":"Famila","shop":"supermarket"},"name":"Famila","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hemköp":{"tags":{"name":"Hemköp","shop":"supermarket"},"name":"Hemköp","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/real,-":{"tags":{"name":"real,-","shop":"supermarket"},"name":"real,-","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Markant":{"tags":{"name":"Markant","shop":"supermarket"},"name":"Markant","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Volg":{"tags":{"name":"Volg","shop":"supermarket"},"name":"Volg","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Leader Price":{"tags":{"name":"Leader Price","shop":"supermarket"},"name":"Leader Price","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Treff 3000":{"tags":{"name":"Treff 3000","shop":"supermarket"},"name":"Treff 3000","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/SuperBrugsen":{"tags":{"name":"SuperBrugsen","shop":"supermarket"},"name":"SuperBrugsen","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kaiser's":{"tags":{"name":"Kaiser's","shop":"supermarket"},"name":"Kaiser's","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/K+K":{"tags":{"name":"K+K","shop":"supermarket"},"name":"K+K","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Unimarkt":{"tags":{"name":"Unimarkt","shop":"supermarket"},"name":"Unimarkt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour City":{"tags":{"name":"Carrefour City","shop":"supermarket"},"name":"Carrefour City","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sobeys":{"tags":{"name":"Sobeys","shop":"supermarket"},"name":"Sobeys","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/S-Market":{"tags":{"name":"S-Market","shop":"supermarket"},"name":"S-Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Combi":{"tags":{"name":"Combi","shop":"supermarket"},"name":"Combi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Denner":{"tags":{"name":"Denner","shop":"supermarket"},"name":"Denner","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Konsum":{"tags":{"name":"Konsum","shop":"supermarket"},"name":"Konsum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Franprix":{"tags":{"name":"Franprix","shop":"supermarket"},"name":"Franprix","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Monoprix":{"tags":{"name":"Monoprix","shop":"supermarket"},"name":"Monoprix","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Diska":{"tags":{"name":"Diska","shop":"supermarket"},"name":"Diska","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/PENNY":{"tags":{"name":"PENNY","shop":"supermarket"},"name":"PENNY","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Dia":{"tags":{"name":"Dia","shop":"supermarket"},"name":"Dia","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Giant Eagle":{"tags":{"name":"Giant Eagle","shop":"supermarket"},"name":"Giant Eagle","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/NORMA":{"tags":{"name":"NORMA","shop":"supermarket"},"name":"NORMA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/AD Delhaize":{"tags":{"name":"AD Delhaize","shop":"supermarket"},"name":"AD Delhaize","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Auchan":{"tags":{"name":"Auchan","shop":"supermarket"},"name":"Auchan","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Mercadona":{"tags":{"name":"Mercadona","shop":"supermarket"},"name":"Mercadona","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Consum":{"tags":{"name":"Consum","shop":"supermarket"},"name":"Consum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour Market":{"tags":{"name":"Carrefour Market","shop":"supermarket"},"name":"Carrefour Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Whole Foods":{"tags":{"name":"Whole Foods","shop":"supermarket"},"name":"Whole Foods","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Pam":{"tags":{"name":"Pam","shop":"supermarket"},"name":"Pam","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/sky":{"tags":{"name":"sky","shop":"supermarket"},"name":"sky","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Despar":{"tags":{"name":"Despar","shop":"supermarket"},"name":"Despar","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Eroski":{"tags":{"name":"Eroski","shop":"supermarket"},"name":"Eroski","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Maxi":{"tags":{"name":"Maxi","shop":"supermarket"},"name":"Maxi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Colruyt":{"tags":{"name":"Colruyt","shop":"supermarket"},"name":"Colruyt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/The Co-operative":{"tags":{"name":"The Co-operative","shop":"supermarket"},"name":"The Co-operative","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Intermarché":{"tags":{"name":"Intermarché","shop":"supermarket"},"name":"Intermarché","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Delhaize":{"tags":{"name":"Delhaize","shop":"supermarket"},"name":"Delhaize","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/CBA":{"tags":{"name":"CBA","shop":"supermarket"},"name":"CBA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Shopi":{"tags":{"name":"Shopi","shop":"supermarket"},"name":"Shopi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Walmart":{"tags":{"name":"Walmart","shop":"supermarket"},"name":"Walmart","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kroger":{"tags":{"name":"Kroger","shop":"supermarket"},"name":"Kroger","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Albertsons":{"tags":{"name":"Albertsons","shop":"supermarket"},"name":"Albertsons","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Trader Joe's":{"tags":{"name":"Trader Joe's","shop":"supermarket"},"name":"Trader Joe's","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Feneberg":{"tags":{"name":"Feneberg","shop":"supermarket"},"name":"Feneberg","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/denn's Biomarkt":{"tags":{"name":"denn's Biomarkt","shop":"supermarket"},"name":"denn's Biomarkt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Kvickly":{"tags":{"name":"Kvickly","shop":"supermarket"},"name":"Kvickly","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Makro":{"tags":{"name":"Makro","shop":"supermarket"},"name":"Makro","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Dico":{"tags":{"name":"Dico","shop":"supermarket"},"name":"Dico","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Nah & Frisch":{"tags":{"name":"Nah & Frisch","shop":"supermarket"},"name":"Nah & Frisch","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Champion":{"tags":{"name":"Champion","shop":"supermarket"},"name":"Champion","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ICA Supermarket":{"tags":{"name":"ICA Supermarket","shop":"supermarket"},"name":"ICA Supermarket","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Fakta":{"tags":{"name":"Fakta","shop":"supermarket"},"name":"Fakta","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Магнит":{"tags":{"name":"Магнит","shop":"supermarket"},"name":"Магнит","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Caprabo":{"tags":{"name":"Caprabo","shop":"supermarket"},"name":"Caprabo","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Famiglia Cooperativa":{"tags":{"name":"Famiglia Cooperativa","shop":"supermarket"},"name":"Famiglia Cooperativa","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Народная 7Я семьЯ":{"tags":{"name":"Народная 7Я семьЯ","shop":"supermarket"},"name":"Народная 7Я семьЯ","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Esselunga":{"tags":{"name":"Esselunga","shop":"supermarket"},"name":"Esselunga","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Maxima":{"tags":{"name":"Maxima","shop":"supermarket"},"name":"Maxima","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Wasgau":{"tags":{"name":"Wasgau","shop":"supermarket"},"name":"Wasgau","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Pingo Doce":{"tags":{"name":"Pingo Doce","shop":"supermarket"},"name":"Pingo Doce","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Match":{"tags":{"name":"Match","shop":"supermarket"},"name":"Match","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Profi":{"tags":{"name":"Profi","shop":"supermarket"},"name":"Profi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Lider":{"tags":{"name":"Lider","shop":"supermarket"},"name":"Lider","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Unimarc":{"tags":{"name":"Unimarc","shop":"supermarket"},"name":"Unimarc","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/The Co-operative Food":{"tags":{"name":"The Co-operative Food","shop":"supermarket"},"name":"The Co-operative Food","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Santa Isabel":{"tags":{"name":"Santa Isabel","shop":"supermarket"},"name":"Santa Isabel","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Седьмой континент":{"tags":{"name":"Седьмой континент","shop":"supermarket"},"name":"Седьмой континент","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/HIT":{"tags":{"name":"HIT","shop":"supermarket"},"name":"HIT","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Rimi":{"tags":{"name":"Rimi","shop":"supermarket"},"name":"Rimi","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Conad":{"tags":{"name":"Conad","shop":"supermarket"},"name":"Conad","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Фуршет":{"tags":{"name":"Фуршет","shop":"supermarket"},"name":"Фуршет","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Willys":{"tags":{"name":"Willys","shop":"supermarket"},"name":"Willys","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Farmfoods":{"tags":{"name":"Farmfoods","shop":"supermarket"},"name":"Farmfoods","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/U Express":{"tags":{"name":"U Express","shop":"supermarket"},"name":"U Express","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Фора":{"tags":{"name":"Фора","shop":"supermarket"},"name":"Фора","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Dunnes Stores":{"tags":{"name":"Dunnes Stores","shop":"supermarket"},"name":"Dunnes Stores","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Сільпо":{"tags":{"name":"Сільпо","shop":"supermarket"},"name":"Сільпо","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/マルエツ":{"tags":{"name":"マルエツ","shop":"supermarket"},"name":"マルエツ","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Piggly Wiggly":{"tags":{"name":"Piggly Wiggly","shop":"supermarket"},"name":"Piggly Wiggly","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Crai":{"tags":{"name":"Crai","shop":"supermarket"},"name":"Crai","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/El Árbol":{"tags":{"name":"El Árbol","shop":"supermarket"},"name":"El Árbol","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Centre Commercial E. Leclerc":{"tags":{"name":"Centre Commercial E. Leclerc","shop":"supermarket"},"name":"Centre Commercial E. Leclerc","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Foodland":{"tags":{"name":"Foodland","shop":"supermarket"},"name":"Foodland","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Super Brugsen":{"tags":{"name":"Super Brugsen","shop":"supermarket"},"name":"Super Brugsen","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Дикси":{"tags":{"name":"Дикси","shop":"supermarket"},"name":"Дикси","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Пятёрочка":{"tags":{"name":"Пятёрочка","shop":"supermarket"},"name":"Пятёрочка","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Publix":{"tags":{"name":"Publix","shop":"supermarket"},"name":"Publix","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Føtex":{"tags":{"name":"Føtex","shop":"supermarket"},"name":"Føtex","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/coop":{"tags":{"name":"coop","shop":"supermarket"},"name":"coop","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Coop Konsum":{"tags":{"name":"Coop Konsum","shop":"supermarket"},"name":"Coop Konsum","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Carrefour Contact":{"tags":{"name":"Carrefour Contact","shop":"supermarket"},"name":"Carrefour Contact","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/No Frills":{"tags":{"name":"No Frills","shop":"supermarket"},"name":"No Frills","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Plodine":{"tags":{"name":"Plodine","shop":"supermarket"},"name":"Plodine","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ADEG":{"tags":{"name":"ADEG","shop":"supermarket"},"name":"ADEG","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Minipreço":{"tags":{"name":"Minipreço","shop":"supermarket"},"name":"Minipreço","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Biedronka":{"tags":{"name":"Biedronka","shop":"supermarket"},"name":"Biedronka","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Eurospin":{"tags":{"name":"Eurospin","shop":"supermarket"},"name":"Eurospin","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Семья":{"tags":{"name":"Семья","shop":"supermarket"},"name":"Семья","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Gadis":{"tags":{"name":"Gadis","shop":"supermarket"},"name":"Gadis","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Евроопт":{"tags":{"name":"Евроопт","shop":"supermarket"},"name":"Евроопт","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Квартал":{"tags":{"name":"Квартал","shop":"supermarket"},"name":"Квартал","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/New World":{"tags":{"name":"New World","shop":"supermarket"},"name":"New World","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Countdown":{"tags":{"name":"Countdown","shop":"supermarket"},"name":"Countdown","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Reliance Fresh":{"tags":{"name":"Reliance Fresh","shop":"supermarket"},"name":"Reliance Fresh","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Stokrotka":{"tags":{"name":"Stokrotka","shop":"supermarket"},"name":"Stokrotka","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Coop Jednota":{"tags":{"name":"Coop Jednota","shop":"supermarket"},"name":"Coop Jednota","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Fred Meyer":{"tags":{"name":"Fred Meyer","shop":"supermarket"},"name":"Fred Meyer","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Irma":{"tags":{"name":"Irma","shop":"supermarket"},"name":"Irma","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Continente":{"tags":{"name":"Continente","shop":"supermarket"},"name":"Continente","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Price Chopper":{"tags":{"name":"Price Chopper","shop":"supermarket"},"name":"Price Chopper","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Game":{"tags":{"name":"Game","shop":"supermarket"},"name":"Game","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Soriana":{"tags":{"name":"Soriana","shop":"supermarket"},"name":"Soriana","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Alimerka":{"tags":{"name":"Alimerka","shop":"supermarket"},"name":"Alimerka","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Piotr i Paweł":{"tags":{"name":"Piotr i Paweł","shop":"supermarket"},"name":"Piotr i Paweł","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Перекресток":{"tags":{"name":"Перекресток","shop":"supermarket"},"name":"Перекресток","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Maxima X":{"tags":{"name":"Maxima X","shop":"supermarket"},"name":"Maxima X","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Карусель":{"tags":{"name":"Карусель","shop":"supermarket"},"name":"Карусель","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ALDI Nord":{"tags":{"name":"ALDI Nord","shop":"supermarket"},"name":"ALDI Nord","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Condis":{"tags":{"name":"Condis","shop":"supermarket"},"name":"Condis","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sam's Club":{"tags":{"name":"Sam's Club","shop":"supermarket"},"name":"Sam's Club","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Копейка":{"tags":{"name":"Копейка","shop":"supermarket"},"name":"Копейка","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Géant Casino":{"tags":{"name":"Géant Casino","shop":"supermarket"},"name":"Géant Casino","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ASDA":{"tags":{"name":"ASDA","shop":"supermarket"},"name":"ASDA","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Intermarche":{"tags":{"name":"Intermarche","shop":"supermarket"},"name":"Intermarche","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Stop & Shop":{"tags":{"name":"Stop & Shop","shop":"supermarket"},"name":"Stop & Shop","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Food Lion":{"tags":{"name":"Food Lion","shop":"supermarket"},"name":"Food Lion","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Harris Teeter":{"tags":{"name":"Harris Teeter","shop":"supermarket"},"name":"Harris Teeter","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Foodworks":{"tags":{"name":"Foodworks","shop":"supermarket"},"name":"Foodworks","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Polo Market":{"tags":{"name":"Polo Market","shop":"supermarket"},"name":"Polo Market","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Лента":{"tags":{"name":"Лента","shop":"supermarket"},"name":"Лента","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/西友 (SEIYU)":{"tags":{"name":"西友 (SEIYU)","shop":"supermarket"},"name":"西友 (SEIYU)","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/H-E-B":{"tags":{"name":"H-E-B","shop":"supermarket"},"name":"H-E-B","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Атак":{"tags":{"name":"Атак","shop":"supermarket"},"name":"Атак","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Полушка":{"tags":{"name":"Полушка","shop":"supermarket"},"name":"Полушка","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Extra":{"tags":{"name":"Extra","shop":"supermarket"},"name":"Extra","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Sigma":{"tags":{"name":"Sigma","shop":"supermarket"},"name":"Sigma","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/АТБ":{"tags":{"name":"АТБ","shop":"supermarket"},"name":"АТБ","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Bodega Aurrera":{"tags":{"name":"Bodega Aurrera","shop":"supermarket"},"name":"Bodega Aurrera","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Tesco Lotus":{"tags":{"name":"Tesco Lotus","shop":"supermarket"},"name":"Tesco Lotus","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Мария-Ра":{"tags":{"name":"Мария-Ра","shop":"supermarket"},"name":"Мария-Ра","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Магнолия":{"tags":{"name":"Магнолия","shop":"supermarket"},"name":"Магнолия","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Монетка":{"tags":{"name":"Монетка","shop":"supermarket"},"name":"Монетка","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hy-Vee":{"tags":{"name":"Hy-Vee","shop":"supermarket"},"name":"Hy-Vee","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Walmart Supercenter":{"tags":{"name":"Walmart Supercenter","shop":"supermarket"},"name":"Walmart Supercenter","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Hannaford":{"tags":{"name":"Hannaford","shop":"supermarket"},"name":"Hannaford","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Wegmans":{"tags":{"name":"Wegmans","shop":"supermarket"},"name":"Wegmans","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/業務スーパー":{"tags":{"name":"業務スーパー","shop":"supermarket"},"name":"業務スーパー","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Norfa XL":{"tags":{"name":"Norfa XL","shop":"supermarket"},"name":"Norfa XL","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/ヨークマート (YorkMart)":{"tags":{"name":"ヨークマート (YorkMart)","shop":"supermarket"},"name":"ヨークマート (YorkMart)","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/supermarket/Leclerc Drive":{"tags":{"name":"Leclerc Drive","shop":"supermarket"},"name":"Leclerc Drive","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Media Markt":{"tags":{"name":"Media Markt","shop":"electronics"},"name":"Media Markt","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Maplin":{"tags":{"name":"Maplin","shop":"electronics"},"name":"Maplin","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Best Buy":{"tags":{"name":"Best Buy","shop":"electronics"},"name":"Best Buy","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Future Shop":{"tags":{"name":"Future Shop","shop":"electronics"},"name":"Future Shop","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Saturn":{"tags":{"name":"Saturn","shop":"electronics"},"name":"Saturn","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Currys":{"tags":{"name":"Currys","shop":"electronics"},"name":"Currys","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Radio Shack":{"tags":{"name":"Radio Shack","shop":"electronics"},"name":"Radio Shack","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Euronics":{"tags":{"name":"Euronics","shop":"electronics"},"name":"Euronics","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Expert":{"tags":{"name":"Expert","shop":"electronics"},"name":"Expert","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Эльдорадо":{"tags":{"name":"Эльдорадо","shop":"electronics"},"name":"Эльдорадо","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/Darty":{"tags":{"name":"Darty","shop":"electronics"},"name":"Darty","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/М.Видео":{"tags":{"name":"М.Видео","shop":"electronics"},"name":"М.Видео","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/electronics/ヤマダ電機":{"tags":{"name":"ヤマダ電機","shop":"electronics"},"name":"ヤマダ電機","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/McColl's":{"tags":{"name":"McColl's","shop":"convenience"},"name":"McColl's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Tesco Express":{"tags":{"name":"Tesco Express","shop":"convenience"},"name":"Tesco Express","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/One Stop":{"tags":{"name":"One Stop","shop":"convenience"},"name":"One Stop","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Londis":{"tags":{"name":"Londis","shop":"convenience"},"name":"Londis","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/7-Eleven":{"tags":{"name":"7-Eleven","shop":"convenience"},"name":"7-Eleven","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Sale":{"tags":{"name":"Sale","shop":"convenience"},"name":"Sale","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Siwa":{"tags":{"name":"Siwa","shop":"convenience"},"name":"Siwa","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/COOP Jednota":{"tags":{"name":"COOP Jednota","shop":"convenience"},"name":"COOP Jednota","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mac's":{"tags":{"name":"Mac's","shop":"convenience"},"name":"Mac's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Alepa":{"tags":{"name":"Alepa","shop":"convenience"},"name":"Alepa","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Hasty Market":{"tags":{"name":"Hasty Market","shop":"convenience"},"name":"Hasty Market","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/K-Market":{"tags":{"name":"K-Market","shop":"convenience"},"name":"K-Market","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Costcutter":{"tags":{"name":"Costcutter","shop":"convenience"},"name":"Costcutter","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Valintatalo":{"tags":{"name":"Valintatalo","shop":"convenience"},"name":"Valintatalo","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Circle K":{"tags":{"name":"Circle K","shop":"convenience"},"name":"Circle K","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/セブンイレブン":{"tags":{"name":"セブンイレブン","name:en":"7-Eleven","shop":"convenience"},"name":"セブンイレブン","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ローソン":{"tags":{"name":"ローソン","name:en":"LAWSON","shop":"convenience"},"name":"ローソン","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Petit Casino":{"tags":{"name":"Petit Casino","shop":"convenience"},"name":"Petit Casino","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mace":{"tags":{"name":"Mace","shop":"convenience"},"name":"Mace","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mini Market":{"tags":{"name":"Mini Market","shop":"convenience"},"name":"Mini Market","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Nisa Local":{"tags":{"name":"Nisa Local","shop":"convenience"},"name":"Nisa Local","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Dorfladen":{"tags":{"name":"Dorfladen","shop":"convenience"},"name":"Dorfladen","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Продукты":{"tags":{"name":"Продукты","shop":"convenience"},"name":"Продукты","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mini Stop":{"tags":{"name":"Mini Stop","shop":"convenience"},"name":"Mini Stop","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/LAWSON":{"tags":{"name":"LAWSON","shop":"convenience"},"name":"LAWSON","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/デイリーヤマザキ":{"tags":{"name":"デイリーヤマザキ","shop":"convenience"},"name":"デイリーヤマザキ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Надежда":{"tags":{"name":"Надежда","shop":"convenience"},"name":"Надежда","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Nisa":{"tags":{"name":"Nisa","shop":"convenience"},"name":"Nisa","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Premier":{"tags":{"name":"Premier","shop":"convenience"},"name":"Premier","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ABC":{"tags":{"name":"ABC","shop":"convenience"},"name":"ABC","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ミニストップ":{"tags":{"name":"ミニストップ","name:en":"MINISTOP","shop":"convenience"},"name":"ミニストップ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/サンクス":{"tags":{"name":"サンクス","name:en":"sunkus","shop":"convenience"},"name":"サンクス","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/スリーエフ":{"tags":{"name":"スリーエフ","shop":"convenience"},"name":"スリーエフ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/8 à Huit":{"tags":{"name":"8 à Huit","shop":"convenience"},"name":"8 à Huit","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Żabka":{"tags":{"name":"Żabka","shop":"convenience"},"name":"Żabka","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Almacen":{"tags":{"name":"Almacen","shop":"convenience"},"name":"Almacen","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Vival":{"tags":{"name":"Vival","shop":"convenience"},"name":"Vival","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/FamilyMart":{"tags":{"name":"FamilyMart","shop":"convenience"},"name":"FamilyMart","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ファミリーマート":{"tags":{"name":"ファミリーマート","name:en":"FamilyMart","shop":"convenience"},"name":"ファミリーマート","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Sunkus":{"tags":{"name":"Sunkus","shop":"convenience"},"name":"Sunkus","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/セブンイレブン(Seven-Eleven)":{"tags":{"name":"セブンイレブン(Seven-Eleven)","shop":"convenience"},"name":"セブンイレブン(Seven-Eleven)","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Jednota":{"tags":{"name":"Jednota","shop":"convenience"},"name":"Jednota","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Магазин":{"tags":{"name":"Магазин","shop":"convenience"},"name":"Магазин","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Гастроном":{"tags":{"name":"Гастроном","shop":"convenience"},"name":"Гастроном","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Centra":{"tags":{"name":"Centra","shop":"convenience"},"name":"Centra","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/サークルK":{"tags":{"name":"サークルK","name:en":"Circle K","shop":"convenience"},"name":"サークルK","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Wawa":{"tags":{"name":"Wawa","shop":"convenience"},"name":"Wawa","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Proxi":{"tags":{"name":"Proxi","shop":"convenience"},"name":"Proxi","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Универсам":{"tags":{"name":"Универсам","shop":"convenience"},"name":"Универсам","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Groszek":{"tags":{"name":"Groszek","shop":"convenience"},"name":"Groszek","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Select":{"tags":{"name":"Select","shop":"convenience"},"name":"Select","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Večerka":{"tags":{"name":"Večerka","shop":"convenience"},"name":"Večerka","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Potraviny":{"tags":{"name":"Potraviny","shop":"convenience"},"name":"Potraviny","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Смак":{"tags":{"name":"Смак","shop":"convenience"},"name":"Смак","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Эконом":{"tags":{"name":"Эконом","shop":"convenience"},"name":"Эконом","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Березка":{"tags":{"name":"Березка","shop":"convenience"},"name":"Березка","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Społem":{"tags":{"name":"Społem","shop":"convenience"},"name":"Społem","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Cumberland Farms":{"tags":{"name":"Cumberland Farms","shop":"convenience"},"name":"Cumberland Farms","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Tesco Lotus Express":{"tags":{"name":"Tesco Lotus Express","shop":"convenience"},"name":"Tesco Lotus Express","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Kiosk":{"tags":{"name":"Kiosk","shop":"convenience"},"name":"Kiosk","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Sklep spożywczy":{"tags":{"name":"Sklep spożywczy","shop":"convenience"},"name":"Sklep spożywczy","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/24 часа":{"tags":{"name":"24 часа","shop":"convenience"},"name":"24 часа","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Минимаркет":{"tags":{"name":"Минимаркет","shop":"convenience"},"name":"Минимаркет","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Oxxo":{"tags":{"name":"Oxxo","shop":"convenience"},"name":"Oxxo","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/abc":{"tags":{"name":"abc","shop":"convenience"},"name":"abc","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/7/11":{"tags":{"name":"7/11","shop":"convenience"},"name":"7/11","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Stewart's":{"tags":{"name":"Stewart's","shop":"convenience"},"name":"Stewart's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Продукти":{"tags":{"name":"Продукти","shop":"convenience"},"name":"Продукти","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ローソンストア100 (LAWSON STORE 100)":{"tags":{"name":"ローソンストア100 (LAWSON STORE 100)","shop":"convenience"},"name":"ローソンストア100 (LAWSON STORE 100)","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Радуга":{"tags":{"name":"Радуга","shop":"convenience"},"name":"Радуга","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ローソンストア100":{"tags":{"name":"ローソンストア100","shop":"convenience"},"name":"ローソンストア100","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/เซเว่นอีเลฟเว่น":{"tags":{"name":"เซเว่นอีเลฟเว่น","shop":"convenience"},"name":"เซเว่นอีเลฟเว่น","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Фортуна":{"tags":{"name":"Фортуна","shop":"convenience"},"name":"Фортуна","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Picard":{"tags":{"name":"Picard","shop":"convenience"},"name":"Picard","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Four Square":{"tags":{"name":"Four Square","shop":"convenience"},"name":"Four Square","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Визит":{"tags":{"name":"Визит","shop":"convenience"},"name":"Визит","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Авоська":{"tags":{"name":"Авоська","shop":"convenience"},"name":"Авоська","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Dollar General":{"tags":{"name":"Dollar General","shop":"convenience"},"name":"Dollar General","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Studenac":{"tags":{"name":"Studenac","shop":"convenience"},"name":"Studenac","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Central Convenience Store":{"tags":{"name":"Central Convenience Store","shop":"convenience"},"name":"Central Convenience Store","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/продукты":{"tags":{"name":"продукты","shop":"convenience"},"name":"продукты","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Кулинария":{"tags":{"name":"Кулинария","shop":"convenience"},"name":"Кулинария","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/全家":{"tags":{"name":"全家","shop":"convenience"},"name":"全家","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Мечта":{"tags":{"name":"Мечта","shop":"convenience"},"name":"Мечта","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Epicerie":{"tags":{"name":"Epicerie","shop":"convenience"},"name":"Epicerie","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Кировский":{"tags":{"name":"Кировский","shop":"convenience"},"name":"Кировский","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Food Mart":{"tags":{"name":"Food Mart","shop":"convenience"},"name":"Food Mart","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Delikatesy":{"tags":{"name":"Delikatesy","shop":"convenience"},"name":"Delikatesy","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/ポプラ":{"tags":{"name":"ポプラ","shop":"convenience"},"name":"ポプラ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Lewiatan":{"tags":{"name":"Lewiatan","shop":"convenience"},"name":"Lewiatan","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Продуктовый магазин":{"tags":{"name":"Продуктовый магазин","shop":"convenience"},"name":"Продуктовый магазин","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Продуктовый":{"tags":{"name":"Продуктовый","shop":"convenience"},"name":"Продуктовый","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/セイコーマート (Seicomart)":{"tags":{"name":"セイコーマート (Seicomart)","shop":"convenience"},"name":"セイコーマート (Seicomart)","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Виктория":{"tags":{"name":"Виктория","shop":"convenience"},"name":"Виктория","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Весна":{"tags":{"name":"Весна","shop":"convenience"},"name":"Весна","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Mini Market Non-Stop":{"tags":{"name":"Mini Market Non-Stop","shop":"convenience"},"name":"Mini Market Non-Stop","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Копеечка":{"tags":{"name":"Копеечка","shop":"convenience"},"name":"Копеечка","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Royal Farms":{"tags":{"name":"Royal Farms","shop":"convenience"},"name":"Royal Farms","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Alfamart":{"tags":{"name":"Alfamart","shop":"convenience"},"name":"Alfamart","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Indomaret":{"tags":{"name":"Indomaret","shop":"convenience"},"name":"Indomaret","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/магазин":{"tags":{"name":"магазин","shop":"convenience"},"name":"магазин","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/全家便利商店":{"tags":{"name":"全家便利商店","shop":"convenience"},"name":"全家便利商店","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Boutique":{"tags":{"name":"Boutique","shop":"convenience"},"name":"Boutique","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/მარკეტი (Market)":{"tags":{"name":"მარკეტი (Market)","shop":"convenience"},"name":"მარკეტი (Market)","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/convenience/Stores":{"tags":{"name":"Stores","shop":"convenience"},"name":"Stores","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/dm":{"tags":{"name":"dm","shop":"chemist"},"name":"dm","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Müller":{"tags":{"name":"Müller","shop":"chemist"},"name":"Müller","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Schlecker":{"tags":{"name":"Schlecker","shop":"chemist"},"name":"Schlecker","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Etos":{"tags":{"name":"Etos","shop":"chemist"},"name":"Etos","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Bipa":{"tags":{"name":"Bipa","shop":"chemist"},"name":"Bipa","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Rossmann":{"tags":{"name":"Rossmann","shop":"chemist"},"name":"Rossmann","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/DM Drogeriemarkt":{"tags":{"name":"DM Drogeriemarkt","shop":"chemist"},"name":"DM Drogeriemarkt","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Ihr Platz":{"tags":{"name":"Ihr Platz","shop":"chemist"},"name":"Ihr Platz","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Douglas":{"tags":{"name":"Douglas","shop":"chemist"},"name":"Douglas","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/chemist/Kruidvat":{"tags":{"name":"Kruidvat","shop":"chemist"},"name":"Kruidvat","icon":"grocery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/car_repair/Kwik Fit":{"tags":{"name":"Kwik Fit","shop":"car_repair"},"name":"Kwik Fit","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/ATU":{"tags":{"name":"ATU","shop":"car_repair"},"name":"ATU","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Midas":{"tags":{"name":"Midas","shop":"car_repair"},"name":"Midas","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Feu Vert":{"tags":{"name":"Feu Vert","shop":"car_repair"},"name":"Feu Vert","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Norauto":{"tags":{"name":"Norauto","shop":"car_repair"},"name":"Norauto","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Speedy":{"tags":{"name":"Speedy","shop":"car_repair"},"name":"Speedy","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Pit Stop":{"tags":{"name":"Pit Stop","shop":"car_repair"},"name":"Pit Stop","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Jiffy Lube":{"tags":{"name":"Jiffy Lube","shop":"car_repair"},"name":"Jiffy Lube","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Шиномонтаж":{"tags":{"name":"Шиномонтаж","shop":"car_repair"},"name":"Шиномонтаж","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/СТО":{"tags":{"name":"СТО","shop":"car_repair"},"name":"СТО","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/O'Reilly Auto Parts":{"tags":{"name":"O'Reilly Auto Parts","shop":"car_repair"},"name":"O'Reilly Auto Parts","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Carglass":{"tags":{"name":"Carglass","shop":"car_repair"},"name":"Carglass","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/шиномонтаж":{"tags":{"name":"шиномонтаж","shop":"car_repair"},"name":"шиномонтаж","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Euromaster":{"tags":{"name":"Euromaster","shop":"car_repair"},"name":"Euromaster","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Firestone":{"tags":{"name":"Firestone","shop":"car_repair"},"name":"Firestone","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Автосервис":{"tags":{"name":"Автосервис","shop":"car_repair"},"name":"Автосервис","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Advance Auto Parts":{"tags":{"name":"Advance Auto Parts","shop":"car_repair"},"name":"Advance Auto Parts","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/car_repair/Roady":{"tags":{"name":"Roady","shop":"car_repair"},"name":"Roady","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","service/vehicle"],"suggestion":true},"shop/furniture/IKEA":{"tags":{"name":"IKEA","shop":"furniture"},"name":"IKEA","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Jysk":{"tags":{"name":"Jysk","shop":"furniture"},"name":"Jysk","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Roller":{"tags":{"name":"Roller","shop":"furniture"},"name":"Roller","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Dänisches Bettenlager":{"tags":{"name":"Dänisches Bettenlager","shop":"furniture"},"name":"Dänisches Bettenlager","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Conforama":{"tags":{"name":"Conforama","shop":"furniture"},"name":"Conforama","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Matratzen Concord":{"tags":{"name":"Matratzen Concord","shop":"furniture"},"name":"Matratzen Concord","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/Мебель":{"tags":{"name":"Мебель","shop":"furniture"},"name":"Мебель","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/furniture/But":{"tags":{"name":"But","shop":"furniture"},"name":"But","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hornbach":{"tags":{"name":"Hornbach","shop":"doityourself"},"name":"Hornbach","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/B&Q":{"tags":{"name":"B&Q","shop":"doityourself"},"name":"B&Q","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hubo":{"tags":{"name":"Hubo","shop":"doityourself"},"name":"Hubo","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Mr Bricolage":{"tags":{"name":"Mr Bricolage","shop":"doityourself"},"name":"Mr Bricolage","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Gamma":{"tags":{"name":"Gamma","shop":"doityourself"},"name":"Gamma","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/OBI":{"tags":{"name":"OBI","shop":"doityourself"},"name":"OBI","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Lowes":{"tags":{"name":"Lowes","shop":"doityourself"},"name":"Lowes","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Wickes":{"tags":{"name":"Wickes","shop":"doityourself"},"name":"Wickes","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hagebau":{"tags":{"name":"Hagebau","shop":"doityourself"},"name":"Hagebau","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Max Bahr":{"tags":{"name":"Max Bahr","shop":"doityourself"},"name":"Max Bahr","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Castorama":{"tags":{"name":"Castorama","shop":"doityourself"},"name":"Castorama","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Rona":{"tags":{"name":"Rona","shop":"doityourself"},"name":"Rona","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Home Depot":{"tags":{"name":"Home Depot","shop":"doityourself"},"name":"Home Depot","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Toom Baumarkt":{"tags":{"name":"Toom Baumarkt","shop":"doityourself"},"name":"Toom Baumarkt","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Homebase":{"tags":{"name":"Homebase","shop":"doityourself"},"name":"Homebase","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Baumax":{"tags":{"name":"Baumax","shop":"doityourself"},"name":"Baumax","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Lagerhaus":{"tags":{"name":"Lagerhaus","shop":"doityourself"},"name":"Lagerhaus","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Bauhaus":{"tags":{"name":"Bauhaus","shop":"doityourself"},"name":"Bauhaus","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Canadian Tire":{"tags":{"name":"Canadian Tire","shop":"doityourself"},"name":"Canadian Tire","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Leroy Merlin":{"tags":{"name":"Leroy Merlin","shop":"doityourself"},"name":"Leroy Merlin","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hellweg":{"tags":{"name":"Hellweg","shop":"doityourself"},"name":"Hellweg","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Brico":{"tags":{"name":"Brico","shop":"doityourself"},"name":"Brico","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Bricomarché":{"tags":{"name":"Bricomarché","shop":"doityourself"},"name":"Bricomarché","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Toom":{"tags":{"name":"Toom","shop":"doityourself"},"name":"Toom","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Hagebaumarkt":{"tags":{"name":"Hagebaumarkt","shop":"doityourself"},"name":"Hagebaumarkt","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Praktiker":{"tags":{"name":"Praktiker","shop":"doityourself"},"name":"Praktiker","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Menards":{"tags":{"name":"Menards","shop":"doityourself"},"name":"Menards","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Weldom":{"tags":{"name":"Weldom","shop":"doityourself"},"name":"Weldom","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Bunnings Warehouse":{"tags":{"name":"Bunnings Warehouse","shop":"doityourself"},"name":"Bunnings Warehouse","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Ace Hardware":{"tags":{"name":"Ace Hardware","shop":"doityourself"},"name":"Ace Hardware","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Home Hardware":{"tags":{"name":"Home Hardware","shop":"doityourself"},"name":"Home Hardware","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Стройматериалы":{"tags":{"name":"Стройматериалы","shop":"doityourself"},"name":"Стройматериалы","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Bricorama":{"tags":{"name":"Bricorama","shop":"doityourself"},"name":"Bricorama","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/doityourself/Point P":{"tags":{"name":"Point P","shop":"doityourself"},"name":"Point P","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/stationery/Staples":{"tags":{"name":"Staples","shop":"stationery"},"name":"Staples","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/stationery/McPaper":{"tags":{"name":"McPaper","shop":"stationery"},"name":"McPaper","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/stationery/Office Depot":{"tags":{"name":"Office Depot","shop":"stationery"},"name":"Office Depot","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/stationery/Канцтовары":{"tags":{"name":"Канцтовары","shop":"stationery"},"name":"Канцтовары","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/car/Skoda":{"tags":{"name":"Skoda","shop":"car"},"name":"Skoda","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/BMW":{"tags":{"name":"BMW","shop":"car"},"name":"BMW","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Citroen":{"tags":{"name":"Citroen","shop":"car"},"name":"Citroen","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Renault":{"tags":{"name":"Renault","shop":"car"},"name":"Renault","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Mercedes-Benz":{"tags":{"name":"Mercedes-Benz","shop":"car"},"name":"Mercedes-Benz","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Volvo":{"tags":{"name":"Volvo","shop":"car"},"name":"Volvo","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Ford":{"tags":{"name":"Ford","shop":"car"},"name":"Ford","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Volkswagen":{"tags":{"name":"Volkswagen","shop":"car"},"name":"Volkswagen","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Mazda":{"tags":{"name":"Mazda","shop":"car"},"name":"Mazda","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Mitsubishi":{"tags":{"name":"Mitsubishi","shop":"car"},"name":"Mitsubishi","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Fiat":{"tags":{"name":"Fiat","shop":"car"},"name":"Fiat","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Автозапчасти":{"tags":{"name":"Автозапчасти","shop":"car"},"name":"Автозапчасти","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Opel":{"tags":{"name":"Opel","shop":"car"},"name":"Opel","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Audi":{"tags":{"name":"Audi","shop":"car"},"name":"Audi","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Toyota":{"tags":{"name":"Toyota","shop":"car"},"name":"Toyota","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Nissan":{"tags":{"name":"Nissan","shop":"car"},"name":"Nissan","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Suzuki":{"tags":{"name":"Suzuki","shop":"car"},"name":"Suzuki","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Honda":{"tags":{"name":"Honda","shop":"car"},"name":"Honda","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Peugeot":{"tags":{"name":"Peugeot","shop":"car"},"name":"Peugeot","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Hyundai":{"tags":{"name":"Hyundai","shop":"car"},"name":"Hyundai","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Subaru":{"tags":{"name":"Subaru","shop":"car"},"name":"Subaru","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Chevrolet":{"tags":{"name":"Chevrolet","shop":"car"},"name":"Chevrolet","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/car/Автомагазин":{"tags":{"name":"Автомагазин","shop":"car"},"name":"Автомагазин","icon":"car","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","second_hand","service/vehicle"],"suggestion":true},"shop/clothes/Matalan":{"tags":{"name":"Matalan","shop":"clothes"},"name":"Matalan","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/KiK":{"tags":{"name":"KiK","shop":"clothes"},"name":"KiK","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/H&M":{"tags":{"name":"H&M","shop":"clothes"},"name":"H&M","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Urban Outfitters":{"tags":{"name":"Urban Outfitters","shop":"clothes"},"name":"Urban Outfitters","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Vögele":{"tags":{"name":"Vögele","shop":"clothes"},"name":"Vögele","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Zeeman":{"tags":{"name":"Zeeman","shop":"clothes"},"name":"Zeeman","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Takko":{"tags":{"name":"Takko","shop":"clothes"},"name":"Takko","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/C&A":{"tags":{"name":"C&A","shop":"clothes"},"name":"C&A","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Zara":{"tags":{"name":"Zara","shop":"clothes"},"name":"Zara","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Vero Moda":{"tags":{"name":"Vero Moda","shop":"clothes"},"name":"Vero Moda","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/NKD":{"tags":{"name":"NKD","shop":"clothes"},"name":"NKD","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Ernsting's family":{"tags":{"name":"Ernsting's family","shop":"clothes"},"name":"Ernsting's family","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Winners":{"tags":{"name":"Winners","shop":"clothes"},"name":"Winners","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/River Island":{"tags":{"name":"River Island","shop":"clothes"},"name":"River Island","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Next":{"tags":{"name":"Next","shop":"clothes"},"name":"Next","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Gap":{"tags":{"name":"Gap","shop":"clothes"},"name":"Gap","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Adidas":{"tags":{"name":"Adidas","shop":"clothes"},"name":"Adidas","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Mr Price":{"tags":{"name":"Mr Price","shop":"clothes"},"name":"Mr Price","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Pep":{"tags":{"name":"Pep","shop":"clothes"},"name":"Pep","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Edgars":{"tags":{"name":"Edgars","shop":"clothes"},"name":"Edgars","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Ackermans":{"tags":{"name":"Ackermans","shop":"clothes"},"name":"Ackermans","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Truworths":{"tags":{"name":"Truworths","shop":"clothes"},"name":"Truworths","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Ross":{"tags":{"name":"Ross","shop":"clothes"},"name":"Ross","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Burton":{"tags":{"name":"Burton","shop":"clothes"},"name":"Burton","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Dorothy Perkins":{"tags":{"name":"Dorothy Perkins","shop":"clothes"},"name":"Dorothy Perkins","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Lindex":{"tags":{"name":"Lindex","shop":"clothes"},"name":"Lindex","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/s.Oliver":{"tags":{"name":"s.Oliver","shop":"clothes"},"name":"s.Oliver","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Cecil":{"tags":{"name":"Cecil","shop":"clothes"},"name":"Cecil","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Dress Barn":{"tags":{"name":"Dress Barn","shop":"clothes"},"name":"Dress Barn","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Old Navy":{"tags":{"name":"Old Navy","shop":"clothes"},"name":"Old Navy","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Jack & Jones":{"tags":{"name":"Jack & Jones","shop":"clothes"},"name":"Jack & Jones","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Pimkie":{"tags":{"name":"Pimkie","shop":"clothes"},"name":"Pimkie","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Esprit":{"tags":{"name":"Esprit","shop":"clothes"},"name":"Esprit","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Primark":{"tags":{"name":"Primark","shop":"clothes"},"name":"Primark","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Bonita":{"tags":{"name":"Bonita","shop":"clothes"},"name":"Bonita","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Mexx":{"tags":{"name":"Mexx","shop":"clothes"},"name":"Mexx","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Gerry Weber":{"tags":{"name":"Gerry Weber","shop":"clothes"},"name":"Gerry Weber","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Tally Weijl":{"tags":{"name":"Tally Weijl","shop":"clothes"},"name":"Tally Weijl","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Mango":{"tags":{"name":"Mango","shop":"clothes"},"name":"Mango","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/TK Maxx":{"tags":{"name":"TK Maxx","shop":"clothes"},"name":"TK Maxx","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Benetton":{"tags":{"name":"Benetton","shop":"clothes"},"name":"Benetton","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Ulla Popken":{"tags":{"name":"Ulla Popken","shop":"clothes"},"name":"Ulla Popken","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/AWG":{"tags":{"name":"AWG","shop":"clothes"},"name":"AWG","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Tommy Hilfiger":{"tags":{"name":"Tommy Hilfiger","shop":"clothes"},"name":"Tommy Hilfiger","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/New Yorker":{"tags":{"name":"New Yorker","shop":"clothes"},"name":"New Yorker","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Orsay":{"tags":{"name":"Orsay","shop":"clothes"},"name":"Orsay","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Jeans Fritz":{"tags":{"name":"Jeans Fritz","shop":"clothes"},"name":"Jeans Fritz","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Charles Vögele":{"tags":{"name":"Charles Vögele","shop":"clothes"},"name":"Charles Vögele","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/New Look":{"tags":{"name":"New Look","shop":"clothes"},"name":"New Look","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Lacoste":{"tags":{"name":"Lacoste","shop":"clothes"},"name":"Lacoste","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Etam":{"tags":{"name":"Etam","shop":"clothes"},"name":"Etam","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Kiabi":{"tags":{"name":"Kiabi","shop":"clothes"},"name":"Kiabi","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Jack Wolfskin":{"tags":{"name":"Jack Wolfskin","shop":"clothes"},"name":"Jack Wolfskin","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/American Apparel":{"tags":{"name":"American Apparel","shop":"clothes"},"name":"American Apparel","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Men's Wearhouse":{"tags":{"name":"Men's Wearhouse","shop":"clothes"},"name":"Men's Wearhouse","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Intimissimi":{"tags":{"name":"Intimissimi","shop":"clothes"},"name":"Intimissimi","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/United Colors of Benetton":{"tags":{"name":"United Colors of Benetton","shop":"clothes"},"name":"United Colors of Benetton","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Jules":{"tags":{"name":"Jules","shop":"clothes"},"name":"Jules","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Second Hand":{"tags":{"name":"Second Hand","shop":"clothes"},"name":"Second Hand","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/AOKI":{"tags":{"name":"AOKI","shop":"clothes"},"name":"AOKI","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Calzedonia":{"tags":{"name":"Calzedonia","shop":"clothes"},"name":"Calzedonia","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/洋服の青山":{"tags":{"name":"洋服の青山","shop":"clothes"},"name":"洋服の青山","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Levi's":{"tags":{"name":"Levi's","shop":"clothes"},"name":"Levi's","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Celio":{"tags":{"name":"Celio","shop":"clothes"},"name":"Celio","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/TJ Maxx":{"tags":{"name":"TJ Maxx","shop":"clothes"},"name":"TJ Maxx","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Promod":{"tags":{"name":"Promod","shop":"clothes"},"name":"Promod","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Street One":{"tags":{"name":"Street One","shop":"clothes"},"name":"Street One","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/ユニクロ":{"tags":{"name":"ユニクロ","shop":"clothes"},"name":"ユニクロ","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Banana Republic":{"tags":{"name":"Banana Republic","shop":"clothes"},"name":"Banana Republic","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Одежда":{"tags":{"name":"Одежда","shop":"clothes"},"name":"Одежда","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Marshalls":{"tags":{"name":"Marshalls","shop":"clothes"},"name":"Marshalls","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/La Halle":{"tags":{"name":"La Halle","shop":"clothes"},"name":"La Halle","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/Peacocks":{"tags":{"name":"Peacocks","shop":"clothes"},"name":"Peacocks","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/clothes/しまむら":{"tags":{"name":"しまむら","shop":"clothes"},"name":"しまむら","icon":"clothing-store","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/books/Bruna":{"tags":{"name":"Bruna","shop":"books"},"name":"Bruna","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Waterstones":{"tags":{"name":"Waterstones","shop":"books"},"name":"Waterstones","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Libro":{"tags":{"name":"Libro","shop":"books"},"name":"Libro","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Barnes & Noble":{"tags":{"name":"Barnes & Noble","shop":"books"},"name":"Barnes & Noble","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Weltbild":{"tags":{"name":"Weltbild","shop":"books"},"name":"Weltbild","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Thalia":{"tags":{"name":"Thalia","shop":"books"},"name":"Thalia","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/books/Книги":{"tags":{"name":"Книги","shop":"books"},"name":"Книги","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","internet_access","internet_access/fee","internet_access/ssid"],"suggestion":true},"shop/department_store/Debenhams":{"tags":{"name":"Debenhams","shop":"department_store"},"name":"Debenhams","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Karstadt":{"tags":{"name":"Karstadt","shop":"department_store"},"name":"Karstadt","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Kmart":{"tags":{"name":"Kmart","shop":"department_store"},"name":"Kmart","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Target":{"tags":{"name":"Target","shop":"department_store"},"name":"Target","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Galeria Kaufhof":{"tags":{"name":"Galeria Kaufhof","shop":"department_store"},"name":"Galeria Kaufhof","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Marks & Spencer":{"tags":{"name":"Marks & Spencer","shop":"department_store"},"name":"Marks & Spencer","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Big W":{"tags":{"name":"Big W","shop":"department_store"},"name":"Big W","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Woolworth":{"tags":{"name":"Woolworth","shop":"department_store"},"name":"Woolworth","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Универмаг":{"tags":{"name":"Универмаг","shop":"department_store"},"name":"Универмаг","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Sears":{"tags":{"name":"Sears","shop":"department_store"},"name":"Sears","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Kohl's":{"tags":{"name":"Kohl's","shop":"department_store"},"name":"Kohl's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/Macy's":{"tags":{"name":"Macy's","shop":"department_store"},"name":"Macy's","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/department_store/JCPenney":{"tags":{"name":"JCPenney","shop":"department_store"},"name":"JCPenney","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/alcohol/Alko":{"tags":{"name":"Alko","shop":"alcohol"},"name":"Alko","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/The Beer Store":{"tags":{"name":"The Beer Store","shop":"alcohol"},"name":"The Beer Store","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Systembolaget":{"tags":{"name":"Systembolaget","shop":"alcohol"},"name":"Systembolaget","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/LCBO":{"tags":{"name":"LCBO","shop":"alcohol"},"name":"LCBO","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Ароматный мир":{"tags":{"name":"Ароматный мир","shop":"alcohol"},"name":"Ароматный мир","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Bargain Booze":{"tags":{"name":"Bargain Booze","shop":"alcohol"},"name":"Bargain Booze","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Nicolas":{"tags":{"name":"Nicolas","shop":"alcohol"},"name":"Nicolas","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/BWS":{"tags":{"name":"BWS","shop":"alcohol"},"name":"BWS","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Botilleria":{"tags":{"name":"Botilleria","shop":"alcohol"},"name":"Botilleria","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/SAQ":{"tags":{"name":"SAQ","shop":"alcohol"},"name":"SAQ","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Gall & Gall":{"tags":{"name":"Gall & Gall","shop":"alcohol"},"name":"Gall & Gall","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/alcohol/Живое пиво":{"tags":{"name":"Живое пиво","shop":"alcohol"},"name":"Живое пиво","icon":"alcohol-shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours","drive_through"],"suggestion":true},"shop/bakery/Kamps":{"tags":{"name":"Kamps","shop":"bakery"},"name":"Kamps","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Banette":{"tags":{"name":"Banette","shop":"bakery"},"name":"Banette","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Bäckerei Schmidt":{"tags":{"name":"Bäckerei Schmidt","shop":"bakery"},"name":"Bäckerei Schmidt","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Anker":{"tags":{"name":"Anker","shop":"bakery"},"name":"Anker","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Hofpfisterei":{"tags":{"name":"Hofpfisterei","shop":"bakery"},"name":"Hofpfisterei","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Greggs":{"tags":{"name":"Greggs","shop":"bakery"},"name":"Greggs","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Oebel":{"tags":{"name":"Oebel","shop":"bakery"},"name":"Oebel","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Boulangerie":{"tags":{"name":"Boulangerie","shop":"bakery"},"name":"Boulangerie","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Stadtbäckerei":{"tags":{"name":"Stadtbäckerei","shop":"bakery"},"name":"Stadtbäckerei","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Steinecke":{"tags":{"name":"Steinecke","shop":"bakery"},"name":"Steinecke","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Ihle":{"tags":{"name":"Ihle","shop":"bakery"},"name":"Ihle","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Goldilocks":{"tags":{"name":"Goldilocks","shop":"bakery"},"name":"Goldilocks","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Dat Backhus":{"tags":{"name":"Dat Backhus","shop":"bakery"},"name":"Dat Backhus","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/K&U":{"tags":{"name":"K&U","shop":"bakery"},"name":"K&U","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Der Beck":{"tags":{"name":"Der Beck","shop":"bakery"},"name":"Der Beck","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Thürmann":{"tags":{"name":"Thürmann","shop":"bakery"},"name":"Thürmann","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Backwerk":{"tags":{"name":"Backwerk","shop":"bakery"},"name":"Backwerk","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Schäfer's":{"tags":{"name":"Schäfer's","shop":"bakery"},"name":"Schäfer's","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Panaderia":{"tags":{"name":"Panaderia","shop":"bakery"},"name":"Panaderia","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Goeken backen":{"tags":{"name":"Goeken backen","shop":"bakery"},"name":"Goeken backen","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Stadtbäckerei Junge":{"tags":{"name":"Stadtbäckerei Junge","shop":"bakery"},"name":"Stadtbäckerei Junge","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Boulangerie Patisserie":{"tags":{"name":"Boulangerie Patisserie","shop":"bakery"},"name":"Boulangerie Patisserie","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Paul":{"tags":{"name":"Paul","shop":"bakery"},"name":"Paul","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Хлеб":{"tags":{"name":"Хлеб","shop":"bakery"},"name":"Хлеб","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Пекарня":{"tags":{"name":"Пекарня","shop":"bakery"},"name":"Пекарня","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/bakery/Кулиничи":{"tags":{"name":"Кулиничи","shop":"bakery"},"name":"Кулиничи","icon":"bakery","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Sports Direct":{"tags":{"name":"Sports Direct","shop":"sports"},"name":"Sports Direct","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Decathlon":{"tags":{"name":"Decathlon","shop":"sports"},"name":"Decathlon","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Intersport":{"tags":{"name":"Intersport","shop":"sports"},"name":"Intersport","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Sports Authority":{"tags":{"name":"Sports Authority","shop":"sports"},"name":"Sports Authority","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Спортмастер":{"tags":{"name":"Спортмастер","shop":"sports"},"name":"Спортмастер","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Sport 2000":{"tags":{"name":"Sport 2000","shop":"sports"},"name":"Sport 2000","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/sports/Dick's Sporting Goods":{"tags":{"name":"Dick's Sporting Goods","shop":"sports"},"name":"Dick's Sporting Goods","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/variety_store/Tedi":{"tags":{"name":"Tedi","shop":"variety_store"},"name":"Tedi","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/variety_store/Dollarama":{"tags":{"name":"Dollarama","shop":"variety_store"},"name":"Dollarama","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/variety_store/Family Dollar":{"tags":{"name":"Family Dollar","shop":"variety_store"},"name":"Family Dollar","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/variety_store/Dollar Tree":{"tags":{"name":"Dollar Tree","shop":"variety_store"},"name":"Dollar Tree","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Fressnapf":{"tags":{"name":"Fressnapf","shop":"pet"},"name":"Fressnapf","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/PetSmart":{"tags":{"name":"PetSmart","shop":"pet"},"name":"PetSmart","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Das Futterhaus":{"tags":{"name":"Das Futterhaus","shop":"pet"},"name":"Das Futterhaus","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Pets at Home":{"tags":{"name":"Pets at Home","shop":"pet"},"name":"Pets at Home","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Petco":{"tags":{"name":"Petco","shop":"pet"},"name":"Petco","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/pet/Зоомагазин":{"tags":{"name":"Зоомагазин","shop":"pet"},"name":"Зоомагазин","icon":"dog-park","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Deichmann":{"tags":{"name":"Deichmann","shop":"shoes"},"name":"Deichmann","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Reno":{"tags":{"name":"Reno","shop":"shoes"},"name":"Reno","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Ecco":{"tags":{"name":"Ecco","shop":"shoes"},"name":"Ecco","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Clarks":{"tags":{"name":"Clarks","shop":"shoes"},"name":"Clarks","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/La Halle aux Chaussures":{"tags":{"name":"La Halle aux Chaussures","shop":"shoes"},"name":"La Halle aux Chaussures","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Brantano":{"tags":{"name":"Brantano","shop":"shoes"},"name":"Brantano","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Geox":{"tags":{"name":"Geox","shop":"shoes"},"name":"Geox","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Salamander":{"tags":{"name":"Salamander","shop":"shoes"},"name":"Salamander","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Обувь":{"tags":{"name":"Обувь","shop":"shoes"},"name":"Обувь","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Payless Shoe Source":{"tags":{"name":"Payless Shoe Source","shop":"shoes"},"name":"Payless Shoe Source","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Famous Footwear":{"tags":{"name":"Famous Footwear","shop":"shoes"},"name":"Famous Footwear","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Quick Schuh":{"tags":{"name":"Quick Schuh","shop":"shoes"},"name":"Quick Schuh","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Shoe Zone":{"tags":{"name":"Shoe Zone","shop":"shoes"},"name":"Shoe Zone","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Foot Locker":{"tags":{"name":"Foot Locker","shop":"shoes"},"name":"Foot Locker","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/Bata":{"tags":{"name":"Bata","shop":"shoes"},"name":"Bata","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/shoes/ЦентрОбувь":{"tags":{"name":"ЦентрОбувь","shop":"shoes"},"name":"ЦентрОбувь","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/La Grande Récré":{"tags":{"name":"La Grande Récré","shop":"toys"},"name":"La Grande Récré","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/Toys R Us":{"tags":{"name":"Toys R Us","shop":"toys"},"name":"Toys R Us","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/Intertoys":{"tags":{"name":"Intertoys","shop":"toys"},"name":"Intertoys","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/Детский мир":{"tags":{"name":"Детский мир","shop":"toys"},"name":"Детский мир","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/toys/Игрушки":{"tags":{"name":"Игрушки","shop":"toys"},"name":"Игрушки","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/travel_agency/Flight Centre":{"tags":{"name":"Flight Centre","shop":"travel_agency"},"name":"Flight Centre","icon":"suitcase","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/travel_agency/Thomas Cook":{"tags":{"name":"Thomas Cook","shop":"travel_agency"},"name":"Thomas Cook","icon":"suitcase","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/jewelry/Bijou Brigitte":{"tags":{"name":"Bijou Brigitte","shop":"jewelry"},"name":"Bijou Brigitte","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/jewelry/Christ":{"tags":{"name":"Christ","shop":"jewelry"},"name":"Christ","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/jewelry/Swarovski":{"tags":{"name":"Swarovski","shop":"jewelry"},"name":"Swarovski","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Fielmann":{"tags":{"name":"Fielmann","shop":"optician"},"name":"Fielmann","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Apollo Optik":{"tags":{"name":"Apollo Optik","shop":"optician"},"name":"Apollo Optik","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Vision Express":{"tags":{"name":"Vision Express","shop":"optician"},"name":"Vision Express","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Оптика":{"tags":{"name":"Оптика","shop":"optician"},"name":"Оптика","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Optic 2000":{"tags":{"name":"Optic 2000","shop":"optician"},"name":"Optic 2000","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Alain Afflelou":{"tags":{"name":"Alain Afflelou","shop":"optician"},"name":"Alain Afflelou","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Specsavers":{"tags":{"name":"Specsavers","shop":"optician"},"name":"Specsavers","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Krys":{"tags":{"name":"Krys","shop":"optician"},"name":"Krys","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/optician/Atol":{"tags":{"name":"Atol","shop":"optician"},"name":"Atol","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/video/Blockbuster":{"tags":{"name":"Blockbuster","shop":"video"},"name":"Blockbuster","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/video/World of Video":{"tags":{"name":"World of Video","shop":"video"},"name":"World of Video","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Билайн":{"tags":{"name":"Билайн","shop":"mobile_phone"},"name":"Билайн","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/ソフトバンクショップ (SoftBank shop)":{"tags":{"name":"ソフトバンクショップ (SoftBank shop)","shop":"mobile_phone"},"name":"ソフトバンクショップ (SoftBank shop)","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Vodafone":{"tags":{"name":"Vodafone","shop":"mobile_phone"},"name":"Vodafone","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/O2":{"tags":{"name":"O2","shop":"mobile_phone"},"name":"O2","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Carphone Warehouse":{"tags":{"name":"Carphone Warehouse","shop":"mobile_phone"},"name":"Carphone Warehouse","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Orange":{"tags":{"name":"Orange","shop":"mobile_phone"},"name":"Orange","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Verizon Wireless":{"tags":{"name":"Verizon Wireless","shop":"mobile_phone"},"name":"Verizon Wireless","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Sprint":{"tags":{"name":"Sprint","shop":"mobile_phone"},"name":"Sprint","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/T-Mobile":{"tags":{"name":"T-Mobile","shop":"mobile_phone"},"name":"T-Mobile","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/МТС":{"tags":{"name":"МТС","shop":"mobile_phone"},"name":"МТС","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Евросеть":{"tags":{"name":"Евросеть","shop":"mobile_phone"},"name":"Евросеть","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Bell":{"tags":{"name":"Bell","shop":"mobile_phone"},"name":"Bell","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/The Phone House":{"tags":{"name":"The Phone House","shop":"mobile_phone"},"name":"The Phone House","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/SFR":{"tags":{"name":"SFR","shop":"mobile_phone"},"name":"SFR","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Связной":{"tags":{"name":"Связной","shop":"mobile_phone"},"name":"Связной","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Мегафон":{"tags":{"name":"Мегафон","shop":"mobile_phone"},"name":"Мегафон","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/AT&T":{"tags":{"name":"AT&T","shop":"mobile_phone"},"name":"AT&T","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/ドコモショップ (docomo shop)":{"tags":{"name":"ドコモショップ (docomo shop)","shop":"mobile_phone"},"name":"ドコモショップ (docomo shop)","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/au":{"tags":{"name":"au","shop":"mobile_phone"},"name":"au","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Movistar":{"tags":{"name":"Movistar","shop":"mobile_phone"},"name":"Movistar","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/mobile_phone/Bitė":{"tags":{"name":"Bitė","shop":"mobile_phone"},"name":"Bitė","icon":"mobile-phone","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/computer/PC World":{"tags":{"name":"PC World","shop":"computer"},"name":"PC World","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/computer/DNS":{"tags":{"name":"DNS","shop":"computer"},"name":"DNS","icon":"shop","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Klier":{"tags":{"name":"Klier","shop":"hairdresser"},"name":"Klier","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Supercuts":{"tags":{"name":"Supercuts","shop":"hairdresser"},"name":"Supercuts","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Hairkiller":{"tags":{"name":"Hairkiller","shop":"hairdresser"},"name":"Hairkiller","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Great Clips":{"tags":{"name":"Great Clips","shop":"hairdresser"},"name":"Great Clips","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Парикмахерская":{"tags":{"name":"Парикмахерская","shop":"hairdresser"},"name":"Парикмахерская","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Стиль":{"tags":{"name":"Стиль","shop":"hairdresser"},"name":"Стиль","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Franck Provost":{"tags":{"name":"Franck Provost","shop":"hairdresser"},"name":"Franck Provost","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hairdresser/Салон красоты":{"tags":{"name":"Салон красоты","shop":"hairdresser"},"name":"Салон красоты","icon":"hairdresser","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hardware/1000 мелочей":{"tags":{"name":"1000 мелочей","shop":"hardware"},"name":"1000 мелочей","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/hardware/Хозтовары":{"tags":{"name":"Хозтовары","shop":"hardware"},"name":"Хозтовары","icon":"poi-tool","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true},"shop/motorcycle/Yamaha":{"tags":{"name":"Yamaha","shop":"motorcycle"},"name":"Yamaha","icon":"scooter","geometry":["point","area"],"fields":["operator","address","building_area","opening_hours"],"suggestion":true}};
18628
18629 var defaults = {"area":["category-landuse","category-building","category-water-area","category-natural-area","leisure/park","amenity/hospital","amenity/place_of_worship","amenity/cafe","amenity/restaurant","area"],"line":["category-road","category-rail","category-path","category-water-line","category-barrier","category-natural-line","power/line","line"],"point":["category-natural-point","leisure/park","amenity/hospital","amenity/place_of_worship","amenity/cafe","amenity/restaurant","amenity/fast_food","amenity/bar","amenity/bank","shop/supermarket","point"],"vertex":["highway/crosswalk","highway/crossing","railway/level_crossing","highway/traffic_signals","highway/turning_circle","highway/turning_loop","traffic_calming","highway/mini_roundabout","highway/motorway_junction","vertex"],"relation":["category-route","category-restriction","type/boundary","type/multipolygon","type/site","relation"]};
18630
18631 var categories = {"category-barrier":{"icon":"roadblock","geometry":"line","name":"Barrier Features","members":["barrier/fence","barrier/wall","barrier/ditch","barrier/gate","barrier"]},"category-building":{"icon":"building","geometry":"area","name":"Building Features","members":["building","building/house","building/apartments","building/commercial","building/industrial","building/residential"]},"category-golf":{"icon":"golf","geometry":"area","name":"Golf Features","members":["golf/fairway","golf/green","golf/lateral_water_hazard_area","golf/rough","golf/bunker","golf/tee","golf/water_hazard_area"]},"category-landuse":{"icon":"landuse","geometry":"area","name":"Land Use Features","members":["landuse/residential","landuse/industrial","landuse/commercial","landuse/retail","landuse/farmland","landuse/farmyard","landuse/forest","landuse/meadow","landuse/aquaculture","landuse/cemetery","landuse/military"]},"category-natural-area":{"icon":"natural","geometry":"area","name":"Natural Features","members":["natural/water","natural/wood","natural/scrub","natural/wetland","natural/grassland","natural/heath","natural/bare_rock","natural/beach","natural/cave_entrance","natural/glacier"]},"category-natural-line":{"icon":"natural","geometry":"line","name":"Natural Features","members":["natural/coastline","natural/tree_row"]},"category-natural-point":{"icon":"natural","geometry":"point","name":"Natural Features","members":["natural/peak","natural/cliff","natural/beach","natural/cave_entrance"]},"category-path":{"icon":"category-path","geometry":"line","name":"Path Features","members":["footway/crosswalk","footway/sidewalk","highway/steps","highway/path","highway/footway","highway/cycleway","highway/bridleway","highway/pedestrian"]},"category-rail":{"icon":"category-rail","geometry":"line","name":"Rail Features","members":["railway/rail","railway/subway","railway/tram","railway/monorail","railway/disused","railway/abandoned"]},"category-restriction":{"icon":"restriction","geometry":"relation","name":"Restriction Features","members":["type/restriction/no_left_turn","type/restriction/no_right_turn","type/restriction/no_straight_on","type/restriction/no_u_turn","type/restriction/only_left_turn","type/restriction/only_right_turn","type/restriction/only_straight_on","type/restriction"]},"category-road":{"icon":"category-roads","geometry":"line","name":"Road Features","members":["highway/residential","highway/motorway","highway/trunk","highway/primary","highway/secondary","highway/tertiary","highway/living_street","highway/unclassified","highway/service","highway/track","highway/motorway_link","highway/trunk_link","highway/primary_link","highway/secondary_link","highway/tertiary_link","highway/road"]},"category-route":{"icon":"route","geometry":"relation","name":"Route Features","members":["type/route/road","type/route/bicycle","type/route/foot","type/route/hiking","type/route/horse","type/route/bus","type/route/train","type/route/tram","type/route/ferry","type/route/power","type/route/pipeline","type/route/detour","type/route_master","type/route"]},"category-water-area":{"icon":"water","geometry":"area","name":"Water Features","members":["natural/water/lake","natural/water/pond","natural/water/reservoir","natural/water"]},"category-water-line":{"icon":"category-water","geometry":"line","name":"Water Features","members":["waterway/river","waterway/stream","waterway/canal","waterway/ditch","waterway/drain"]}};
18632
18633 var fields = {"access_simple":{"key":"access","type":"combo","label":"Allowed Access","options":["permissive","private","customers","no"]},"access_toilets":{"key":"access","type":"combo","label":"Access","options":["yes","permissive","private","customers"]},"access":{"keys":["access","foot","motor_vehicle","bicycle","horse"],"reference":{"key":"access"},"type":"access","label":"Allowed Access","placeholder":"Not Specified","strings":{"types":{"access":"All","foot":"Foot","motor_vehicle":"Motor Vehicles","bicycle":"Bicycles","horse":"Horses"},"options":{"yes":{"title":"Allowed","description":"Access permitted by law; a right of way"},"no":{"title":"Prohibited","description":"Access not permitted to the general public"},"permissive":{"title":"Permissive","description":"Access permitted until such time as the owner revokes the permission"},"private":{"title":"Private","description":"Access permitted only with permission of the owner on an individual basis"},"designated":{"title":"Designated","description":"Access permitted according to signs or specific local laws"},"destination":{"title":"Destination","description":"Access permitted only to reach a destination"},"dismount":{"title":"Dismount","description":"Access permitted but rider must dismount"}}}},"address":{"type":"address","keys":["addr:block_number","addr:city","addr:block_number","addr:conscriptionnumber","addr:county","addr:country","addr:county","addr:district","addr:floor","addr:hamlet","addr:housename","addr:housenumber","addr:neighbourhood","addr:place","addr:postcode","addr:province","addr:quarter","addr:state","addr:street","addr:subdistrict","addr:suburb"],"reference":{"key":"addr"},"icon":"address","universal":true,"label":"Address","strings":{"placeholders":{"block_number":"Block Number","block_number!jp":"Block No.","city":"City","city!jp":"City/Town/Village/Tokyo Special Ward","city!vn":"City/Town","conscriptionnumber":"123","country":"Country","county":"County","county!jp":"District","district":"District","district!vn":"Arrondissement/Town/District","floor":"Floor","hamlet":"Hamlet","housename":"Housename","housenumber":"123","housenumber!jp":"Building No./Lot No.","neighbourhood":"Neighbourhood","neighbourhood!jp":"Chōme/Aza/Koaza","place":"Place","postcode":"Postcode","province":"Province","province!jp":"Prefecture","quarter":"Quarter","quarter!jp":"Ōaza/Machi","state":"State","street":"Street","subdistrict":"Subdistrict","subdistrict!vn":"Ward/Commune/Townlet","suburb":"Suburb","suburb!jp":"Ward"}}},"admin_level":{"key":"admin_level","type":"number","label":"Admin Level"},"aerialway":{"key":"aerialway","type":"typeCombo","label":"Type"},"aerialway/access":{"key":"aerialway:access","type":"combo","label":"Access","strings":{"options":{"entry":"Entry","exit":"Exit","both":"Both"}}},"aerialway/bubble":{"key":"aerialway:bubble","type":"check","label":"Bubble"},"aerialway/capacity":{"key":"aerialway:capacity","type":"number","label":"Capacity (per hour)","placeholder":"500, 2500, 5000..."},"aerialway/duration":{"key":"aerialway:duration","type":"number","label":"Duration (minutes)","placeholder":"1, 2, 3..."},"aerialway/heating":{"key":"aerialway:heating","type":"check","label":"Heated"},"aerialway/occupancy":{"key":"aerialway:occupancy","type":"number","label":"Occupancy","placeholder":"2, 4, 8..."},"aerialway/summer/access":{"key":"aerialway:summer:access","type":"combo","label":"Access (summer)","strings":{"options":{"entry":"Entry","exit":"Exit","both":"Both"}}},"aeroway":{"key":"aeroway","type":"typeCombo","label":"Type"},"amenity":{"key":"amenity","type":"typeCombo","label":"Type"},"animal_boarding":{"key":"animal_boarding","type":"semiCombo","label":"For Animals"},"animal_breeding":{"key":"animal_breeding","type":"semiCombo","label":"For Animals"},"animal_shelter":{"key":"animal_shelter","type":"semiCombo","label":"For Animals"},"area/highway":{"key":"area:highway","type":"typeCombo","label":"Type"},"artist":{"key":"artist_name","type":"text","label":"Artist"},"artwork_type":{"key":"artwork_type","type":"combo","label":"Type"},"atm":{"key":"atm","type":"check","label":"ATM"},"backrest":{"key":"backrest","type":"check","label":"Backrest"},"barrier":{"key":"barrier","type":"typeCombo","label":"Type"},"bath/open_air":{"key":"bath:open_air","label":"Open Air","type":"check"},"bath/sand_bath":{"key":"bath:sand_bath","label":"Sand Bath","type":"check"},"bath/type":{"key":"bath:type","type":"combo","label":"Specialty","strings":{"options":{"onsen":"Japanese Onsen","foot_bath":"Foot Bath","hot_spring":"Hot Spring"}}},"beauty":{"key":"beauty","type":"combo","label":"Shop Type"},"bench":{"key":"bench","type":"check","label":"Bench"},"bicycle_parking":{"key":"bicycle_parking","type":"combo","label":"Type"},"bin":{"key":"bin","type":"check","label":"Waste Bin"},"blood_components":{"key":"blood:","type":"multiCombo","label":"Blood Components","strings":{"options":{"whole":"whole blood","plasma":"plasma","platelets":"platelets","stemcells":"stem cell samples"}}},"board_type":{"key":"board_type","type":"typeCombo","label":"Type"},"boundary":{"key":"boundary","type":"combo","label":"Type"},"brand":{"key":"brand","type":"text","label":"Brand"},"building_area":{"key":"building","type":"combo","default":"yes","geometry":"area","label":"Building"},"building":{"key":"building","type":"combo","label":"Building"},"bunker_type":{"key":"bunker_type","type":"combo","label":"Type"},"camera/direction":{"key":"camera:direction","type":"number","label":"Direction (Degrees Clockwise)","placeholder":"45, 90, 180, 270"},"camera/mount":{"key":"camera:mount","type":"combo","label":"Camera Mount"},"camera/type":{"key":"camera:type","type":"combo","label":"Camera Type","strings":{"options":{"fixed":"Fixed","panning":"Panning","dome":"Dome"}}},"capacity":{"key":"capacity","type":"number","label":"Capacity","placeholder":"50, 100, 200..."},"cardinal_direction":{"key":"direction","type":"combo","label":"Direction","strings":{"options":{"N":"North","E":"East","S":"South","W":"West","NE":"Northeast","SE":"Southeast","SW":"Southwest","NW":"Northwest","NNE":"North-northeast","ENE":"East-northeast","ESE":"East-southeast","SSE":"South-southeast","SSW":"South-southwest","WSW":"West-southwest","WNW":"West-northwest","NNW":"North-northwest"}}},"castle_type":{"key":"castle_type","type":"combo","label":"Type"},"clock_direction":{"key":"direction","type":"combo","label":"Direction","strings":{"options":{"clockwise":"Clockwise","anticlockwise":"Counterclockwise"}}},"club":{"key":"club","type":"typeCombo","label":"Type"},"collection_times":{"key":"collection_times","type":"text","label":"Collection Times"},"communication_multi":{"key":"communication:","type":"multiCombo","label":"Communication Types"},"construction":{"key":"construction","type":"combo","label":"Type"},"contact/webcam":{"key":"contact:webcam","type":"url","icon":"website","label":"Webcam URL","placeholder":"http://example.com/"},"content":{"key":"content","type":"combo","label":"Contents"},"country":{"key":"country","type":"combo","label":"Country"},"covered":{"key":"covered","type":"check","label":"Covered"},"craft":{"key":"craft","type":"typeCombo","label":"Type"},"crop":{"key":"crop","type":"semiCombo","label":"Crops"},"crossing":{"key":"crossing","type":"combo","label":"Type"},"cuisine":{"key":"cuisine","type":"semiCombo","label":"Cuisines"},"currency_multi":{"key":"currency:","type":"multiCombo","label":"Currency Types"},"cycle_network":{"key":"cycle_network","type":"networkCombo","label":"Network"},"cycleway":{"keys":["cycleway:left","cycleway:right"],"reference":{"key":"cycleway"},"type":"cycleway","label":"Bike Lanes","placeholder":"none","strings":{"types":{"cycleway:left":"Left side","cycleway:right":"Right side"},"options":{"none":{"title":"None","description":"No bike lane"},"lane":{"title":"Standard bike lane","description":"A bike lane separated from auto traffic by a painted line"},"shared_lane":{"title":"Shared bike lane","description":"A bike lane with no separation from auto traffic"},"track":{"title":"Bike track","description":"A bike lane separated from traffic by a physical barrier"},"share_busway":{"title":"Bike lane shared with bus","description":"A bike lane shared with a bus lane"},"opposite_lane":{"title":"Opposite bike lane","description":"A bike lane that travels in the opposite direction of traffic"},"opposite":{"title":"Contraflow bike lane","description":"A bike lane that travels in both directions on a one-way street"}}}},"date":{"key":"date","type":"check","label":"Date"},"delivery":{"key":"delivery","type":"check","label":"Delivery"},"denomination":{"key":"denomination","type":"combo","label":"Denomination"},"denotation":{"key":"denotation","type":"combo","label":"Denotation"},"description":{"key":"description","type":"textarea","label":"Description","universal":true},"diaper":{"key":"diaper","type":"combo","label":"Diaper Changing Available","options":["yes","no","room","1","2","3","4","5"]},"display":{"key":"display","type":"combo","label":"Display","options":["analog","digital","sundial","unorthodox"]},"dock":{"key":"dock","type":"combo","label":"Type"},"drive_through":{"key":"drive_through","type":"check","label":"Drive-Through"},"electrified":{"key":"electrified","type":"combo","label":"Electrification","placeholder":"Contact Line, Electrified Rail...","strings":{"options":{"contact_line":"Contact Line","rail":"Electrified Rail","yes":"Yes (unspecified)","no":"No"}}},"elevation":{"key":"ele","type":"number","icon":"elevation","universal":true,"label":"Elevation"},"email":{"key":"email","type":"email","placeholder":"example@example.com","universal":true,"label":"Email"},"emergency":{"key":"emergency","type":"check","label":"Emergency"},"entrance":{"key":"entrance","type":"typeCombo","label":"Type"},"except":{"key":"except","type":"combo","label":"Exceptions"},"fax":{"key":"fax","type":"tel","label":"Fax","universal":true,"placeholder":"+31 42 123 4567"},"fee":{"key":"fee","type":"check","label":"Fee"},"fence_type":{"key":"fence_type","type":"combo","label":"Type"},"fire_hydrant/position":{"key":"fire_hydrant:position","type":"combo","label":"Position","strings":{"options":{"lane":"Lane","parking_lot":"Parking Lot","sidewalk":"Sidewalk","green":"Green"}}},"fire_hydrant/type":{"key":"fire_hydrant:type","type":"combo","label":"Type","strings":{"options":{"pillar":"Pillar/Aboveground","underground":"Underground","wall":"Wall","pond":"Pond"}}},"fixme":{"key":"fixme","type":"textarea","label":"Fix Me","universal":true},"fuel_multi":{"key":"fuel:","type":"multiCombo","label":"Fuel Types"},"fuel":{"key":"fuel","type":"combo","label":"Fuel"},"gauge":{"key":"gauge","type":"combo","label":"Gauge"},"gender":{"type":"radio","keys":["male","female","unisex"],"label":"Gender","placeholder":"Unknown","strings":{"options":{"male":"Male","female":"Female","unisex":"Unisex"}}},"generator/method":{"key":"generator:method","type":"combo","label":"Method"},"generator/source":{"key":"generator:source","type":"combo","label":"Source"},"generator/type":{"key":"generator:type","type":"combo","label":"Type"},"golf_hole":{"key":"ref","type":"text","label":"Reference","placeholder":"Hole number (1-18)"},"grape_variety":{"key":"grape_variety","type":"semiCombo","label":"Grape Varieties"},"handicap":{"key":"handicap","type":"number","label":"Handicap","placeholder":"1-18"},"handrail":{"key":"handrail","type":"check","label":"Handrail"},"height":{"key":"height","type":"number","label":"Height (Meters)"},"highway":{"key":"highway","type":"typeCombo","label":"Type"},"historic":{"key":"historic","type":"typeCombo","label":"Type"},"historic/civilization":{"key":"historic:civilization","type":"combo","label":"Historic Civilization"},"hoops":{"key":"hoops","type":"number","label":"Hoops","placeholder":"1, 2, 4..."},"iata":{"key":"iata","type":"text","label":"IATA"},"icao":{"key":"icao","type":"text","label":"ICAO"},"incline_steps":{"key":"incline","type":"combo","label":"Incline","strings":{"options":{"up":"Up","down":"Down"}}},"incline":{"key":"incline","type":"combo","label":"Incline"},"indoor":{"key":"indoor","type":"check","label":"Indoor"},"information":{"key":"information","type":"typeCombo","label":"Type"},"inscription":{"key":"inscription","type":"textarea","label":"Inscription"},"internet_access":{"key":"internet_access","type":"combo","label":"Internet Access","strings":{"options":{"yes":"Yes","no":"No","wlan":"Wifi","wired":"Wired","terminal":"Terminal"}}},"internet_access/fee":{"key":"internet_access:fee","type":"check","label":"Internet Access Fee"},"internet_access/ssid":{"key":"internet_access:ssid","type":"text","label":"SSID (Network Name)"},"kerb":{"key":"kerb","type":"combo","label":"Curb Ramp"},"lamp_type":{"key":"lamp_type","type":"combo","label":"Type"},"landuse":{"key":"landuse","type":"typeCombo","label":"Type"},"lanes":{"key":"lanes","type":"number","label":"Lanes","placeholder":"1, 2, 3..."},"layer":{"key":"layer","type":"combo","label":"Layer"},"leaf_cycle_singular":{"key":"leaf_cycle","type":"combo","label":"Leaf Cycle","strings":{"options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous"}}},"leaf_cycle":{"key":"leaf_cycle","type":"combo","label":"Leaf Cycle","strings":{"options":{"evergreen":"Evergreen","deciduous":"Deciduous","semi_evergreen":"Semi-Evergreen","semi_deciduous":"Semi-Deciduous","mixed":"Mixed"}}},"leaf_type_singular":{"key":"leaf_type","type":"combo","label":"Leaf Type","strings":{"options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","leafless":"Leafless"}}},"leaf_type":{"key":"leaf_type","type":"combo","label":"Leaf Type","strings":{"options":{"broadleaved":"Broadleaved","needleleaved":"Needleleaved","mixed":"Mixed","leafless":"Leafless"}}},"leisure":{"key":"leisure","type":"typeCombo","label":"Type"},"length":{"key":"length","type":"number","label":"Length (Meters)"},"level":{"key":"level","type":"combo","label":"Level","universal":true},"levels":{"key":"building:levels","type":"number","label":"Levels","placeholder":"2, 4, 6..."},"lit":{"key":"lit","type":"check","label":"Lit"},"location":{"key":"location","type":"combo","label":"Location"},"man_made":{"key":"man_made","type":"typeCombo","label":"Type"},"map_size":{"key":"map_size","type":"typeCombo","label":"Coverage"},"map_type":{"key":"map_type","type":"typeCombo","label":"Type"},"maxheight":{"key":"maxheight","type":"combo","label":"Max Height","placeholder":"4, 4.5, 5, 14'0\", 14'6\", 15'0\"","snake_case":false},"maxspeed":{"key":"maxspeed","type":"maxspeed","label":"Speed Limit","placeholder":"40, 50, 60..."},"maxstay":{"key":"maxstay","type":"combo","label":"Max Stay","options":["15 min","30 min","45 min","1 hr","1.5 hr","2 hr","2.5 hr","3 hr","4 hr","1 day","2 day"],"snake_case":false},"mtb/scale":{"key":"mtb:scale","type":"combo","label":"Mountain Biking Difficulty","placeholder":"0, 1, 2, 3...","strings":{"options":{"0":"0: Solid gravel/packed earth, no obstacles, wide curves","1":"1: Some loose surface, small obstacles, wide curves","2":"2: Much loose surface, large obstacles, easy hairpins","3":"3: Slippery surface, large obstacles, tight hairpins","4":"4: Loose surface or boulders, dangerous hairpins","5":"5: Maximum difficulty, boulder fields, landslides","6":"6: Not rideable except by the very best mountain bikers"}}},"mtb/scale/imba":{"key":"mtb:scale:imba","type":"combo","label":"IMBA Trail Difficulty","placeholder":"Easy, Medium, Difficult...","strings":{"options":{"0":"Easiest (white circle)","1":"Easy (green circle)","2":"Medium (blue square)","3":"Difficult (black diamond)","4":"Extremely Difficult (double black diamond)"}}},"mtb/scale/uphill":{"key":"mtb:scale:uphill","type":"combo","label":"Mountain Biking Uphill Difficulty","placeholder":"0, 1, 2, 3...","strings":{"options":{"0":"0: Avg. incline <10%, gravel/packed earth, no obstacles","1":"1: Avg. incline <15%, gravel/packed earth, few small objects","2":"2: Avg. incline <20%, stable surface, fistsize rocks/roots","3":"3: Avg. incline <25%, variable surface, fistsize rocks/branches","4":"4: Avg. incline <30%, poor condition, big rocks/branches","5":"5: Very steep, bike generally needs to be pushed or carried"}}},"name":{"key":"name","type":"localized","label":"Name","placeholder":"Common name (if any)"},"natural":{"key":"natural","type":"typeCombo","label":"Natural"},"network_bicycle":{"key":"network","type":"combo","label":"Network Type","placeholder":"Local, Regional, National, International","strings":{"options":{"lcn":"Local","rcn":"Regional","ncn":"National","icn":"International"}}},"network_foot":{"key":"network","type":"combo","label":"Network Type","placeholder":"Local, Regional, National, International","strings":{"options":{"lwn":"Local","rwn":"Regional","nwn":"National","iwn":"International"}}},"network_horse":{"key":"network","type":"combo","label":"Network Type","placeholder":"Local, Regional, National, International","strings":{"options":{"lhn":"Local","rhn":"Regional","nhn":"National","ihn":"International"}}},"network_road":{"key":"network","type":"networkCombo","label":"Network"},"network":{"key":"network","type":"text","label":"Network"},"note":{"key":"note","type":"textarea","universal":true,"icon":"note","label":"Note"},"office":{"key":"office","type":"typeCombo","label":"Type"},"oneway_yes":{"key":"oneway","type":"onewayCheck","label":"One Way","strings":{"options":{"undefined":"Assumed to be Yes","yes":"Yes","no":"No"}}},"oneway":{"key":"oneway","type":"onewayCheck","label":"One Way","strings":{"options":{"undefined":"Assumed to be No","yes":"Yes","no":"No"}}},"opening_hours":{"key":"opening_hours","type":"combo","label":"Hours","snake_case":false},"operator":{"key":"operator","type":"text","label":"Operator"},"outdoor_seating":{"key":"outdoor_seating","type":"check","label":"Outdoor Seating"},"par":{"key":"par","type":"number","label":"Par","placeholder":"3, 4, 5..."},"parallel_direction":{"key":"direction","type":"combo","label":"Direction","strings":{"options":{"forward":"Forward","backward":"Backward"}}},"park_ride":{"key":"park_ride","type":"check","label":"Park and Ride"},"parking":{"key":"parking","type":"combo","label":"Type","strings":{"options":{"surface":"Surface","multi-storey":"Multilevel","underground":"Underground","sheds":"Sheds","carports":"Carports","garage_boxes":"Garage Boxes","lane":"Roadside Lane"}}},"payment_multi":{"key":"payment:","type":"multiCombo","label":"Payment Types"},"phone":{"key":"phone","type":"tel","icon":"telephone","universal":true,"label":"Phone","placeholder":"+31 42 123 4567"},"piste/difficulty":{"key":"piste:difficulty","type":"combo","label":"Difficulty","placeholder":"Easy, Intermediate, Advanced...","strings":{"options":{"novice":"Novice (instructional)","easy":"Easy (green circle)","intermediate":"Intermediate (blue square)","advanced":"Advanced (black diamond)","expert":"Expert (double black diamond)","freeride":"Freeride (off-piste)","extreme":"Extreme (climbing equipment required)"}}},"piste/grooming":{"key":"piste:grooming","type":"combo","label":"Grooming","strings":{"options":{"classic":"Classic","mogul":"Mogul","backcountry":"Backcountry","classic+skating":"Classic and Skating","scooter":"Scooter/Snowmobile","skating":"Skating"}}},"piste/type":{"key":"piste:type","type":"typeCombo","label":"Type","strings":{"options":{"downhill":"Downhill","nordic":"Nordic","skitour":"Skitour","sled":"Sled","hike":"Hike","sleigh":"Sleigh","ice_skate":"Ice Skate","snow_park":"Snow Park","playground":"Playground"}}},"place":{"key":"place","type":"typeCombo","label":"Type"},"plant":{"key":"plant","type":"combo","label":"Plant"},"population":{"key":"population","type":"text","label":"Population"},"power_supply":{"key":"power_supply","type":"check","label":"Power Supply"},"power":{"key":"power","type":"typeCombo","label":"Type"},"produce":{"key":"produce","type":"semiCombo","label":"Produce"},"product":{"key":"product","type":"semiCombo","label":"Products"},"railway":{"key":"railway","type":"typeCombo","label":"Type"},"recycling_accepts":{"key":"recycling:","type":"multiCombo","label":"Accepts"},"recycling_type":{"key":"recycling_type","default":"container","type":"combo","label":"Recycling Type","strings":{"options":{"container":"Container","centre":"Recycling Center"}}},"ref":{"key":"ref","type":"text","label":"Reference"},"relation":{"key":"type","type":"combo","label":"Type"},"religion":{"key":"religion","type":"combo","label":"Religion"},"restriction":{"key":"restriction","type":"combo","label":"Type"},"restrictions":{"type":"restrictions","geometry":"vertex","icon":"restrictions","reference":{"rtype":"restriction"},"label":"Turn Restrictions"},"rooms":{"key":"rooms","type":"number","label":"Rooms"},"route_master":{"key":"route_master","type":"combo","label":"Type"},"route":{"key":"route","type":"combo","label":"Type"},"sac_scale":{"key":"sac_scale","type":"combo","label":"Hiking Difficulty","placeholder":"Mountain Hiking, Alpine Hiking...","strings":{"options":{"hiking":"T1: Hiking","mountain_hiking":"T2: Mountain Hiking","demanding_mountain_hiking":"T3: Demanding Mountain Hiking","alpine_hiking":"T4: Alpine Hiking","demanding_alpine_hiking":"T5: Demanding Alpine Hiking","difficult_alpine_hiking":"T6: Difficult Alpine Hiking"}}},"sanitary_dump_station":{"key":"sanitary_dump_station","type":"check","label":"Toilet Disposal"},"seasonal":{"key":"seasonal","type":"check","label":"Seasonal"},"second_hand":{"key":"second_hand","type":"combo","label":"Sells Used","placeholder":"Yes, No, Only","strings":{"options":{"yes":"Yes","no":"No","only":"Only"}}},"service_rail":{"key":"service","type":"combo","label":"Service Type","strings":{"options":{"spur":"Spur","yard":"Yard","siding":"Siding","crossover":"Crossover"}}},"service_times":{"key":"service_times","type":"text","label":"Service Times"},"service":{"key":"service","type":"combo","label":"Type","options":["parking_aisle","driveway","alley","emergency_access","drive-through"]},"service/bicycle":{"key":"service:bicycle:","type":"multiCombo","label":"Services"},"service/vehicle":{"key":"service:vehicle:","type":"multiCombo","label":"Services"},"shelter_type":{"key":"shelter_type","type":"combo","label":"Type"},"shelter":{"key":"shelter","type":"check","label":"Shelter"},"shop":{"key":"shop","type":"typeCombo","label":"Type"},"site":{"key":"site","type":"combo","label":"Type"},"smoking":{"key":"smoking","type":"combo","label":"Smoking","placeholder":"No, Separated, Yes...","strings":{"options":{"no":"No smoking anywhere","separated":"In smoking areas, not physically isolated","isolated":"In smoking areas, physically isolated","outside":"Allowed outside","yes":"Allowed everywhere","dedicated":"Dedicated to smokers (e.g. smokers' club)"}}},"smoothness":{"key":"smoothness","type":"combo","label":"Smoothness","placeholder":"Thin Rollers, Wheels, Off-Road...","strings":{"options":{"excellent":"Thin Rollers: rollerblade, skateboard","good":"Thin Wheels: racing bike","intermediate":"Wheels: city bike, wheelchair, scooter","bad":"Robust Wheels: trekking bike, car, rickshaw","very_bad":"High Clearance: light duty off-road vehicle","horrible":"Off-Road: heavy duty off-road vehicle","very_horrible":"Specialized off-road: tractor, ATV","impassable":"Impassable / No wheeled vehicle"}}},"social_facility_for":{"key":"social_facility:for","type":"combo","label":"People Served"},"social_facility":{"key":"social_facility","type":"combo","label":"Type"},"source":{"key":"source","type":"text","icon":"source","universal":true,"label":"Source"},"sport_ice":{"key":"sport","type":"semiCombo","label":"Sports","options":["skating","hockey","multi","curling","ice_stock"]},"sport_racing_motor":{"key":"sport","type":"semiCombo","label":"Sports","options":["motor","karting","motocross"]},"sport_racing_nonmotor":{"key":"sport","type":"semiCombo","label":"Sports","options":["bmx","cycling","dog_racing","horse_racing","running"]},"sport":{"key":"sport","type":"semiCombo","label":"Sports"},"stars":{"key":"stars","type":"number","label":"Stars"},"start_date":{"key":"start_date","type":"text","universal":true,"label":"Start Date"},"step_count":{"key":"step_count","type":"number","label":"Number of Steps"},"stop":{"key":"stop","type":"combo","label":"Stop Type","strings":{"options":{"all":"All Ways","minor":"Minor Road"}}},"structure":{"type":"structureRadio","keys":["bridge","tunnel","embankment","cutting","ford"],"label":"Structure","placeholder":"Unknown","strings":{"options":{"bridge":"Bridge","tunnel":"Tunnel","embankment":"Embankment","cutting":"Cutting","ford":"Ford"}}},"studio":{"key":"studio","type":"combo","label":"Type"},"substation":{"key":"substation","type":"typeCombo","label":"Type"},"supervised":{"key":"supervised","type":"check","label":"Supervised"},"support":{"key":"support","type":"combo","label":"Support"},"surface":{"key":"surface","type":"combo","label":"Surface"},"surveillance":{"key":"surveillance","type":"combo","label":"Surveillance Kind"},"surveillance/type":{"key":"surveillance:type","type":"combo","label":"Surveillance Type","strings":{"options":{"camera":"Camera","guard":"Guard","ALPR":"Automatic License Plate Reader"}}},"surveillance/zone":{"key":"surveillance:zone","type":"combo","label":"Surveillance Zone"},"tactile_paving":{"key":"tactile_paving","type":"check","label":"Tactile Paving"},"takeaway":{"key":"takeaway","type":"combo","label":"Takeaway","placeholder":"Yes, No, Takeaway Only...","strings":{"options":{"yes":"Yes","no":"No","only":"Takeaway Only"}}},"toilets/disposal":{"key":"toilets:disposal","type":"combo","label":"Disposal","strings":{"options":{"flush":"Flush","pitlatrine":"Pit/Latrine","chemical":"Chemical","bucket":"Bucket"}}},"toll":{"key":"toll","type":"check","label":"Toll"},"tomb":{"key":"tomb","type":"typeCombo","label":"Type"},"tourism":{"key":"tourism","type":"typeCombo","label":"Type"},"tower/construction":{"key":"tower:construction","type":"combo","label":"Construction","placeholder":"Guyed, Lattice, Concealed, ..."},"tower/type":{"key":"tower:type","type":"combo","label":"Type"},"tracktype":{"key":"tracktype","type":"combo","label":"Track Type","placeholder":"Solid, Mostly Solid, Soft...","strings":{"options":{"grade1":"Solid: paved or heavily compacted hardcore surface","grade2":"Mostly Solid: gravel/rock with some soft material mixed in","grade3":"Even mixture of hard and soft materials","grade4":"Mostly Soft: soil/sand/grass with some hard material mixed in","grade5":"Soft: soil/sand/grass"}}},"traffic_calming":{"key":"traffic_calming","type":"typeCombo","label":"Type"},"traffic_signals":{"key":"traffic_signals","type":"combo","label":"Type","default":"signal"},"trail_visibility":{"key":"trail_visibility","type":"combo","label":"Trail Visibility","placeholder":"Excellent, Good, Bad...","strings":{"options":{"excellent":"Excellent: unambiguous path or markers everywhere","good":"Good: markers visible, sometimes require searching","intermediate":"Intermediate: few markers, path mostly visible","bad":"Bad: no markers, path sometimes invisible/pathless","horrible":"Horrible: often pathless, some orientation skills required","no":"No: pathless, excellent orientation skills required"}}},"trees":{"key":"trees","type":"semiCombo","label":"Trees"},"tunnel":{"key":"tunnel","type":"combo","label":"Tunnel"},"vending":{"key":"vending","type":"combo","label":"Type of Goods"},"visibility":{"key":"visibility","type":"combo","label":"Visibility","strings":{"options":{"house":"Up to 5m (16ft)","street":"5 to 20m (16 to 65ft)","area":"Over 20m (65ft)"}}},"wall":{"key":"wall","type":"combo","label":"Type"},"water_point":{"key":"water_point","type":"check","label":"Water Point"},"water":{"key":"water","type":"combo","label":"Type"},"waterway":{"key":"waterway","type":"typeCombo","label":"Type"},"website":{"key":"website","type":"url","icon":"website","placeholder":"http://example.com/","universal":true,"label":"Website"},"wetland":{"key":"wetland","type":"combo","label":"Type"},"wheelchair":{"key":"wheelchair","type":"radio","options":["yes","limited","no"],"icon":"wheelchair","universal":true,"label":"Wheelchair Access"},"width":{"key":"width","type":"number","label":"Width (Meters)"},"wikipedia":{"key":"wikipedia","keys":["wikipedia","wikidata"],"type":"wikipedia","icon":"wikipedia","universal":true,"label":"Wikipedia"}};
18634
18635 var all = ["aerialway","airfield","airport","alcohol-shop","america-football","amusement-park","aquarium","art-gallery","attraction","bakery","bank","bar","barrier","baseball","basketball","bbq","beer","bicycle","bicycle-share","blood-bank","buddhism","building","building-alt1","bus","cafe","campsite","car","castle","cemetery","cinema","circle","circle-stroked","city","clothing-store","college","commercial","cricket","cross","dam","danger","defibrillator","dentist","doctor","dog-park","drinking-water","embassy","emergency-phone","entrance","entrance-alt1","farm","fast-food","fence","ferry","fire-station","florist","fuel","gaming","garden","garden-center","gift","golf","grocery","hairdresser","harbor","heart","heliport","home","horse-riding","hospital","ice-cream","industry","information","karaoke","landmark","landuse","laundry","library","lighthouse","lodging","logging","marker","marker-stroked","mobile-phone","monument","mountain","museum","music","natural","park","park-alt1","parking","parking-garage","pharmacy","picnic-site","pitch","place-of-worship","playground","police","post","prison","rail","rail-light","rail-metro","ranger-station","recycling","religious-christian","religious-jewish","religious-muslim","residential-community","restaurant","roadblock","rocket","school","scooter","shelter","shop","skiing","slaughterhouse","snowmobile","soccer","square","square-stroked","stadium","star","star-stroked","suitcase","sushi","swimming","teahouse","telephone","tennis","theatre","toilet","town","town-hall","triangle","triangle-stroked","veterinary","village","volcano","warehouse","waste-basket","water","wetland","wheelchair","zoo"];
18636 var all$1 = {
18637         all: all
18638 };
18639
18640 var all$2 = Object.freeze({
18641         all: all,
18642         default: all$1
18643 });
18644
18645 var Airport = ["airfield","airport","heliport","rocket"];
18646 var Dining = ["bakery","bar","beer","cafe","fast-food","ice-cream","restaurant"];
18647 var Education = ["college","school"];
18648 var General = ["alcohol-shop","amusement-park","aquarium","art-gallery","attraction","bank","bicycle","bicycle-share","car","castle","cinema","circle","circle-stroked","clothing-store","drinking-water","embassy","fire-station","fuel","grocery","harbor","information","laundry","library","lodging","marker","monument","museum","music","place-of-worship","police","post","prison","religious-christian","religious-jewish","religious-muslim","shop","stadium","star","suitcase","swimming","theatre","toilet","town-hall","triangle","triangle-stroked","veterinary"];
18649 var Health = ["dentist","doctor","hospital","pharmacy"];
18650 var Outdoors = ["campsite","cemetery","dog-park","garden","golf","park","picnic-site","playground","zoo"];
18651 var Transit = ["bus","ferry"];
18652 var streets = {
18653         Airport: Airport,
18654         Dining: Dining,
18655         Education: Education,
18656         General: General,
18657         Health: Health,
18658         Outdoors: Outdoors,
18659         Transit: Transit,
18660         "Mountain peak": ["mountain","volcano"],
18661         "Rail station": ["entrance","rail","rail-light","rail-metro"]
18662 };
18663
18664 var streets$1 = Object.freeze({
18665         Airport: Airport,
18666         Dining: Dining,
18667         Education: Education,
18668         General: General,
18669         Health: Health,
18670         Outdoors: Outdoors,
18671         Transit: Transit,
18672         default: streets
18673 });
18674
18675 var require$$0 = ( all$2 && all$1 ) || all$2;
18676
18677 var require$$1 = ( streets$1 && streets ) || streets$1;
18678
18679 var index$1 = {
18680   layouts: {
18681     all: require$$0,
18682     streets: require$$1
18683   }
18684 };
18685
18686 var dataFeatureIcons = index$1.layouts.all.all;
18687
18688 var data = {
18689     imagery: dataImagery,
18690     presets: {
18691         presets: presets,
18692         defaults: defaults,
18693         categories: categories,
18694         fields: fields
18695     }
18696 };
18697
18698 function osmEntity$$1(attrs) {
18699     // For prototypal inheritance.
18700     if (this instanceof osmEntity$$1) return;
18701
18702     // Create the appropriate subtype.
18703     if (attrs && attrs.type) {
18704         return osmEntity$$1[attrs.type].apply(this, arguments);
18705     } else if (attrs && attrs.id) {
18706         return osmEntity$$1[osmEntity$$1.id.type(attrs.id)].apply(this, arguments);
18707     }
18708
18709     // Initialize a generic Entity (used only in tests).
18710     return (new osmEntity$$1()).initialize(arguments);
18711 }
18712
18713
18714 osmEntity$$1.id = function(type) {
18715     return osmEntity$$1.id.fromOSM(type, osmEntity$$1.id.next[type]--);
18716 };
18717
18718
18719 osmEntity$$1.id.next = {
18720     changeset: -1, node: -1, way: -1, relation: -1
18721 };
18722
18723
18724 osmEntity$$1.id.fromOSM = function(type, id) {
18725     return type[0] + id;
18726 };
18727
18728
18729 osmEntity$$1.id.toOSM = function(id) {
18730     return id.slice(1);
18731 };
18732
18733
18734 osmEntity$$1.id.type = function(id) {
18735     return { 'c': 'changeset', 'n': 'node', 'w': 'way', 'r': 'relation' }[id[0]];
18736 };
18737
18738
18739 // A function suitable for use as the second argument to d3.selection#data().
18740 osmEntity$$1.key = function(entity) {
18741     return entity.id + 'v' + (entity.v || 0);
18742 };
18743
18744
18745 osmEntity$$1.prototype = {
18746
18747     tags: {},
18748
18749
18750     initialize: function(sources) {
18751         for (var i = 0; i < sources.length; ++i) {
18752             var source = sources[i];
18753             for (var prop in source) {
18754                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
18755                     if (source[prop] === undefined) {
18756                         delete this[prop];
18757                     } else {
18758                         this[prop] = source[prop];
18759                     }
18760                 }
18761             }
18762         }
18763
18764         if (!this.id && this.type) {
18765             this.id = osmEntity$$1.id(this.type);
18766         }
18767         if (!this.hasOwnProperty('visible')) {
18768             this.visible = true;
18769         }
18770
18771         if (debug) {
18772             Object.freeze(this);
18773             Object.freeze(this.tags);
18774
18775             if (this.loc) Object.freeze(this.loc);
18776             if (this.nodes) Object.freeze(this.nodes);
18777             if (this.members) Object.freeze(this.members);
18778         }
18779
18780         return this;
18781     },
18782
18783
18784     copy: function(resolver, copies) {
18785         if (copies[this.id])
18786             return copies[this.id];
18787
18788         var copy = osmEntity$$1(this, {id: undefined, user: undefined, version: undefined});
18789         copies[this.id] = copy;
18790
18791         return copy;
18792     },
18793
18794
18795     osmId: function() {
18796         return osmEntity$$1.id.toOSM(this.id);
18797     },
18798
18799
18800     isNew: function() {
18801         return this.osmId() < 0;
18802     },
18803
18804
18805     update: function(attrs) {
18806         return osmEntity$$1(this, attrs, {v: 1 + (this.v || 0)});
18807     },
18808
18809
18810     mergeTags: function(tags) {
18811         var merged = lodash.clone(this.tags), changed = false;
18812         for (var k in tags) {
18813             var t1 = merged[k],
18814                 t2 = tags[k];
18815             if (!t1) {
18816                 changed = true;
18817                 merged[k] = t2;
18818             } else if (t1 !== t2) {
18819                 changed = true;
18820                 merged[k] = lodash.union(t1.split(/;\s*/), t2.split(/;\s*/)).join(';');
18821             }
18822         }
18823         return changed ? this.update({tags: merged}) : this;
18824     },
18825
18826
18827     intersects: function(extent, resolver) {
18828         return this.extent(resolver).intersects(extent);
18829     },
18830
18831
18832     isUsed: function(resolver) {
18833         return lodash.without(Object.keys(this.tags), 'area').length > 0 ||
18834             resolver.parentRelations(this).length > 0;
18835     },
18836
18837
18838     hasInterestingTags: function() {
18839         return lodash.keys(this.tags).some(osmIsInterestingTag);
18840     },
18841
18842
18843     isHighwayIntersection: function() {
18844         return false;
18845     },
18846
18847     isDegenerate: function() {
18848         return true;
18849     },
18850
18851     deprecatedTags: function() {
18852         var tags = lodash.toPairs(this.tags);
18853         var deprecated = {};
18854
18855         dataDeprecated.forEach(function(d) {
18856             var match = lodash.toPairs(d.old)[0];
18857             tags.forEach(function(t) {
18858                 if (t[0] === match[0] &&
18859                     (t[1] === match[1] || match[1] === '*')) {
18860                     deprecated[t[0]] = t[1];
18861                 }
18862             });
18863         });
18864
18865         return deprecated;
18866     }
18867 };
18868
18869 function geoRoundCoords(c) {
18870     return [Math.floor(c[0]), Math.floor(c[1])];
18871 }
18872
18873
18874 function geoInterp(p1, p2, t) {
18875     return [p1[0] + (p2[0] - p1[0]) * t,
18876             p1[1] + (p2[1] - p1[1]) * t];
18877 }
18878
18879
18880 // 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
18881 // Returns a positive value, if OAB makes a counter-clockwise turn,
18882 // negative for clockwise turn, and zero if the points are collinear.
18883 function geoCross(o, a, b) {
18884     return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
18885 }
18886
18887
18888 // http://jsperf.com/id-dist-optimization
18889 function geoEuclideanDistance(a, b) {
18890     var x = a[0] - b[0], y = a[1] - b[1];
18891     return Math.sqrt((x * x) + (y * y));
18892 }
18893
18894
18895 // using WGS84 polar radius (6356752.314245179 m)
18896 // const = 2 * PI * r / 360
18897 function geoLatToMeters(dLat) {
18898     return dLat * 110946.257617;
18899 }
18900
18901
18902 // using WGS84 equatorial radius (6378137.0 m)
18903 // const = 2 * PI * r / 360
18904 function geoLonToMeters(dLon, atLat) {
18905     return Math.abs(atLat) >= 90 ? 0 :
18906         dLon * 111319.490793 * Math.abs(Math.cos(atLat * (Math.PI/180)));
18907 }
18908
18909
18910 // using WGS84 polar radius (6356752.314245179 m)
18911 // const = 2 * PI * r / 360
18912 function geoMetersToLat(m) {
18913     return m / 110946.257617;
18914 }
18915
18916
18917 // using WGS84 equatorial radius (6378137.0 m)
18918 // const = 2 * PI * r / 360
18919 function geoMetersToLon(m, atLat) {
18920     return Math.abs(atLat) >= 90 ? 0 :
18921         m / 111319.490793 / Math.abs(Math.cos(atLat * (Math.PI/180)));
18922 }
18923
18924
18925 function geoOffsetToMeters(offset) {
18926     var equatRadius = 6356752.314245179,
18927         polarRadius = 6378137.0,
18928         tileSize = 256;
18929
18930     return [
18931         offset[0] * 2 * Math.PI * equatRadius / tileSize,
18932         -offset[1] * 2 * Math.PI * polarRadius / tileSize
18933     ];
18934 }
18935
18936
18937 function geoMetersToOffset(meters) {
18938     var equatRadius = 6356752.314245179,
18939         polarRadius = 6378137.0,
18940         tileSize = 256;
18941
18942     return [
18943         meters[0] * tileSize / (2 * Math.PI * equatRadius),
18944         -meters[1] * tileSize / (2 * Math.PI * polarRadius)
18945     ];
18946 }
18947
18948
18949 // Equirectangular approximation of spherical distances on Earth
18950 function geoSphericalDistance(a, b) {
18951     var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2),
18952         y = geoLatToMeters(a[1] - b[1]);
18953     return Math.sqrt((x * x) + (y * y));
18954 }
18955
18956
18957 function geoEdgeEqual(a, b) {
18958     return (a[0] === b[0] && a[1] === b[1]) ||
18959         (a[0] === b[1] && a[1] === b[0]);
18960 }
18961
18962
18963 // Return the counterclockwise angle in the range (-pi, pi)
18964 // between the positive X axis and the line intersecting a and b.
18965 function geoAngle(a, b, projection) {
18966     a = projection(a.loc);
18967     b = projection(b.loc);
18968     return Math.atan2(b[1] - a[1], b[0] - a[0]);
18969 }
18970
18971
18972 // Rotate all points counterclockwise around a pivot point by given angle
18973 function geoRotate(points, angle, around) {
18974     return points.map(function(point) {
18975         var radial = [point[0] - around[0], point[1] - around[1]];
18976         return [
18977             radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + around[0],
18978             radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + around[1]
18979         ];
18980     });
18981 }
18982
18983
18984 // Choose the edge with the minimal distance from `point` to its orthogonal
18985 // projection onto that edge, if such a projection exists, or the distance to
18986 // the closest vertex on that edge. Returns an object with the `index` of the
18987 // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
18988 function geoChooseEdge(nodes, point, projection) {
18989     var dist = geoEuclideanDistance,
18990         points = nodes.map(function(n) { return projection(n.loc); }),
18991         min = Infinity,
18992         idx, loc;
18993
18994     function dot(p, q) {
18995         return p[0] * q[0] + p[1] * q[1];
18996     }
18997
18998     for (var i = 0; i < points.length - 1; i++) {
18999         var o = points[i],
19000             s = [points[i + 1][0] - o[0],
19001                  points[i + 1][1] - o[1]],
19002             v = [point[0] - o[0],
19003                  point[1] - o[1]],
19004             proj = dot(v, s) / dot(s, s),
19005             p;
19006
19007         if (proj < 0) {
19008             p = o;
19009         } else if (proj > 1) {
19010             p = points[i + 1];
19011         } else {
19012             p = [o[0] + proj * s[0], o[1] + proj * s[1]];
19013         }
19014
19015         var d = dist(p, point);
19016         if (d < min) {
19017             min = d;
19018             idx = i + 1;
19019             loc = projection.invert(p);
19020         }
19021     }
19022
19023     return {
19024         index: idx,
19025         distance: min,
19026         loc: loc
19027     };
19028 }
19029
19030
19031 // Return the intersection point of 2 line segments.
19032 // From https://github.com/pgkelley4/line-segments-intersect
19033 // This uses the vector cross product approach described below:
19034 //  http://stackoverflow.com/a/565282/786339
19035 function geoLineIntersection(a, b) {
19036     function subtractPoints(point1, point2) {
19037         return [point1[0] - point2[0], point1[1] - point2[1]];
19038     }
19039     function crossProduct(point1, point2) {
19040         return point1[0] * point2[1] - point1[1] * point2[0];
19041     }
19042
19043     var p = [a[0][0], a[0][1]],
19044         p2 = [a[1][0], a[1][1]],
19045         q = [b[0][0], b[0][1]],
19046         q2 = [b[1][0], b[1][1]],
19047         r = subtractPoints(p2, p),
19048         s = subtractPoints(q2, q),
19049         uNumerator = crossProduct(subtractPoints(q, p), r),
19050         denominator = crossProduct(r, s);
19051
19052     if (uNumerator && denominator) {
19053         var u = uNumerator / denominator,
19054             t = crossProduct(subtractPoints(q, p), s) / denominator;
19055
19056         if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) {
19057             return geoInterp(p, p2, t);
19058         }
19059     }
19060
19061     return null;
19062 }
19063
19064
19065 function geoPathIntersections(path1, path2) {
19066     var intersections = [];
19067     for (var i = 0; i < path1.length - 1; i++) {
19068         for (var j = 0; j < path2.length - 1; j++) {
19069             var a = [ path1[i], path1[i+1] ],
19070                 b = [ path2[j], path2[j+1] ],
19071                 hit = geoLineIntersection(a, b);
19072             if (hit) intersections.push(hit);
19073         }
19074     }
19075     return intersections;
19076 }
19077
19078
19079 // Return whether point is contained in polygon.
19080 //
19081 // `point` should be a 2-item array of coordinates.
19082 // `polygon` should be an array of 2-item arrays of coordinates.
19083 //
19084 // From https://github.com/substack/point-in-polygon.
19085 // ray-casting algorithm based on
19086 // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
19087 //
19088 function geoPointInPolygon(point, polygon) {
19089     var x = point[0],
19090         y = point[1],
19091         inside = false;
19092
19093     for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
19094         var xi = polygon[i][0], yi = polygon[i][1];
19095         var xj = polygon[j][0], yj = polygon[j][1];
19096
19097         var intersect = ((yi > y) !== (yj > y)) &&
19098             (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
19099         if (intersect) inside = !inside;
19100     }
19101
19102     return inside;
19103 }
19104
19105
19106 function geoPolygonContainsPolygon(outer, inner) {
19107     return lodash.every(inner, function(point) {
19108         return geoPointInPolygon(point, outer);
19109     });
19110 }
19111
19112
19113 function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
19114     function testSegments(outer, inner) {
19115         for (var i = 0; i < outer.length - 1; i++) {
19116             for (var j = 0; j < inner.length - 1; j++) {
19117                 var a = [ outer[i], outer[i+1] ],
19118                     b = [ inner[j], inner[j+1] ];
19119                 if (geoLineIntersection(a, b)) return true;
19120             }
19121         }
19122         return false;
19123     }
19124
19125     function testPoints(outer, inner) {
19126         return lodash.some(inner, function(point) {
19127             return geoPointInPolygon(point, outer);
19128         });
19129     }
19130
19131    return testPoints(outer, inner) || (!!checkSegments && testSegments(outer, inner));
19132 }
19133
19134
19135 function geoPathLength(path) {
19136     var length = 0;
19137     for (var i = 0; i < path.length - 1; i++) {
19138         length += geoEuclideanDistance(path[i], path[i + 1]);
19139     }
19140     return length;
19141 }
19142
19143 function geoExtent$$1(min, max) {
19144     if (!(this instanceof geoExtent$$1)) return new geoExtent$$1(min, max);
19145     if (min instanceof geoExtent$$1) {
19146         return min;
19147     } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
19148         this[0] = min[0];
19149         this[1] = min[1];
19150     } else {
19151         this[0] = min        || [ Infinity,  Infinity];
19152         this[1] = max || min || [-Infinity, -Infinity];
19153     }
19154 }
19155
19156 geoExtent$$1.prototype = new Array(2);
19157
19158 lodash.extend(geoExtent$$1.prototype, {
19159
19160     equals: function (obj) {
19161         return this[0][0] === obj[0][0] &&
19162             this[0][1] === obj[0][1] &&
19163             this[1][0] === obj[1][0] &&
19164             this[1][1] === obj[1][1];
19165     },
19166
19167
19168     extend: function(obj) {
19169         if (!(obj instanceof geoExtent$$1)) obj = new geoExtent$$1(obj);
19170         return geoExtent$$1(
19171             [Math.min(obj[0][0], this[0][0]), Math.min(obj[0][1], this[0][1])],
19172             [Math.max(obj[1][0], this[1][0]), Math.max(obj[1][1], this[1][1])]
19173         );
19174     },
19175
19176
19177     _extend: function(extent) {
19178         this[0][0] = Math.min(extent[0][0], this[0][0]);
19179         this[0][1] = Math.min(extent[0][1], this[0][1]);
19180         this[1][0] = Math.max(extent[1][0], this[1][0]);
19181         this[1][1] = Math.max(extent[1][1], this[1][1]);
19182     },
19183
19184
19185     area: function() {
19186         return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
19187     },
19188
19189
19190     center: function() {
19191         return [(this[0][0] + this[1][0]) / 2,
19192                 (this[0][1] + this[1][1]) / 2];
19193     },
19194
19195
19196     rectangle: function() {
19197         return [this[0][0], this[0][1], this[1][0], this[1][1]];
19198     },
19199
19200
19201     bbox: function() {
19202         return { minX: this[0][0], minY: this[0][1], maxX: this[1][0], maxY: this[1][1] };
19203     },
19204
19205
19206     polygon: function() {
19207         return [
19208             [this[0][0], this[0][1]],
19209             [this[0][0], this[1][1]],
19210             [this[1][0], this[1][1]],
19211             [this[1][0], this[0][1]],
19212             [this[0][0], this[0][1]]
19213         ];
19214     },
19215
19216
19217     contains: function(obj) {
19218         if (!(obj instanceof geoExtent$$1)) obj = new geoExtent$$1(obj);
19219         return obj[0][0] >= this[0][0] &&
19220                obj[0][1] >= this[0][1] &&
19221                obj[1][0] <= this[1][0] &&
19222                obj[1][1] <= this[1][1];
19223     },
19224
19225
19226     intersects: function(obj) {
19227         if (!(obj instanceof geoExtent$$1)) obj = new geoExtent$$1(obj);
19228         return obj[0][0] <= this[1][0] &&
19229                obj[0][1] <= this[1][1] &&
19230                obj[1][0] >= this[0][0] &&
19231                obj[1][1] >= this[0][1];
19232     },
19233
19234
19235     intersection: function(obj) {
19236         if (!this.intersects(obj)) return new geoExtent$$1();
19237         return new geoExtent$$1(
19238             [Math.max(obj[0][0], this[0][0]), Math.max(obj[0][1], this[0][1])],
19239             [Math.min(obj[1][0], this[1][0]), Math.min(obj[1][1], this[1][1])]
19240         );
19241     },
19242
19243
19244     percentContainedIn: function(obj) {
19245         if (!(obj instanceof geoExtent$$1)) obj = new geoExtent$$1(obj);
19246         var a1 = this.intersection(obj).area(),
19247             a2 = this.area();
19248
19249         if (a1 === Infinity || a2 === Infinity || a1 === 0 || a2 === 0) {
19250             return 0;
19251         } else {
19252             return a1 / a2;
19253         }
19254     },
19255
19256
19257     padByMeters: function(meters) {
19258         var dLat = geoMetersToLat(meters),
19259             dLon = geoMetersToLon(meters, this.center()[1]);
19260         return geoExtent$$1(
19261             [this[0][0] - dLon, this[0][1] - dLat],
19262             [this[1][0] + dLon, this[1][1] + dLat]
19263         );
19264     },
19265
19266
19267     toParam: function() {
19268         return this.rectangle().join(',');
19269     }
19270
19271 });
19272
19273 var version = "4.8.0";
19274
19275 var ascending = function(a, b) {
19276   return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
19277 };
19278
19279 var bisector = function(compare) {
19280   if (compare.length === 1) compare = ascendingComparator(compare);
19281   return {
19282     left: function(a, x, lo, hi) {
19283       if (lo == null) lo = 0;
19284       if (hi == null) hi = a.length;
19285       while (lo < hi) {
19286         var mid = lo + hi >>> 1;
19287         if (compare(a[mid], x) < 0) lo = mid + 1;
19288         else hi = mid;
19289       }
19290       return lo;
19291     },
19292     right: function(a, x, lo, hi) {
19293       if (lo == null) lo = 0;
19294       if (hi == null) hi = a.length;
19295       while (lo < hi) {
19296         var mid = lo + hi >>> 1;
19297         if (compare(a[mid], x) > 0) hi = mid;
19298         else lo = mid + 1;
19299       }
19300       return lo;
19301     }
19302   };
19303 };
19304
19305 function ascendingComparator(f) {
19306   return function(d, x) {
19307     return ascending(f(d), x);
19308   };
19309 }
19310
19311 var ascendingBisect = bisector(ascending);
19312 var bisectRight = ascendingBisect.right;
19313 var bisectLeft = ascendingBisect.left;
19314
19315 var pairs = function(array, f) {
19316   if (f == null) f = pair;
19317   var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n);
19318   while (i < n) pairs[i] = f(p, p = array[++i]);
19319   return pairs;
19320 };
19321
19322 function pair(a, b) {
19323   return [a, b];
19324 }
19325
19326 var cross = function(values0, values1, reduce) {
19327   var n0 = values0.length,
19328       n1 = values1.length,
19329       values = new Array(n0 * n1),
19330       i0,
19331       i1,
19332       i,
19333       value0;
19334
19335   if (reduce == null) reduce = pair;
19336
19337   for (i0 = i = 0; i0 < n0; ++i0) {
19338     for (value0 = values0[i0], i1 = 0; i1 < n1; ++i1, ++i) {
19339       values[i] = reduce(value0, values1[i1]);
19340     }
19341   }
19342
19343   return values;
19344 };
19345
19346 var descending = function(a, b) {
19347   return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
19348 };
19349
19350 var number = function(x) {
19351   return x === null ? NaN : +x;
19352 };
19353
19354 var variance = function(values, valueof) {
19355   var n = values.length,
19356       m = 0,
19357       i = -1,
19358       mean = 0,
19359       value,
19360       delta,
19361       sum = 0;
19362
19363   if (valueof == null) {
19364     while (++i < n) {
19365       if (!isNaN(value = number(values[i]))) {
19366         delta = value - mean;
19367         mean += delta / ++m;
19368         sum += delta * (value - mean);
19369       }
19370     }
19371   }
19372
19373   else {
19374     while (++i < n) {
19375       if (!isNaN(value = number(valueof(values[i], i, values)))) {
19376         delta = value - mean;
19377         mean += delta / ++m;
19378         sum += delta * (value - mean);
19379       }
19380     }
19381   }
19382
19383   if (m > 1) return sum / (m - 1);
19384 };
19385
19386 var deviation = function(array, f) {
19387   var v = variance(array, f);
19388   return v ? Math.sqrt(v) : v;
19389 };
19390
19391 var extent = function(values, valueof) {
19392   var n = values.length,
19393       i = -1,
19394       value,
19395       min,
19396       max;
19397
19398   if (valueof == null) {
19399     while (++i < n) { // Find the first comparable value.
19400       if ((value = values[i]) != null && value >= value) {
19401         min = max = value;
19402         while (++i < n) { // Compare the remaining values.
19403           if ((value = values[i]) != null) {
19404             if (min > value) min = value;
19405             if (max < value) max = value;
19406           }
19407         }
19408       }
19409     }
19410   }
19411
19412   else {
19413     while (++i < n) { // Find the first comparable value.
19414       if ((value = valueof(values[i], i, values)) != null && value >= value) {
19415         min = max = value;
19416         while (++i < n) { // Compare the remaining values.
19417           if ((value = valueof(values[i], i, values)) != null) {
19418             if (min > value) min = value;
19419             if (max < value) max = value;
19420           }
19421         }
19422       }
19423     }
19424   }
19425
19426   return [min, max];
19427 };
19428
19429 var array = Array.prototype;
19430
19431 var slice = array.slice;
19432 var map = array.map;
19433
19434 var constant = function(x) {
19435   return function() {
19436     return x;
19437   };
19438 };
19439
19440 var identity = function(x) {
19441   return x;
19442 };
19443
19444 var sequence = function(start, stop, step) {
19445   start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
19446
19447   var i = -1,
19448       n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
19449       range = new Array(n);
19450
19451   while (++i < n) {
19452     range[i] = start + i * step;
19453   }
19454
19455   return range;
19456 };
19457
19458 var e10 = Math.sqrt(50);
19459 var e5 = Math.sqrt(10);
19460 var e2 = Math.sqrt(2);
19461
19462 var ticks = function(start, stop, count) {
19463   var reverse = stop < start,
19464       i = -1,
19465       n,
19466       ticks,
19467       step;
19468
19469   if (reverse) n = start, start = stop, stop = n;
19470
19471   if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
19472
19473   if (step > 0) {
19474     start = Math.ceil(start / step);
19475     stop = Math.floor(stop / step);
19476     ticks = new Array(n = Math.ceil(stop - start + 1));
19477     while (++i < n) ticks[i] = (start + i) * step;
19478   } else {
19479     start = Math.floor(start * step);
19480     stop = Math.ceil(stop * step);
19481     ticks = new Array(n = Math.ceil(start - stop + 1));
19482     while (++i < n) ticks[i] = (start - i) / step;
19483   }
19484
19485   if (reverse) ticks.reverse();
19486
19487   return ticks;
19488 };
19489
19490 function tickIncrement(start, stop, count) {
19491   var step = (stop - start) / Math.max(0, count),
19492       power = Math.floor(Math.log(step) / Math.LN10),
19493       error = step / Math.pow(10, power);
19494   return power >= 0
19495       ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power)
19496       : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
19497 }
19498
19499 function tickStep(start, stop, count) {
19500   var step0 = Math.abs(stop - start) / Math.max(0, count),
19501       step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
19502       error = step0 / step1;
19503   if (error >= e10) step1 *= 10;
19504   else if (error >= e5) step1 *= 5;
19505   else if (error >= e2) step1 *= 2;
19506   return stop < start ? -step1 : step1;
19507 }
19508
19509 var sturges = function(values) {
19510   return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
19511 };
19512
19513 var histogram = function() {
19514   var value = identity,
19515       domain = extent,
19516       threshold = sturges;
19517
19518   function histogram(data) {
19519     var i,
19520         n = data.length,
19521         x,
19522         values = new Array(n);
19523
19524     for (i = 0; i < n; ++i) {
19525       values[i] = value(data[i], i, data);
19526     }
19527
19528     var xz = domain(values),
19529         x0 = xz[0],
19530         x1 = xz[1],
19531         tz = threshold(values, x0, x1);
19532
19533     // Convert number of thresholds into uniform thresholds.
19534     if (!Array.isArray(tz)) {
19535       tz = tickStep(x0, x1, tz);
19536       tz = sequence(Math.ceil(x0 / tz) * tz, Math.floor(x1 / tz) * tz, tz); // exclusive
19537     }
19538
19539     // Remove any thresholds outside the domain.
19540     var m = tz.length;
19541     while (tz[0] <= x0) tz.shift(), --m;
19542     while (tz[m - 1] > x1) tz.pop(), --m;
19543
19544     var bins = new Array(m + 1),
19545         bin;
19546
19547     // Initialize bins.
19548     for (i = 0; i <= m; ++i) {
19549       bin = bins[i] = [];
19550       bin.x0 = i > 0 ? tz[i - 1] : x0;
19551       bin.x1 = i < m ? tz[i] : x1;
19552     }
19553
19554     // Assign data to bins by value, ignoring any outside the domain.
19555     for (i = 0; i < n; ++i) {
19556       x = values[i];
19557       if (x0 <= x && x <= x1) {
19558         bins[bisectRight(tz, x, 0, m)].push(data[i]);
19559       }
19560     }
19561
19562     return bins;
19563   }
19564
19565   histogram.value = function(_) {
19566     return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value;
19567   };
19568
19569   histogram.domain = function(_) {
19570     return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain;
19571   };
19572
19573   histogram.thresholds = function(_) {
19574     return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), histogram) : threshold;
19575   };
19576
19577   return histogram;
19578 };
19579
19580 var threshold = function(values, p, valueof) {
19581   if (valueof == null) valueof = number;
19582   if (!(n = values.length)) return;
19583   if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);
19584   if (p >= 1) return +valueof(values[n - 1], n - 1, values);
19585   var n,
19586       i = (n - 1) * p,
19587       i0 = Math.floor(i),
19588       value0 = +valueof(values[i0], i0, values),
19589       value1 = +valueof(values[i0 + 1], i0 + 1, values);
19590   return value0 + (value1 - value0) * (i - i0);
19591 };
19592
19593 var freedmanDiaconis = function(values, min, max) {
19594   values = map.call(values, number).sort(ascending);
19595   return Math.ceil((max - min) / (2 * (threshold(values, 0.75) - threshold(values, 0.25)) * Math.pow(values.length, -1 / 3)));
19596 };
19597
19598 var scott = function(values, min, max) {
19599   return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3)));
19600 };
19601
19602 var max = function(values, valueof) {
19603   var n = values.length,
19604       i = -1,
19605       value,
19606       max;
19607
19608   if (valueof == null) {
19609     while (++i < n) { // Find the first comparable value.
19610       if ((value = values[i]) != null && value >= value) {
19611         max = value;
19612         while (++i < n) { // Compare the remaining values.
19613           if ((value = values[i]) != null && value > max) {
19614             max = value;
19615           }
19616         }
19617       }
19618     }
19619   }
19620
19621   else {
19622     while (++i < n) { // Find the first comparable value.
19623       if ((value = valueof(values[i], i, values)) != null && value >= value) {
19624         max = value;
19625         while (++i < n) { // Compare the remaining values.
19626           if ((value = valueof(values[i], i, values)) != null && value > max) {
19627             max = value;
19628           }
19629         }
19630       }
19631     }
19632   }
19633
19634   return max;
19635 };
19636
19637 var mean = function(values, valueof) {
19638   var n = values.length,
19639       m = n,
19640       i = -1,
19641       value,
19642       sum = 0;
19643
19644   if (valueof == null) {
19645     while (++i < n) {
19646       if (!isNaN(value = number(values[i]))) sum += value;
19647       else --m;
19648     }
19649   }
19650
19651   else {
19652     while (++i < n) {
19653       if (!isNaN(value = number(valueof(values[i], i, values)))) sum += value;
19654       else --m;
19655     }
19656   }
19657
19658   if (m) return sum / m;
19659 };
19660
19661 var median = function(values, valueof) {
19662   var n = values.length,
19663       i = -1,
19664       value,
19665       numbers = [];
19666
19667   if (valueof == null) {
19668     while (++i < n) {
19669       if (!isNaN(value = number(values[i]))) {
19670         numbers.push(value);
19671       }
19672     }
19673   }
19674
19675   else {
19676     while (++i < n) {
19677       if (!isNaN(value = number(valueof(values[i], i, values)))) {
19678         numbers.push(value);
19679       }
19680     }
19681   }
19682
19683   return threshold(numbers.sort(ascending), 0.5);
19684 };
19685
19686 var merge = function(arrays) {
19687   var n = arrays.length,
19688       m,
19689       i = -1,
19690       j = 0,
19691       merged,
19692       array;
19693
19694   while (++i < n) j += arrays[i].length;
19695   merged = new Array(j);
19696
19697   while (--n >= 0) {
19698     array = arrays[n];
19699     m = array.length;
19700     while (--m >= 0) {
19701       merged[--j] = array[m];
19702     }
19703   }
19704
19705   return merged;
19706 };
19707
19708 var min = function(values, valueof) {
19709   var n = values.length,
19710       i = -1,
19711       value,
19712       min;
19713
19714   if (valueof == null) {
19715     while (++i < n) { // Find the first comparable value.
19716       if ((value = values[i]) != null && value >= value) {
19717         min = value;
19718         while (++i < n) { // Compare the remaining values.
19719           if ((value = values[i]) != null && min > value) {
19720             min = value;
19721           }
19722         }
19723       }
19724     }
19725   }
19726
19727   else {
19728     while (++i < n) { // Find the first comparable value.
19729       if ((value = valueof(values[i], i, values)) != null && value >= value) {
19730         min = value;
19731         while (++i < n) { // Compare the remaining values.
19732           if ((value = valueof(values[i], i, values)) != null && min > value) {
19733             min = value;
19734           }
19735         }
19736       }
19737     }
19738   }
19739
19740   return min;
19741 };
19742
19743 var permute = function(array, indexes) {
19744   var i = indexes.length, permutes = new Array(i);
19745   while (i--) permutes[i] = array[indexes[i]];
19746   return permutes;
19747 };
19748
19749 var scan = function(values, compare) {
19750   if (!(n = values.length)) return;
19751   var n,
19752       i = 0,
19753       j = 0,
19754       xi,
19755       xj = values[j];
19756
19757   if (compare == null) compare = ascending;
19758
19759   while (++i < n) {
19760     if (compare(xi = values[i], xj) < 0 || compare(xj, xj) !== 0) {
19761       xj = xi, j = i;
19762     }
19763   }
19764
19765   if (compare(xj, xj) === 0) return j;
19766 };
19767
19768 var shuffle = function(array, i0, i1) {
19769   var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0),
19770       t,
19771       i;
19772
19773   while (m) {
19774     i = Math.random() * m-- | 0;
19775     t = array[m + i0];
19776     array[m + i0] = array[i + i0];
19777     array[i + i0] = t;
19778   }
19779
19780   return array;
19781 };
19782
19783 var sum = function(values, valueof) {
19784   var n = values.length,
19785       i = -1,
19786       value,
19787       sum = 0;
19788
19789   if (valueof == null) {
19790     while (++i < n) {
19791       if (value = +values[i]) sum += value; // Note: zero and null are equivalent.
19792     }
19793   }
19794
19795   else {
19796     while (++i < n) {
19797       if (value = +valueof(values[i], i, values)) sum += value;
19798     }
19799   }
19800
19801   return sum;
19802 };
19803
19804 var transpose = function(matrix) {
19805   if (!(n = matrix.length)) return [];
19806   for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) {
19807     for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) {
19808       row[j] = matrix[j][i];
19809     }
19810   }
19811   return transpose;
19812 };
19813
19814 function length(d) {
19815   return d.length;
19816 }
19817
19818 var zip = function() {
19819   return transpose(arguments);
19820 };
19821
19822 var slice$1 = Array.prototype.slice;
19823
19824 var identity$1 = function(x) {
19825   return x;
19826 };
19827
19828 var top = 1;
19829 var right = 2;
19830 var bottom = 3;
19831 var left = 4;
19832 var epsilon = 1e-6;
19833
19834 function translateX(x) {
19835   return "translate(" + x + ",0)";
19836 }
19837
19838 function translateY(y) {
19839   return "translate(0," + y + ")";
19840 }
19841
19842 function center(scale) {
19843   var offset = scale.bandwidth() / 2;
19844   if (scale.round()) offset = Math.round(offset);
19845   return function(d) {
19846     return scale(d) + offset;
19847   };
19848 }
19849
19850 function entering() {
19851   return !this.__axis;
19852 }
19853
19854 function axis(orient, scale) {
19855   var tickArguments = [],
19856       tickValues = null,
19857       tickFormat = null,
19858       tickSizeInner = 6,
19859       tickSizeOuter = 6,
19860       tickPadding = 3,
19861       k = orient === top || orient === left ? -1 : 1,
19862       x, y = orient === left || orient === right ? (x = "x", "y") : (x = "y", "x"),
19863       transform = orient === top || orient === bottom ? translateX : translateY;
19864
19865   function axis(context) {
19866     var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues,
19867         format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$1) : tickFormat,
19868         spacing = Math.max(tickSizeInner, 0) + tickPadding,
19869         range = scale.range(),
19870         range0 = range[0] + 0.5,
19871         range1 = range[range.length - 1] + 0.5,
19872         position = (scale.bandwidth ? center : identity$1)(scale.copy()),
19873         selection = context.selection ? context.selection() : context,
19874         path = selection.selectAll(".domain").data([null]),
19875         tick = selection.selectAll(".tick").data(values, scale).order(),
19876         tickExit = tick.exit(),
19877         tickEnter = tick.enter().append("g").attr("class", "tick"),
19878         line = tick.select("line"),
19879         text = tick.select("text");
19880
19881     path = path.merge(path.enter().insert("path", ".tick")
19882         .attr("class", "domain")
19883         .attr("stroke", "#000"));
19884
19885     tick = tick.merge(tickEnter);
19886
19887     line = line.merge(tickEnter.append("line")
19888         .attr("stroke", "#000")
19889         .attr(x + "2", k * tickSizeInner)
19890         .attr(y + "1", 0.5)
19891         .attr(y + "2", 0.5));
19892
19893     text = text.merge(tickEnter.append("text")
19894         .attr("fill", "#000")
19895         .attr(x, k * spacing)
19896         .attr(y, 0.5)
19897         .attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em"));
19898
19899     if (context !== selection) {
19900       path = path.transition(context);
19901       tick = tick.transition(context);
19902       line = line.transition(context);
19903       text = text.transition(context);
19904
19905       tickExit = tickExit.transition(context)
19906           .attr("opacity", epsilon)
19907           .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d) : this.getAttribute("transform"); });
19908
19909       tickEnter
19910           .attr("opacity", epsilon)
19911           .attr("transform", function(d) { var p = this.parentNode.__axis; return transform(p && isFinite(p = p(d)) ? p : position(d)); });
19912     }
19913
19914     tickExit.remove();
19915
19916     path
19917         .attr("d", orient === left || orient == right
19918             ? "M" + k * tickSizeOuter + "," + range0 + "H0.5V" + range1 + "H" + k * tickSizeOuter
19919             : "M" + range0 + "," + k * tickSizeOuter + "V0.5H" + range1 + "V" + k * tickSizeOuter);
19920
19921     tick
19922         .attr("opacity", 1)
19923         .attr("transform", function(d) { return transform(position(d)); });
19924
19925     line
19926         .attr(x + "2", k * tickSizeInner);
19927
19928     text
19929         .attr(x, k * spacing)
19930         .text(format);
19931
19932     selection.filter(entering)
19933         .attr("fill", "none")
19934         .attr("font-size", 10)
19935         .attr("font-family", "sans-serif")
19936         .attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle");
19937
19938     selection
19939         .each(function() { this.__axis = position; });
19940   }
19941
19942   axis.scale = function(_) {
19943     return arguments.length ? (scale = _, axis) : scale;
19944   };
19945
19946   axis.ticks = function() {
19947     return tickArguments = slice$1.call(arguments), axis;
19948   };
19949
19950   axis.tickArguments = function(_) {
19951     return arguments.length ? (tickArguments = _ == null ? [] : slice$1.call(_), axis) : tickArguments.slice();
19952   };
19953
19954   axis.tickValues = function(_) {
19955     return arguments.length ? (tickValues = _ == null ? null : slice$1.call(_), axis) : tickValues && tickValues.slice();
19956   };
19957
19958   axis.tickFormat = function(_) {
19959     return arguments.length ? (tickFormat = _, axis) : tickFormat;
19960   };
19961
19962   axis.tickSize = function(_) {
19963     return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner;
19964   };
19965
19966   axis.tickSizeInner = function(_) {
19967     return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner;
19968   };
19969
19970   axis.tickSizeOuter = function(_) {
19971     return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter;
19972   };
19973
19974   axis.tickPadding = function(_) {
19975     return arguments.length ? (tickPadding = +_, axis) : tickPadding;
19976   };
19977
19978   return axis;
19979 }
19980
19981 function axisTop(scale) {
19982   return axis(top, scale);
19983 }
19984
19985 function axisRight(scale) {
19986   return axis(right, scale);
19987 }
19988
19989 function axisBottom(scale) {
19990   return axis(bottom, scale);
19991 }
19992
19993 function axisLeft(scale) {
19994   return axis(left, scale);
19995 }
19996
19997 var noop = {value: function() {}};
19998
19999 function dispatch() {
20000   for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
20001     if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
20002     _[t] = [];
20003   }
20004   return new Dispatch(_);
20005 }
20006
20007 function Dispatch(_) {
20008   this._ = _;
20009 }
20010
20011 function parseTypenames(typenames, types) {
20012   return typenames.trim().split(/^|\s+/).map(function(t) {
20013     var name = "", i = t.indexOf(".");
20014     if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
20015     if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
20016     return {type: t, name: name};
20017   });
20018 }
20019
20020 Dispatch.prototype = dispatch.prototype = {
20021   constructor: Dispatch,
20022   on: function(typename, callback) {
20023     var _ = this._,
20024         T = parseTypenames(typename + "", _),
20025         t,
20026         i = -1,
20027         n = T.length;
20028
20029     // If no callback was specified, return the callback of the given type and name.
20030     if (arguments.length < 2) {
20031       while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
20032       return;
20033     }
20034
20035     // If a type was specified, set the callback for the given type and name.
20036     // Otherwise, if a null callback was specified, remove callbacks of the given name.
20037     if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
20038     while (++i < n) {
20039       if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
20040       else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);
20041     }
20042
20043     return this;
20044   },
20045   copy: function() {
20046     var copy = {}, _ = this._;
20047     for (var t in _) copy[t] = _[t].slice();
20048     return new Dispatch(copy);
20049   },
20050   call: function(type, that) {
20051     if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
20052     if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
20053     for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
20054   },
20055   apply: function(type, that, args) {
20056     if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
20057     for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
20058   }
20059 };
20060
20061 function get(type, name) {
20062   for (var i = 0, n = type.length, c; i < n; ++i) {
20063     if ((c = type[i]).name === name) {
20064       return c.value;
20065     }
20066   }
20067 }
20068
20069 function set(type, name, callback) {
20070   for (var i = 0, n = type.length; i < n; ++i) {
20071     if (type[i].name === name) {
20072       type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
20073       break;
20074     }
20075   }
20076   if (callback != null) type.push({name: name, value: callback});
20077   return type;
20078 }
20079
20080 var xhtml = "http://www.w3.org/1999/xhtml";
20081
20082 var namespaces = {
20083   svg: "http://www.w3.org/2000/svg",
20084   xhtml: xhtml,
20085   xlink: "http://www.w3.org/1999/xlink",
20086   xml: "http://www.w3.org/XML/1998/namespace",
20087   xmlns: "http://www.w3.org/2000/xmlns/"
20088 };
20089
20090 var namespace = function(name) {
20091   var prefix = name += "", i = prefix.indexOf(":");
20092   if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
20093   return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name;
20094 };
20095
20096 function creatorInherit(name) {
20097   return function() {
20098     var document = this.ownerDocument,
20099         uri = this.namespaceURI;
20100     return uri === xhtml && document.documentElement.namespaceURI === xhtml
20101         ? document.createElement(name)
20102         : document.createElementNS(uri, name);
20103   };
20104 }
20105
20106 function creatorFixed(fullname) {
20107   return function() {
20108     return this.ownerDocument.createElementNS(fullname.space, fullname.local);
20109   };
20110 }
20111
20112 var creator = function(name) {
20113   var fullname = namespace(name);
20114   return (fullname.local
20115       ? creatorFixed
20116       : creatorInherit)(fullname);
20117 };
20118
20119 var nextId = 0;
20120
20121 function local$1() {
20122   return new Local;
20123 }
20124
20125 function Local() {
20126   this._ = "@" + (++nextId).toString(36);
20127 }
20128
20129 Local.prototype = local$1.prototype = {
20130   constructor: Local,
20131   get: function(node) {
20132     var id = this._;
20133     while (!(id in node)) if (!(node = node.parentNode)) return;
20134     return node[id];
20135   },
20136   set: function(node, value) {
20137     return node[this._] = value;
20138   },
20139   remove: function(node) {
20140     return this._ in node && delete node[this._];
20141   },
20142   toString: function() {
20143     return this._;
20144   }
20145 };
20146
20147 var matcher = function(selector) {
20148   return function() {
20149     return this.matches(selector);
20150   };
20151 };
20152
20153 if (typeof document !== "undefined") {
20154   var element = document.documentElement;
20155   if (!element.matches) {
20156     var vendorMatches = element.webkitMatchesSelector
20157         || element.msMatchesSelector
20158         || element.mozMatchesSelector
20159         || element.oMatchesSelector;
20160     matcher = function(selector) {
20161       return function() {
20162         return vendorMatches.call(this, selector);
20163       };
20164     };
20165   }
20166 }
20167
20168 var matcher$1 = matcher;
20169
20170 var filterEvents = {};
20171
20172 var event = null;
20173
20174 if (typeof document !== "undefined") {
20175   var element$1 = document.documentElement;
20176   if (!("onmouseenter" in element$1)) {
20177     filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"};
20178   }
20179 }
20180
20181 function filterContextListener(listener, index, group) {
20182   listener = contextListener(listener, index, group);
20183   return function(event) {
20184     var related = event.relatedTarget;
20185     if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) {
20186       listener.call(this, event);
20187     }
20188   };
20189 }
20190
20191 function contextListener(listener, index, group) {
20192   return function(event1) {
20193     var event0 = event; // Events can be reentrant (e.g., focus).
20194     event = event1;
20195     try {
20196       listener.call(this, this.__data__, index, group);
20197     } finally {
20198       event = event0;
20199     }
20200   };
20201 }
20202
20203 function parseTypenames$1(typenames) {
20204   return typenames.trim().split(/^|\s+/).map(function(t) {
20205     var name = "", i = t.indexOf(".");
20206     if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
20207     return {type: t, name: name};
20208   });
20209 }
20210
20211 function onRemove(typename) {
20212   return function() {
20213     var on = this.__on;
20214     if (!on) return;
20215     for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
20216       if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
20217         this.removeEventListener(o.type, o.listener, o.capture);
20218       } else {
20219         on[++i] = o;
20220       }
20221     }
20222     if (++i) on.length = i;
20223     else delete this.__on;
20224   };
20225 }
20226
20227 function onAdd(typename, value, capture) {
20228   var wrap = filterEvents.hasOwnProperty(typename.type) ? filterContextListener : contextListener;
20229   return function(d, i, group) {
20230     var on = this.__on, o, listener = wrap(value, i, group);
20231     if (on) for (var j = 0, m = on.length; j < m; ++j) {
20232       if ((o = on[j]).type === typename.type && o.name === typename.name) {
20233         this.removeEventListener(o.type, o.listener, o.capture);
20234         this.addEventListener(o.type, o.listener = listener, o.capture = capture);
20235         o.value = value;
20236         return;
20237       }
20238     }
20239     this.addEventListener(typename.type, listener, capture);
20240     o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture};
20241     if (!on) this.__on = [o];
20242     else on.push(o);
20243   };
20244 }
20245
20246 var selection_on = function(typename, value, capture) {
20247   var typenames = parseTypenames$1(typename + ""), i, n = typenames.length, t;
20248
20249   if (arguments.length < 2) {
20250     var on = this.node().__on;
20251     if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
20252       for (i = 0, o = on[j]; i < n; ++i) {
20253         if ((t = typenames[i]).type === o.type && t.name === o.name) {
20254           return o.value;
20255         }
20256       }
20257     }
20258     return;
20259   }
20260
20261   on = value ? onAdd : onRemove;
20262   if (capture == null) capture = false;
20263   for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture));
20264   return this;
20265 };
20266
20267 function customEvent(event1, listener, that, args) {
20268   var event0 = event;
20269   event1.sourceEvent = event;
20270   event = event1;
20271   try {
20272     return listener.apply(that, args);
20273   } finally {
20274     event = event0;
20275   }
20276 }
20277
20278 var sourceEvent = function() {
20279   var current = event, source;
20280   while (source = current.sourceEvent) current = source;
20281   return current;
20282 };
20283
20284 var point = function(node, event) {
20285   var svg = node.ownerSVGElement || node;
20286
20287   if (svg.createSVGPoint) {
20288     var point = svg.createSVGPoint();
20289     point.x = event.clientX, point.y = event.clientY;
20290     point = point.matrixTransform(node.getScreenCTM().inverse());
20291     return [point.x, point.y];
20292   }
20293
20294   var rect = node.getBoundingClientRect();
20295   return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
20296 };
20297
20298 var mouse = function(node) {
20299   var event = sourceEvent();
20300   if (event.changedTouches) event = event.changedTouches[0];
20301   return point(node, event);
20302 };
20303
20304 function none() {}
20305
20306 var selector = function(selector) {
20307   return selector == null ? none : function() {
20308     return this.querySelector(selector);
20309   };
20310 };
20311
20312 var selection_select = function(select) {
20313   if (typeof select !== "function") select = selector(select);
20314
20315   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
20316     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
20317       if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
20318         if ("__data__" in node) subnode.__data__ = node.__data__;
20319         subgroup[i] = subnode;
20320       }
20321     }
20322   }
20323
20324   return new Selection(subgroups, this._parents);
20325 };
20326
20327 function empty$1() {
20328   return [];
20329 }
20330
20331 var selectorAll = function(selector) {
20332   return selector == null ? empty$1 : function() {
20333     return this.querySelectorAll(selector);
20334   };
20335 };
20336
20337 var selection_selectAll = function(select) {
20338   if (typeof select !== "function") select = selectorAll(select);
20339
20340   for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
20341     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
20342       if (node = group[i]) {
20343         subgroups.push(select.call(node, node.__data__, i, group));
20344         parents.push(node);
20345       }
20346     }
20347   }
20348
20349   return new Selection(subgroups, parents);
20350 };
20351
20352 var selection_filter = function(match) {
20353   if (typeof match !== "function") match = matcher$1(match);
20354
20355   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
20356     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
20357       if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
20358         subgroup.push(node);
20359       }
20360     }
20361   }
20362
20363   return new Selection(subgroups, this._parents);
20364 };
20365
20366 var sparse = function(update) {
20367   return new Array(update.length);
20368 };
20369
20370 var selection_enter = function() {
20371   return new Selection(this._enter || this._groups.map(sparse), this._parents);
20372 };
20373
20374 function EnterNode(parent, datum) {
20375   this.ownerDocument = parent.ownerDocument;
20376   this.namespaceURI = parent.namespaceURI;
20377   this._next = null;
20378   this._parent = parent;
20379   this.__data__ = datum;
20380 }
20381
20382 EnterNode.prototype = {
20383   constructor: EnterNode,
20384   appendChild: function(child) { return this._parent.insertBefore(child, this._next); },
20385   insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },
20386   querySelector: function(selector) { return this._parent.querySelector(selector); },
20387   querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
20388 };
20389
20390 var constant$1 = function(x) {
20391   return function() {
20392     return x;
20393   };
20394 };
20395
20396 var keyPrefix = "$"; // Protect against keys like “__proto__”.
20397
20398 function bindIndex(parent, group, enter, update, exit, data) {
20399   var i = 0,
20400       node,
20401       groupLength = group.length,
20402       dataLength = data.length;
20403
20404   // Put any non-null nodes that fit into update.
20405   // Put any null nodes into enter.
20406   // Put any remaining data into enter.
20407   for (; i < dataLength; ++i) {
20408     if (node = group[i]) {
20409       node.__data__ = data[i];
20410       update[i] = node;
20411     } else {
20412       enter[i] = new EnterNode(parent, data[i]);
20413     }
20414   }
20415
20416   // Put any non-null nodes that don’t fit into exit.
20417   for (; i < groupLength; ++i) {
20418     if (node = group[i]) {
20419       exit[i] = node;
20420     }
20421   }
20422 }
20423
20424 function bindKey(parent, group, enter, update, exit, data, key) {
20425   var i,
20426       node,
20427       nodeByKeyValue = {},
20428       groupLength = group.length,
20429       dataLength = data.length,
20430       keyValues = new Array(groupLength),
20431       keyValue;
20432
20433   // Compute the key for each node.
20434   // If multiple nodes have the same key, the duplicates are added to exit.
20435   for (i = 0; i < groupLength; ++i) {
20436     if (node = group[i]) {
20437       keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group);
20438       if (keyValue in nodeByKeyValue) {
20439         exit[i] = node;
20440       } else {
20441         nodeByKeyValue[keyValue] = node;
20442       }
20443     }
20444   }
20445
20446   // Compute the key for each datum.
20447   // If there a node associated with this key, join and add it to update.
20448   // If there is not (or the key is a duplicate), add it to enter.
20449   for (i = 0; i < dataLength; ++i) {
20450     keyValue = keyPrefix + key.call(parent, data[i], i, data);
20451     if (node = nodeByKeyValue[keyValue]) {
20452       update[i] = node;
20453       node.__data__ = data[i];
20454       nodeByKeyValue[keyValue] = null;
20455     } else {
20456       enter[i] = new EnterNode(parent, data[i]);
20457     }
20458   }
20459
20460   // Add any remaining nodes that were not bound to data to exit.
20461   for (i = 0; i < groupLength; ++i) {
20462     if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
20463       exit[i] = node;
20464     }
20465   }
20466 }
20467
20468 var selection_data = function(value, key) {
20469   if (!value) {
20470     data = new Array(this.size()), j = -1;
20471     this.each(function(d) { data[++j] = d; });
20472     return data;
20473   }
20474
20475   var bind = key ? bindKey : bindIndex,
20476       parents = this._parents,
20477       groups = this._groups;
20478
20479   if (typeof value !== "function") value = constant$1(value);
20480
20481   for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
20482     var parent = parents[j],
20483         group = groups[j],
20484         groupLength = group.length,
20485         data = value.call(parent, parent && parent.__data__, j, parents),
20486         dataLength = data.length,
20487         enterGroup = enter[j] = new Array(dataLength),
20488         updateGroup = update[j] = new Array(dataLength),
20489         exitGroup = exit[j] = new Array(groupLength);
20490
20491     bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
20492
20493     // Now connect the enter nodes to their following update node, such that
20494     // appendChild can insert the materialized enter node before this node,
20495     // rather than at the end of the parent node.
20496     for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
20497       if (previous = enterGroup[i0]) {
20498         if (i0 >= i1) i1 = i0 + 1;
20499         while (!(next = updateGroup[i1]) && ++i1 < dataLength);
20500         previous._next = next || null;
20501       }
20502     }
20503   }
20504
20505   update = new Selection(update, parents);
20506   update._enter = enter;
20507   update._exit = exit;
20508   return update;
20509 };
20510
20511 var selection_exit = function() {
20512   return new Selection(this._exit || this._groups.map(sparse), this._parents);
20513 };
20514
20515 var selection_merge = function(selection) {
20516
20517   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) {
20518     for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
20519       if (node = group0[i] || group1[i]) {
20520         merge[i] = node;
20521       }
20522     }
20523   }
20524
20525   for (; j < m0; ++j) {
20526     merges[j] = groups0[j];
20527   }
20528
20529   return new Selection(merges, this._parents);
20530 };
20531
20532 var selection_order = function() {
20533
20534   for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
20535     for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
20536       if (node = group[i]) {
20537         if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
20538         next = node;
20539       }
20540     }
20541   }
20542
20543   return this;
20544 };
20545
20546 var selection_sort = function(compare) {
20547   if (!compare) compare = ascending$1;
20548
20549   function compareNode(a, b) {
20550     return a && b ? compare(a.__data__, b.__data__) : !a - !b;
20551   }
20552
20553   for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
20554     for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
20555       if (node = group[i]) {
20556         sortgroup[i] = node;
20557       }
20558     }
20559     sortgroup.sort(compareNode);
20560   }
20561
20562   return new Selection(sortgroups, this._parents).order();
20563 };
20564
20565 function ascending$1(a, b) {
20566   return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
20567 }
20568
20569 var selection_call = function() {
20570   var callback = arguments[0];
20571   arguments[0] = this;
20572   callback.apply(null, arguments);
20573   return this;
20574 };
20575
20576 var selection_nodes = function() {
20577   var nodes = new Array(this.size()), i = -1;
20578   this.each(function() { nodes[++i] = this; });
20579   return nodes;
20580 };
20581
20582 var selection_node = function() {
20583
20584   for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
20585     for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
20586       var node = group[i];
20587       if (node) return node;
20588     }
20589   }
20590
20591   return null;
20592 };
20593
20594 var selection_size = function() {
20595   var size = 0;
20596   this.each(function() { ++size; });
20597   return size;
20598 };
20599
20600 var selection_empty = function() {
20601   return !this.node();
20602 };
20603
20604 var selection_each = function(callback) {
20605
20606   for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
20607     for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
20608       if (node = group[i]) callback.call(node, node.__data__, i, group);
20609     }
20610   }
20611
20612   return this;
20613 };
20614
20615 function attrRemove(name) {
20616   return function() {
20617     this.removeAttribute(name);
20618   };
20619 }
20620
20621 function attrRemoveNS(fullname) {
20622   return function() {
20623     this.removeAttributeNS(fullname.space, fullname.local);
20624   };
20625 }
20626
20627 function attrConstant(name, value) {
20628   return function() {
20629     this.setAttribute(name, value);
20630   };
20631 }
20632
20633 function attrConstantNS(fullname, value) {
20634   return function() {
20635     this.setAttributeNS(fullname.space, fullname.local, value);
20636   };
20637 }
20638
20639 function attrFunction(name, value) {
20640   return function() {
20641     var v = value.apply(this, arguments);
20642     if (v == null) this.removeAttribute(name);
20643     else this.setAttribute(name, v);
20644   };
20645 }
20646
20647 function attrFunctionNS(fullname, value) {
20648   return function() {
20649     var v = value.apply(this, arguments);
20650     if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
20651     else this.setAttributeNS(fullname.space, fullname.local, v);
20652   };
20653 }
20654
20655 var selection_attr = function(name, value) {
20656   var fullname = namespace(name);
20657
20658   if (arguments.length < 2) {
20659     var node = this.node();
20660     return fullname.local
20661         ? node.getAttributeNS(fullname.space, fullname.local)
20662         : node.getAttribute(fullname);
20663   }
20664
20665   return this.each((value == null
20666       ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function"
20667       ? (fullname.local ? attrFunctionNS : attrFunction)
20668       : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));
20669 };
20670
20671 var window$1 = function(node) {
20672   return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
20673       || (node.document && node) // node is a Window
20674       || node.defaultView; // node is a Document
20675 };
20676
20677 function styleRemove(name) {
20678   return function() {
20679     this.style.removeProperty(name);
20680   };
20681 }
20682
20683 function styleConstant(name, value, priority) {
20684   return function() {
20685     this.style.setProperty(name, value, priority);
20686   };
20687 }
20688
20689 function styleFunction(name, value, priority) {
20690   return function() {
20691     var v = value.apply(this, arguments);
20692     if (v == null) this.style.removeProperty(name);
20693     else this.style.setProperty(name, v, priority);
20694   };
20695 }
20696
20697 var selection_style = function(name, value, priority) {
20698   var node;
20699   return arguments.length > 1
20700       ? this.each((value == null
20701             ? styleRemove : typeof value === "function"
20702             ? styleFunction
20703             : styleConstant)(name, value, priority == null ? "" : priority))
20704       : window$1(node = this.node())
20705           .getComputedStyle(node, null)
20706           .getPropertyValue(name);
20707 };
20708
20709 function propertyRemove(name) {
20710   return function() {
20711     delete this[name];
20712   };
20713 }
20714
20715 function propertyConstant(name, value) {
20716   return function() {
20717     this[name] = value;
20718   };
20719 }
20720
20721 function propertyFunction(name, value) {
20722   return function() {
20723     var v = value.apply(this, arguments);
20724     if (v == null) delete this[name];
20725     else this[name] = v;
20726   };
20727 }
20728
20729 var selection_property = function(name, value) {
20730   return arguments.length > 1
20731       ? this.each((value == null
20732           ? propertyRemove : typeof value === "function"
20733           ? propertyFunction
20734           : propertyConstant)(name, value))
20735       : this.node()[name];
20736 };
20737
20738 function classArray(string) {
20739   return string.trim().split(/^|\s+/);
20740 }
20741
20742 function classList(node) {
20743   return node.classList || new ClassList(node);
20744 }
20745
20746 function ClassList(node) {
20747   this._node = node;
20748   this._names = classArray(node.getAttribute("class") || "");
20749 }
20750
20751 ClassList.prototype = {
20752   add: function(name) {
20753     var i = this._names.indexOf(name);
20754     if (i < 0) {
20755       this._names.push(name);
20756       this._node.setAttribute("class", this._names.join(" "));
20757     }
20758   },
20759   remove: function(name) {
20760     var i = this._names.indexOf(name);
20761     if (i >= 0) {
20762       this._names.splice(i, 1);
20763       this._node.setAttribute("class", this._names.join(" "));
20764     }
20765   },
20766   contains: function(name) {
20767     return this._names.indexOf(name) >= 0;
20768   }
20769 };
20770
20771 function classedAdd(node, names) {
20772   var list = classList(node), i = -1, n = names.length;
20773   while (++i < n) list.add(names[i]);
20774 }
20775
20776 function classedRemove(node, names) {
20777   var list = classList(node), i = -1, n = names.length;
20778   while (++i < n) list.remove(names[i]);
20779 }
20780
20781 function classedTrue(names) {
20782   return function() {
20783     classedAdd(this, names);
20784   };
20785 }
20786
20787 function classedFalse(names) {
20788   return function() {
20789     classedRemove(this, names);
20790   };
20791 }
20792
20793 function classedFunction(names, value) {
20794   return function() {
20795     (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
20796   };
20797 }
20798
20799 var selection_classed = function(name, value) {
20800   var names = classArray(name + "");
20801
20802   if (arguments.length < 2) {
20803     var list = classList(this.node()), i = -1, n = names.length;
20804     while (++i < n) if (!list.contains(names[i])) return false;
20805     return true;
20806   }
20807
20808   return this.each((typeof value === "function"
20809       ? classedFunction : value
20810       ? classedTrue
20811       : classedFalse)(names, value));
20812 };
20813
20814 function textRemove() {
20815   this.textContent = "";
20816 }
20817
20818 function textConstant(value) {
20819   return function() {
20820     this.textContent = value;
20821   };
20822 }
20823
20824 function textFunction(value) {
20825   return function() {
20826     var v = value.apply(this, arguments);
20827     this.textContent = v == null ? "" : v;
20828   };
20829 }
20830
20831 var selection_text = function(value) {
20832   return arguments.length
20833       ? this.each(value == null
20834           ? textRemove : (typeof value === "function"
20835           ? textFunction
20836           : textConstant)(value))
20837       : this.node().textContent;
20838 };
20839
20840 function htmlRemove() {
20841   this.innerHTML = "";
20842 }
20843
20844 function htmlConstant(value) {
20845   return function() {
20846     this.innerHTML = value;
20847   };
20848 }
20849
20850 function htmlFunction(value) {
20851   return function() {
20852     var v = value.apply(this, arguments);
20853     this.innerHTML = v == null ? "" : v;
20854   };
20855 }
20856
20857 var selection_html = function(value) {
20858   return arguments.length
20859       ? this.each(value == null
20860           ? htmlRemove : (typeof value === "function"
20861           ? htmlFunction
20862           : htmlConstant)(value))
20863       : this.node().innerHTML;
20864 };
20865
20866 function raise() {
20867   if (this.nextSibling) this.parentNode.appendChild(this);
20868 }
20869
20870 var selection_raise = function() {
20871   return this.each(raise);
20872 };
20873
20874 function lower() {
20875   if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
20876 }
20877
20878 var selection_lower = function() {
20879   return this.each(lower);
20880 };
20881
20882 var selection_append = function(name) {
20883   var create = typeof name === "function" ? name : creator(name);
20884   return this.select(function() {
20885     return this.appendChild(create.apply(this, arguments));
20886   });
20887 };
20888
20889 function constantNull() {
20890   return null;
20891 }
20892
20893 var selection_insert = function(name, before) {
20894   var create = typeof name === "function" ? name : creator(name),
20895       select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
20896   return this.select(function() {
20897     return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
20898   });
20899 };
20900
20901 function remove() {
20902   var parent = this.parentNode;
20903   if (parent) parent.removeChild(this);
20904 }
20905
20906 var selection_remove = function() {
20907   return this.each(remove);
20908 };
20909
20910 var selection_datum = function(value) {
20911   return arguments.length
20912       ? this.property("__data__", value)
20913       : this.node().__data__;
20914 };
20915
20916 function dispatchEvent(node, type, params) {
20917   var window = window$1(node),
20918       event = window.CustomEvent;
20919
20920   if (event) {
20921     event = new event(type, params);
20922   } else {
20923     event = window.document.createEvent("Event");
20924     if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
20925     else event.initEvent(type, false, false);
20926   }
20927
20928   node.dispatchEvent(event);
20929 }
20930
20931 function dispatchConstant(type, params) {
20932   return function() {
20933     return dispatchEvent(this, type, params);
20934   };
20935 }
20936
20937 function dispatchFunction(type, params) {
20938   return function() {
20939     return dispatchEvent(this, type, params.apply(this, arguments));
20940   };
20941 }
20942
20943 var selection_dispatch = function(type, params) {
20944   return this.each((typeof params === "function"
20945       ? dispatchFunction
20946       : dispatchConstant)(type, params));
20947 };
20948
20949 var root = [null];
20950
20951 function Selection(groups, parents) {
20952   this._groups = groups;
20953   this._parents = parents;
20954 }
20955
20956 function selection() {
20957   return new Selection([[document.documentElement]], root);
20958 }
20959
20960 Selection.prototype = selection.prototype = {
20961   constructor: Selection,
20962   select: selection_select,
20963   selectAll: selection_selectAll,
20964   filter: selection_filter,
20965   data: selection_data,
20966   enter: selection_enter,
20967   exit: selection_exit,
20968   merge: selection_merge,
20969   order: selection_order,
20970   sort: selection_sort,
20971   call: selection_call,
20972   nodes: selection_nodes,
20973   node: selection_node,
20974   size: selection_size,
20975   empty: selection_empty,
20976   each: selection_each,
20977   attr: selection_attr,
20978   style: selection_style,
20979   property: selection_property,
20980   classed: selection_classed,
20981   text: selection_text,
20982   html: selection_html,
20983   raise: selection_raise,
20984   lower: selection_lower,
20985   append: selection_append,
20986   insert: selection_insert,
20987   remove: selection_remove,
20988   datum: selection_datum,
20989   on: selection_on,
20990   dispatch: selection_dispatch
20991 };
20992
20993 var select = function(selector) {
20994   return typeof selector === "string"
20995       ? new Selection([[document.querySelector(selector)]], [document.documentElement])
20996       : new Selection([[selector]], root);
20997 };
20998
20999 var selectAll = function(selector) {
21000   return typeof selector === "string"
21001       ? new Selection([document.querySelectorAll(selector)], [document.documentElement])
21002       : new Selection([selector == null ? [] : selector], root);
21003 };
21004
21005 var touch = function(node, touches, identifier) {
21006   if (arguments.length < 3) identifier = touches, touches = sourceEvent().changedTouches;
21007
21008   for (var i = 0, n = touches ? touches.length : 0, touch; i < n; ++i) {
21009     if ((touch = touches[i]).identifier === identifier) {
21010       return point(node, touch);
21011     }
21012   }
21013
21014   return null;
21015 };
21016
21017 var touches = function(node, touches) {
21018   if (touches == null) touches = sourceEvent().touches;
21019
21020   for (var i = 0, n = touches ? touches.length : 0, points = new Array(n); i < n; ++i) {
21021     points[i] = point(node, touches[i]);
21022   }
21023
21024   return points;
21025 };
21026
21027 function nopropagation() {
21028   event.stopImmediatePropagation();
21029 }
21030
21031 var noevent = function() {
21032   event.preventDefault();
21033   event.stopImmediatePropagation();
21034 };
21035
21036 var dragDisable = function(view) {
21037   var root = view.document.documentElement,
21038       selection$$1 = select(view).on("dragstart.drag", noevent, true);
21039   if ("onselectstart" in root) {
21040     selection$$1.on("selectstart.drag", noevent, true);
21041   } else {
21042     root.__noselect = root.style.MozUserSelect;
21043     root.style.MozUserSelect = "none";
21044   }
21045 };
21046
21047 function yesdrag(view, noclick) {
21048   var root = view.document.documentElement,
21049       selection$$1 = select(view).on("dragstart.drag", null);
21050   if (noclick) {
21051     selection$$1.on("click.drag", noevent, true);
21052     setTimeout(function() { selection$$1.on("click.drag", null); }, 0);
21053   }
21054   if ("onselectstart" in root) {
21055     selection$$1.on("selectstart.drag", null);
21056   } else {
21057     root.style.MozUserSelect = root.__noselect;
21058     delete root.__noselect;
21059   }
21060 }
21061
21062 var constant$2 = function(x) {
21063   return function() {
21064     return x;
21065   };
21066 };
21067
21068 function DragEvent(target, type, subject, id, active, x, y, dx, dy, dispatch) {
21069   this.target = target;
21070   this.type = type;
21071   this.subject = subject;
21072   this.identifier = id;
21073   this.active = active;
21074   this.x = x;
21075   this.y = y;
21076   this.dx = dx;
21077   this.dy = dy;
21078   this._ = dispatch;
21079 }
21080
21081 DragEvent.prototype.on = function() {
21082   var value = this._.on.apply(this._, arguments);
21083   return value === this._ ? this : value;
21084 };
21085
21086 // Ignore right-click, since that should open the context menu.
21087 function defaultFilter$1() {
21088   return !event.button;
21089 }
21090
21091 function defaultContainer() {
21092   return this.parentNode;
21093 }
21094
21095 function defaultSubject(d) {
21096   return d == null ? {x: event.x, y: event.y} : d;
21097 }
21098
21099 var drag = function() {
21100   var filter = defaultFilter$1,
21101       container = defaultContainer,
21102       subject = defaultSubject,
21103       gestures = {},
21104       listeners = dispatch("start", "drag", "end"),
21105       active = 0,
21106       mousemoving,
21107       touchending;
21108
21109   function drag(selection$$1) {
21110     selection$$1
21111         .on("mousedown.drag", mousedowned)
21112         .on("touchstart.drag", touchstarted)
21113         .on("touchmove.drag", touchmoved)
21114         .on("touchend.drag touchcancel.drag", touchended)
21115         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
21116   }
21117
21118   function mousedowned() {
21119     if (touchending || !filter.apply(this, arguments)) return;
21120     var gesture = beforestart("mouse", container.apply(this, arguments), mouse, this, arguments);
21121     if (!gesture) return;
21122     select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
21123     dragDisable(event.view);
21124     nopropagation();
21125     mousemoving = false;
21126     gesture("start");
21127   }
21128
21129   function mousemoved() {
21130     noevent();
21131     mousemoving = true;
21132     gestures.mouse("drag");
21133   }
21134
21135   function mouseupped() {
21136     select(event.view).on("mousemove.drag mouseup.drag", null);
21137     yesdrag(event.view, mousemoving);
21138     noevent();
21139     gestures.mouse("end");
21140   }
21141
21142   function touchstarted() {
21143     if (!filter.apply(this, arguments)) return;
21144     var touches$$1 = event.changedTouches,
21145         c = container.apply(this, arguments),
21146         n = touches$$1.length, i, gesture;
21147
21148     for (i = 0; i < n; ++i) {
21149       if (gesture = beforestart(touches$$1[i].identifier, c, touch, this, arguments)) {
21150         nopropagation();
21151         gesture("start");
21152       }
21153     }
21154   }
21155
21156   function touchmoved() {
21157     var touches$$1 = event.changedTouches,
21158         n = touches$$1.length, i, gesture;
21159
21160     for (i = 0; i < n; ++i) {
21161       if (gesture = gestures[touches$$1[i].identifier]) {
21162         noevent();
21163         gesture("drag");
21164       }
21165     }
21166   }
21167
21168   function touchended() {
21169     var touches$$1 = event.changedTouches,
21170         n = touches$$1.length, i, gesture;
21171
21172     if (touchending) clearTimeout(touchending);
21173     touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
21174     for (i = 0; i < n; ++i) {
21175       if (gesture = gestures[touches$$1[i].identifier]) {
21176         nopropagation();
21177         gesture("end");
21178       }
21179     }
21180   }
21181
21182   function beforestart(id, container, point, that, args) {
21183     var p = point(container, id), s, dx, dy,
21184         sublisteners = listeners.copy();
21185
21186     if (!customEvent(new DragEvent(drag, "beforestart", s, id, active, p[0], p[1], 0, 0, sublisteners), function() {
21187       if ((event.subject = s = subject.apply(that, args)) == null) return false;
21188       dx = s.x - p[0] || 0;
21189       dy = s.y - p[1] || 0;
21190       return true;
21191     })) return;
21192
21193     return function gesture(type) {
21194       var p0 = p, n;
21195       switch (type) {
21196         case "start": gestures[id] = gesture, n = active++; break;
21197         case "end": delete gestures[id], --active; // nobreak
21198         case "drag": p = point(container, id), n = active; break;
21199       }
21200       customEvent(new DragEvent(drag, type, s, id, n, p[0] + dx, p[1] + dy, p[0] - p0[0], p[1] - p0[1], sublisteners), sublisteners.apply, sublisteners, [type, that, args]);
21201     };
21202   }
21203
21204   drag.filter = function(_) {
21205     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$2(!!_), drag) : filter;
21206   };
21207
21208   drag.container = function(_) {
21209     return arguments.length ? (container = typeof _ === "function" ? _ : constant$2(_), drag) : container;
21210   };
21211
21212   drag.subject = function(_) {
21213     return arguments.length ? (subject = typeof _ === "function" ? _ : constant$2(_), drag) : subject;
21214   };
21215
21216   drag.on = function() {
21217     var value = listeners.on.apply(listeners, arguments);
21218     return value === listeners ? drag : value;
21219   };
21220
21221   return drag;
21222 };
21223
21224 var define = function(constructor, factory, prototype) {
21225   constructor.prototype = factory.prototype = prototype;
21226   prototype.constructor = constructor;
21227 };
21228
21229 function extend(parent, definition) {
21230   var prototype = Object.create(parent.prototype);
21231   for (var key in definition) prototype[key] = definition[key];
21232   return prototype;
21233 }
21234
21235 function Color() {}
21236
21237 var darker = 0.7;
21238 var brighter = 1 / darker;
21239
21240 var reI = "\\s*([+-]?\\d+)\\s*";
21241 var reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*";
21242 var reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*";
21243 var reHex3 = /^#([0-9a-f]{3})$/;
21244 var reHex6 = /^#([0-9a-f]{6})$/;
21245 var reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$");
21246 var reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$");
21247 var reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$");
21248 var reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$");
21249 var reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$");
21250 var reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
21251
21252 var named = {
21253   aliceblue: 0xf0f8ff,
21254   antiquewhite: 0xfaebd7,
21255   aqua: 0x00ffff,
21256   aquamarine: 0x7fffd4,
21257   azure: 0xf0ffff,
21258   beige: 0xf5f5dc,
21259   bisque: 0xffe4c4,
21260   black: 0x000000,
21261   blanchedalmond: 0xffebcd,
21262   blue: 0x0000ff,
21263   blueviolet: 0x8a2be2,
21264   brown: 0xa52a2a,
21265   burlywood: 0xdeb887,
21266   cadetblue: 0x5f9ea0,
21267   chartreuse: 0x7fff00,
21268   chocolate: 0xd2691e,
21269   coral: 0xff7f50,
21270   cornflowerblue: 0x6495ed,
21271   cornsilk: 0xfff8dc,
21272   crimson: 0xdc143c,
21273   cyan: 0x00ffff,
21274   darkblue: 0x00008b,
21275   darkcyan: 0x008b8b,
21276   darkgoldenrod: 0xb8860b,
21277   darkgray: 0xa9a9a9,
21278   darkgreen: 0x006400,
21279   darkgrey: 0xa9a9a9,
21280   darkkhaki: 0xbdb76b,
21281   darkmagenta: 0x8b008b,
21282   darkolivegreen: 0x556b2f,
21283   darkorange: 0xff8c00,
21284   darkorchid: 0x9932cc,
21285   darkred: 0x8b0000,
21286   darksalmon: 0xe9967a,
21287   darkseagreen: 0x8fbc8f,
21288   darkslateblue: 0x483d8b,
21289   darkslategray: 0x2f4f4f,
21290   darkslategrey: 0x2f4f4f,
21291   darkturquoise: 0x00ced1,
21292   darkviolet: 0x9400d3,
21293   deeppink: 0xff1493,
21294   deepskyblue: 0x00bfff,
21295   dimgray: 0x696969,
21296   dimgrey: 0x696969,
21297   dodgerblue: 0x1e90ff,
21298   firebrick: 0xb22222,
21299   floralwhite: 0xfffaf0,
21300   forestgreen: 0x228b22,
21301   fuchsia: 0xff00ff,
21302   gainsboro: 0xdcdcdc,
21303   ghostwhite: 0xf8f8ff,
21304   gold: 0xffd700,
21305   goldenrod: 0xdaa520,
21306   gray: 0x808080,
21307   green: 0x008000,
21308   greenyellow: 0xadff2f,
21309   grey: 0x808080,
21310   honeydew: 0xf0fff0,
21311   hotpink: 0xff69b4,
21312   indianred: 0xcd5c5c,
21313   indigo: 0x4b0082,
21314   ivory: 0xfffff0,
21315   khaki: 0xf0e68c,
21316   lavender: 0xe6e6fa,
21317   lavenderblush: 0xfff0f5,
21318   lawngreen: 0x7cfc00,
21319   lemonchiffon: 0xfffacd,
21320   lightblue: 0xadd8e6,
21321   lightcoral: 0xf08080,
21322   lightcyan: 0xe0ffff,
21323   lightgoldenrodyellow: 0xfafad2,
21324   lightgray: 0xd3d3d3,
21325   lightgreen: 0x90ee90,
21326   lightgrey: 0xd3d3d3,
21327   lightpink: 0xffb6c1,
21328   lightsalmon: 0xffa07a,
21329   lightseagreen: 0x20b2aa,
21330   lightskyblue: 0x87cefa,
21331   lightslategray: 0x778899,
21332   lightslategrey: 0x778899,
21333   lightsteelblue: 0xb0c4de,
21334   lightyellow: 0xffffe0,
21335   lime: 0x00ff00,
21336   limegreen: 0x32cd32,
21337   linen: 0xfaf0e6,
21338   magenta: 0xff00ff,
21339   maroon: 0x800000,
21340   mediumaquamarine: 0x66cdaa,
21341   mediumblue: 0x0000cd,
21342   mediumorchid: 0xba55d3,
21343   mediumpurple: 0x9370db,
21344   mediumseagreen: 0x3cb371,
21345   mediumslateblue: 0x7b68ee,
21346   mediumspringgreen: 0x00fa9a,
21347   mediumturquoise: 0x48d1cc,
21348   mediumvioletred: 0xc71585,
21349   midnightblue: 0x191970,
21350   mintcream: 0xf5fffa,
21351   mistyrose: 0xffe4e1,
21352   moccasin: 0xffe4b5,
21353   navajowhite: 0xffdead,
21354   navy: 0x000080,
21355   oldlace: 0xfdf5e6,
21356   olive: 0x808000,
21357   olivedrab: 0x6b8e23,
21358   orange: 0xffa500,
21359   orangered: 0xff4500,
21360   orchid: 0xda70d6,
21361   palegoldenrod: 0xeee8aa,
21362   palegreen: 0x98fb98,
21363   paleturquoise: 0xafeeee,
21364   palevioletred: 0xdb7093,
21365   papayawhip: 0xffefd5,
21366   peachpuff: 0xffdab9,
21367   peru: 0xcd853f,
21368   pink: 0xffc0cb,
21369   plum: 0xdda0dd,
21370   powderblue: 0xb0e0e6,
21371   purple: 0x800080,
21372   rebeccapurple: 0x663399,
21373   red: 0xff0000,
21374   rosybrown: 0xbc8f8f,
21375   royalblue: 0x4169e1,
21376   saddlebrown: 0x8b4513,
21377   salmon: 0xfa8072,
21378   sandybrown: 0xf4a460,
21379   seagreen: 0x2e8b57,
21380   seashell: 0xfff5ee,
21381   sienna: 0xa0522d,
21382   silver: 0xc0c0c0,
21383   skyblue: 0x87ceeb,
21384   slateblue: 0x6a5acd,
21385   slategray: 0x708090,
21386   slategrey: 0x708090,
21387   snow: 0xfffafa,
21388   springgreen: 0x00ff7f,
21389   steelblue: 0x4682b4,
21390   tan: 0xd2b48c,
21391   teal: 0x008080,
21392   thistle: 0xd8bfd8,
21393   tomato: 0xff6347,
21394   turquoise: 0x40e0d0,
21395   violet: 0xee82ee,
21396   wheat: 0xf5deb3,
21397   white: 0xffffff,
21398   whitesmoke: 0xf5f5f5,
21399   yellow: 0xffff00,
21400   yellowgreen: 0x9acd32
21401 };
21402
21403 define(Color, color, {
21404   displayable: function() {
21405     return this.rgb().displayable();
21406   },
21407   toString: function() {
21408     return this.rgb() + "";
21409   }
21410 });
21411
21412 function color(format) {
21413   var m;
21414   format = (format + "").trim().toLowerCase();
21415   return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00
21416       : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000
21417       : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
21418       : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
21419       : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
21420       : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
21421       : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
21422       : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
21423       : named.hasOwnProperty(format) ? rgbn(named[format])
21424       : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
21425       : null;
21426 }
21427
21428 function rgbn(n) {
21429   return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
21430 }
21431
21432 function rgba(r, g, b, a) {
21433   if (a <= 0) r = g = b = NaN;
21434   return new Rgb(r, g, b, a);
21435 }
21436
21437 function rgbConvert(o) {
21438   if (!(o instanceof Color)) o = color(o);
21439   if (!o) return new Rgb;
21440   o = o.rgb();
21441   return new Rgb(o.r, o.g, o.b, o.opacity);
21442 }
21443
21444 function rgb(r, g, b, opacity) {
21445   return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
21446 }
21447
21448 function Rgb(r, g, b, opacity) {
21449   this.r = +r;
21450   this.g = +g;
21451   this.b = +b;
21452   this.opacity = +opacity;
21453 }
21454
21455 define(Rgb, rgb, extend(Color, {
21456   brighter: function(k) {
21457     k = k == null ? brighter : Math.pow(brighter, k);
21458     return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
21459   },
21460   darker: function(k) {
21461     k = k == null ? darker : Math.pow(darker, k);
21462     return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
21463   },
21464   rgb: function() {
21465     return this;
21466   },
21467   displayable: function() {
21468     return (0 <= this.r && this.r <= 255)
21469         && (0 <= this.g && this.g <= 255)
21470         && (0 <= this.b && this.b <= 255)
21471         && (0 <= this.opacity && this.opacity <= 1);
21472   },
21473   toString: function() {
21474     var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
21475     return (a === 1 ? "rgb(" : "rgba(")
21476         + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
21477         + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
21478         + Math.max(0, Math.min(255, Math.round(this.b) || 0))
21479         + (a === 1 ? ")" : ", " + a + ")");
21480   }
21481 }));
21482
21483 function hsla(h, s, l, a) {
21484   if (a <= 0) h = s = l = NaN;
21485   else if (l <= 0 || l >= 1) h = s = NaN;
21486   else if (s <= 0) h = NaN;
21487   return new Hsl(h, s, l, a);
21488 }
21489
21490 function hslConvert(o) {
21491   if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
21492   if (!(o instanceof Color)) o = color(o);
21493   if (!o) return new Hsl;
21494   if (o instanceof Hsl) return o;
21495   o = o.rgb();
21496   var r = o.r / 255,
21497       g = o.g / 255,
21498       b = o.b / 255,
21499       min = Math.min(r, g, b),
21500       max = Math.max(r, g, b),
21501       h = NaN,
21502       s = max - min,
21503       l = (max + min) / 2;
21504   if (s) {
21505     if (r === max) h = (g - b) / s + (g < b) * 6;
21506     else if (g === max) h = (b - r) / s + 2;
21507     else h = (r - g) / s + 4;
21508     s /= l < 0.5 ? max + min : 2 - max - min;
21509     h *= 60;
21510   } else {
21511     s = l > 0 && l < 1 ? 0 : h;
21512   }
21513   return new Hsl(h, s, l, o.opacity);
21514 }
21515
21516 function hsl(h, s, l, opacity) {
21517   return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
21518 }
21519
21520 function Hsl(h, s, l, opacity) {
21521   this.h = +h;
21522   this.s = +s;
21523   this.l = +l;
21524   this.opacity = +opacity;
21525 }
21526
21527 define(Hsl, hsl, extend(Color, {
21528   brighter: function(k) {
21529     k = k == null ? brighter : Math.pow(brighter, k);
21530     return new Hsl(this.h, this.s, this.l * k, this.opacity);
21531   },
21532   darker: function(k) {
21533     k = k == null ? darker : Math.pow(darker, k);
21534     return new Hsl(this.h, this.s, this.l * k, this.opacity);
21535   },
21536   rgb: function() {
21537     var h = this.h % 360 + (this.h < 0) * 360,
21538         s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
21539         l = this.l,
21540         m2 = l + (l < 0.5 ? l : 1 - l) * s,
21541         m1 = 2 * l - m2;
21542     return new Rgb(
21543       hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
21544       hsl2rgb(h, m1, m2),
21545       hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
21546       this.opacity
21547     );
21548   },
21549   displayable: function() {
21550     return (0 <= this.s && this.s <= 1 || isNaN(this.s))
21551         && (0 <= this.l && this.l <= 1)
21552         && (0 <= this.opacity && this.opacity <= 1);
21553   }
21554 }));
21555
21556 /* From FvD 13.37, CSS Color Module Level 3 */
21557 function hsl2rgb(h, m1, m2) {
21558   return (h < 60 ? m1 + (m2 - m1) * h / 60
21559       : h < 180 ? m2
21560       : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60
21561       : m1) * 255;
21562 }
21563
21564 var deg2rad = Math.PI / 180;
21565 var rad2deg = 180 / Math.PI;
21566
21567 var Kn = 18;
21568 var Xn = 0.950470;
21569 var Yn = 1;
21570 var Zn = 1.088830;
21571 var t0 = 4 / 29;
21572 var t1 = 6 / 29;
21573 var t2 = 3 * t1 * t1;
21574 var t3 = t1 * t1 * t1;
21575
21576 function labConvert(o) {
21577   if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
21578   if (o instanceof Hcl) {
21579     var h = o.h * deg2rad;
21580     return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
21581   }
21582   if (!(o instanceof Rgb)) o = rgbConvert(o);
21583   var b = rgb2xyz(o.r),
21584       a = rgb2xyz(o.g),
21585       l = rgb2xyz(o.b),
21586       x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn),
21587       y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn),
21588       z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn);
21589   return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
21590 }
21591
21592 function lab(l, a, b, opacity) {
21593   return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
21594 }
21595
21596 function Lab(l, a, b, opacity) {
21597   this.l = +l;
21598   this.a = +a;
21599   this.b = +b;
21600   this.opacity = +opacity;
21601 }
21602
21603 define(Lab, lab, extend(Color, {
21604   brighter: function(k) {
21605     return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
21606   },
21607   darker: function(k) {
21608     return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
21609   },
21610   rgb: function() {
21611     var y = (this.l + 16) / 116,
21612         x = isNaN(this.a) ? y : y + this.a / 500,
21613         z = isNaN(this.b) ? y : y - this.b / 200;
21614     y = Yn * lab2xyz(y);
21615     x = Xn * lab2xyz(x);
21616     z = Zn * lab2xyz(z);
21617     return new Rgb(
21618       xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB
21619       xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
21620       xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z),
21621       this.opacity
21622     );
21623   }
21624 }));
21625
21626 function xyz2lab(t) {
21627   return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
21628 }
21629
21630 function lab2xyz(t) {
21631   return t > t1 ? t * t * t : t2 * (t - t0);
21632 }
21633
21634 function xyz2rgb(x) {
21635   return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
21636 }
21637
21638 function rgb2xyz(x) {
21639   return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
21640 }
21641
21642 function hclConvert(o) {
21643   if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
21644   if (!(o instanceof Lab)) o = labConvert(o);
21645   var h = Math.atan2(o.b, o.a) * rad2deg;
21646   return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
21647 }
21648
21649 function hcl(h, c, l, opacity) {
21650   return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
21651 }
21652
21653 function Hcl(h, c, l, opacity) {
21654   this.h = +h;
21655   this.c = +c;
21656   this.l = +l;
21657   this.opacity = +opacity;
21658 }
21659
21660 define(Hcl, hcl, extend(Color, {
21661   brighter: function(k) {
21662     return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity);
21663   },
21664   darker: function(k) {
21665     return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity);
21666   },
21667   rgb: function() {
21668     return labConvert(this).rgb();
21669   }
21670 }));
21671
21672 var A = -0.14861;
21673 var B = +1.78277;
21674 var C = -0.29227;
21675 var D = -0.90649;
21676 var E = +1.97294;
21677 var ED = E * D;
21678 var EB = E * B;
21679 var BC_DA = B * C - D * A;
21680
21681 function cubehelixConvert(o) {
21682   if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
21683   if (!(o instanceof Rgb)) o = rgbConvert(o);
21684   var r = o.r / 255,
21685       g = o.g / 255,
21686       b = o.b / 255,
21687       l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
21688       bl = b - l,
21689       k = (E * (g - l) - C * bl) / D,
21690       s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
21691       h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
21692   return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
21693 }
21694
21695 function cubehelix(h, s, l, opacity) {
21696   return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
21697 }
21698
21699 function Cubehelix(h, s, l, opacity) {
21700   this.h = +h;
21701   this.s = +s;
21702   this.l = +l;
21703   this.opacity = +opacity;
21704 }
21705
21706 define(Cubehelix, cubehelix, extend(Color, {
21707   brighter: function(k) {
21708     k = k == null ? brighter : Math.pow(brighter, k);
21709     return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
21710   },
21711   darker: function(k) {
21712     k = k == null ? darker : Math.pow(darker, k);
21713     return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
21714   },
21715   rgb: function() {
21716     var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,
21717         l = +this.l,
21718         a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
21719         cosh = Math.cos(h),
21720         sinh = Math.sin(h);
21721     return new Rgb(
21722       255 * (l + a * (A * cosh + B * sinh)),
21723       255 * (l + a * (C * cosh + D * sinh)),
21724       255 * (l + a * (E * cosh)),
21725       this.opacity
21726     );
21727   }
21728 }));
21729
21730 function basis(t1, v0, v1, v2, v3) {
21731   var t2 = t1 * t1, t3 = t2 * t1;
21732   return ((1 - 3 * t1 + 3 * t2 - t3) * v0
21733       + (4 - 6 * t2 + 3 * t3) * v1
21734       + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
21735       + t3 * v3) / 6;
21736 }
21737
21738 var basis$1 = function(values) {
21739   var n = values.length - 1;
21740   return function(t) {
21741     var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),
21742         v1 = values[i],
21743         v2 = values[i + 1],
21744         v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,
21745         v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
21746     return basis((t - i / n) * n, v0, v1, v2, v3);
21747   };
21748 };
21749
21750 var basisClosed = function(values) {
21751   var n = values.length;
21752   return function(t) {
21753     var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),
21754         v0 = values[(i + n - 1) % n],
21755         v1 = values[i % n],
21756         v2 = values[(i + 1) % n],
21757         v3 = values[(i + 2) % n];
21758     return basis((t - i / n) * n, v0, v1, v2, v3);
21759   };
21760 };
21761
21762 var constant$3 = function(x) {
21763   return function() {
21764     return x;
21765   };
21766 };
21767
21768 function linear(a, d) {
21769   return function(t) {
21770     return a + t * d;
21771   };
21772 }
21773
21774 function exponential(a, b, y) {
21775   return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
21776     return Math.pow(a + t * b, y);
21777   };
21778 }
21779
21780 function hue(a, b) {
21781   var d = b - a;
21782   return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$3(isNaN(a) ? b : a);
21783 }
21784
21785 function gamma(y) {
21786   return (y = +y) === 1 ? nogamma : function(a, b) {
21787     return b - a ? exponential(a, b, y) : constant$3(isNaN(a) ? b : a);
21788   };
21789 }
21790
21791 function nogamma(a, b) {
21792   var d = b - a;
21793   return d ? linear(a, d) : constant$3(isNaN(a) ? b : a);
21794 }
21795
21796 var interpolateRgb = ((function rgbGamma(y) {
21797   var color$$1 = gamma(y);
21798
21799   function rgb$$1(start, end) {
21800     var r = color$$1((start = rgb(start)).r, (end = rgb(end)).r),
21801         g = color$$1(start.g, end.g),
21802         b = color$$1(start.b, end.b),
21803         opacity = nogamma(start.opacity, end.opacity);
21804     return function(t) {
21805       start.r = r(t);
21806       start.g = g(t);
21807       start.b = b(t);
21808       start.opacity = opacity(t);
21809       return start + "";
21810     };
21811   }
21812
21813   rgb$$1.gamma = rgbGamma;
21814
21815   return rgb$$1;
21816 }))(1);
21817
21818 function rgbSpline(spline) {
21819   return function(colors) {
21820     var n = colors.length,
21821         r = new Array(n),
21822         g = new Array(n),
21823         b = new Array(n),
21824         i, color$$1;
21825     for (i = 0; i < n; ++i) {
21826       color$$1 = rgb(colors[i]);
21827       r[i] = color$$1.r || 0;
21828       g[i] = color$$1.g || 0;
21829       b[i] = color$$1.b || 0;
21830     }
21831     r = spline(r);
21832     g = spline(g);
21833     b = spline(b);
21834     color$$1.opacity = 1;
21835     return function(t) {
21836       color$$1.r = r(t);
21837       color$$1.g = g(t);
21838       color$$1.b = b(t);
21839       return color$$1 + "";
21840     };
21841   };
21842 }
21843
21844 var rgbBasis = rgbSpline(basis$1);
21845 var rgbBasisClosed = rgbSpline(basisClosed);
21846
21847 var array$1 = function(a, b) {
21848   var nb = b ? b.length : 0,
21849       na = a ? Math.min(nb, a.length) : 0,
21850       x = new Array(nb),
21851       c = new Array(nb),
21852       i;
21853
21854   for (i = 0; i < na; ++i) x[i] = interpolateValue(a[i], b[i]);
21855   for (; i < nb; ++i) c[i] = b[i];
21856
21857   return function(t) {
21858     for (i = 0; i < na; ++i) c[i] = x[i](t);
21859     return c;
21860   };
21861 };
21862
21863 var date = function(a, b) {
21864   var d = new Date;
21865   return a = +a, b -= a, function(t) {
21866     return d.setTime(a + b * t), d;
21867   };
21868 };
21869
21870 var reinterpolate = function(a, b) {
21871   return a = +a, b -= a, function(t) {
21872     return a + b * t;
21873   };
21874 };
21875
21876 var object = function(a, b) {
21877   var i = {},
21878       c = {},
21879       k;
21880
21881   if (a === null || typeof a !== "object") a = {};
21882   if (b === null || typeof b !== "object") b = {};
21883
21884   for (k in b) {
21885     if (k in a) {
21886       i[k] = interpolateValue(a[k], b[k]);
21887     } else {
21888       c[k] = b[k];
21889     }
21890   }
21891
21892   return function(t) {
21893     for (k in i) c[k] = i[k](t);
21894     return c;
21895   };
21896 };
21897
21898 var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
21899 var reB = new RegExp(reA.source, "g");
21900
21901 function zero(b) {
21902   return function() {
21903     return b;
21904   };
21905 }
21906
21907 function one(b) {
21908   return function(t) {
21909     return b(t) + "";
21910   };
21911 }
21912
21913 var interpolateString = function(a, b) {
21914   var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
21915       am, // current match in a
21916       bm, // current match in b
21917       bs, // string preceding current number in b, if any
21918       i = -1, // index in s
21919       s = [], // string constants and placeholders
21920       q = []; // number interpolators
21921
21922   // Coerce inputs to strings.
21923   a = a + "", b = b + "";
21924
21925   // Interpolate pairs of numbers in a & b.
21926   while ((am = reA.exec(a))
21927       && (bm = reB.exec(b))) {
21928     if ((bs = bm.index) > bi) { // a string precedes the next number in b
21929       bs = b.slice(bi, bs);
21930       if (s[i]) s[i] += bs; // coalesce with previous string
21931       else s[++i] = bs;
21932     }
21933     if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
21934       if (s[i]) s[i] += bm; // coalesce with previous string
21935       else s[++i] = bm;
21936     } else { // interpolate non-matching numbers
21937       s[++i] = null;
21938       q.push({i: i, x: reinterpolate(am, bm)});
21939     }
21940     bi = reB.lastIndex;
21941   }
21942
21943   // Add remains of b.
21944   if (bi < b.length) {
21945     bs = b.slice(bi);
21946     if (s[i]) s[i] += bs; // coalesce with previous string
21947     else s[++i] = bs;
21948   }
21949
21950   // Special optimization for only a single match.
21951   // Otherwise, interpolate each of the numbers and rejoin the string.
21952   return s.length < 2 ? (q[0]
21953       ? one(q[0].x)
21954       : zero(b))
21955       : (b = q.length, function(t) {
21956           for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
21957           return s.join("");
21958         });
21959 };
21960
21961 var interpolateValue = function(a, b) {
21962   var t = typeof b, c;
21963   return b == null || t === "boolean" ? constant$3(b)
21964       : (t === "number" ? reinterpolate
21965       : t === "string" ? ((c = color(b)) ? (b = c, interpolateRgb) : interpolateString)
21966       : b instanceof color ? interpolateRgb
21967       : b instanceof Date ? date
21968       : Array.isArray(b) ? array$1
21969       : isNaN(b) ? object
21970       : reinterpolate)(a, b);
21971 };
21972
21973 var interpolateRound = function(a, b) {
21974   return a = +a, b -= a, function(t) {
21975     return Math.round(a + b * t);
21976   };
21977 };
21978
21979 var degrees = 180 / Math.PI;
21980
21981 var identity$2 = {
21982   translateX: 0,
21983   translateY: 0,
21984   rotate: 0,
21985   skewX: 0,
21986   scaleX: 1,
21987   scaleY: 1
21988 };
21989
21990 var decompose = function(a, b, c, d, e, f) {
21991   var scaleX, scaleY, skewX;
21992   if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
21993   if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
21994   if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
21995   if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
21996   return {
21997     translateX: e,
21998     translateY: f,
21999     rotate: Math.atan2(b, a) * degrees,
22000     skewX: Math.atan(skewX) * degrees,
22001     scaleX: scaleX,
22002     scaleY: scaleY
22003   };
22004 };
22005
22006 var cssNode;
22007 var cssRoot;
22008 var cssView;
22009 var svgNode;
22010
22011 function parseCss(value) {
22012   if (value === "none") return identity$2;
22013   if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView;
22014   cssNode.style.transform = value;
22015   value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform");
22016   cssRoot.removeChild(cssNode);
22017   value = value.slice(7, -1).split(",");
22018   return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]);
22019 }
22020
22021 function parseSvg(value) {
22022   if (value == null) return identity$2;
22023   if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
22024   svgNode.setAttribute("transform", value);
22025   if (!(value = svgNode.transform.baseVal.consolidate())) return identity$2;
22026   value = value.matrix;
22027   return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
22028 }
22029
22030 function interpolateTransform(parse, pxComma, pxParen, degParen) {
22031
22032   function pop(s) {
22033     return s.length ? s.pop() + " " : "";
22034   }
22035
22036   function translate(xa, ya, xb, yb, s, q) {
22037     if (xa !== xb || ya !== yb) {
22038       var i = s.push("translate(", null, pxComma, null, pxParen);
22039       q.push({i: i - 4, x: reinterpolate(xa, xb)}, {i: i - 2, x: reinterpolate(ya, yb)});
22040     } else if (xb || yb) {
22041       s.push("translate(" + xb + pxComma + yb + pxParen);
22042     }
22043   }
22044
22045   function rotate(a, b, s, q) {
22046     if (a !== b) {
22047       if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path
22048       q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: reinterpolate(a, b)});
22049     } else if (b) {
22050       s.push(pop(s) + "rotate(" + b + degParen);
22051     }
22052   }
22053
22054   function skewX(a, b, s, q) {
22055     if (a !== b) {
22056       q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: reinterpolate(a, b)});
22057     } else if (b) {
22058       s.push(pop(s) + "skewX(" + b + degParen);
22059     }
22060   }
22061
22062   function scale(xa, ya, xb, yb, s, q) {
22063     if (xa !== xb || ya !== yb) {
22064       var i = s.push(pop(s) + "scale(", null, ",", null, ")");
22065       q.push({i: i - 4, x: reinterpolate(xa, xb)}, {i: i - 2, x: reinterpolate(ya, yb)});
22066     } else if (xb !== 1 || yb !== 1) {
22067       s.push(pop(s) + "scale(" + xb + "," + yb + ")");
22068     }
22069   }
22070
22071   return function(a, b) {
22072     var s = [], // string constants and placeholders
22073         q = []; // number interpolators
22074     a = parse(a), b = parse(b);
22075     translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
22076     rotate(a.rotate, b.rotate, s, q);
22077     skewX(a.skewX, b.skewX, s, q);
22078     scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
22079     a = b = null; // gc
22080     return function(t) {
22081       var i = -1, n = q.length, o;
22082       while (++i < n) s[(o = q[i]).i] = o.x(t);
22083       return s.join("");
22084     };
22085   };
22086 }
22087
22088 var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
22089 var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
22090
22091 var rho = Math.SQRT2;
22092 var rho2 = 2;
22093 var rho4 = 4;
22094 var epsilon2 = 1e-12;
22095
22096 function cosh(x) {
22097   return ((x = Math.exp(x)) + 1 / x) / 2;
22098 }
22099
22100 function sinh(x) {
22101   return ((x = Math.exp(x)) - 1 / x) / 2;
22102 }
22103
22104 function tanh(x) {
22105   return ((x = Math.exp(2 * x)) - 1) / (x + 1);
22106 }
22107
22108 // p0 = [ux0, uy0, w0]
22109 // p1 = [ux1, uy1, w1]
22110 var interpolateZoom = function(p0, p1) {
22111   var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
22112       ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
22113       dx = ux1 - ux0,
22114       dy = uy1 - uy0,
22115       d2 = dx * dx + dy * dy,
22116       i,
22117       S;
22118
22119   // Special case for u0 ≅ u1.
22120   if (d2 < epsilon2) {
22121     S = Math.log(w1 / w0) / rho;
22122     i = function(t) {
22123       return [
22124         ux0 + t * dx,
22125         uy0 + t * dy,
22126         w0 * Math.exp(rho * t * S)
22127       ];
22128     };
22129   }
22130
22131   // General case.
22132   else {
22133     var d1 = Math.sqrt(d2),
22134         b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
22135         b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
22136         r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
22137         r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
22138     S = (r1 - r0) / rho;
22139     i = function(t) {
22140       var s = t * S,
22141           coshr0 = cosh(r0),
22142           u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
22143       return [
22144         ux0 + u * dx,
22145         uy0 + u * dy,
22146         w0 * coshr0 / cosh(rho * s + r0)
22147       ];
22148     };
22149   }
22150
22151   i.duration = S * 1000;
22152
22153   return i;
22154 };
22155
22156 function hsl$1(hue$$1) {
22157   return function(start, end) {
22158     var h = hue$$1((start = hsl(start)).h, (end = hsl(end)).h),
22159         s = nogamma(start.s, end.s),
22160         l = nogamma(start.l, end.l),
22161         opacity = nogamma(start.opacity, end.opacity);
22162     return function(t) {
22163       start.h = h(t);
22164       start.s = s(t);
22165       start.l = l(t);
22166       start.opacity = opacity(t);
22167       return start + "";
22168     };
22169   }
22170 }
22171
22172 var hsl$2 = hsl$1(hue);
22173 var hslLong = hsl$1(nogamma);
22174
22175 function lab$1(start, end) {
22176   var l = nogamma((start = lab(start)).l, (end = lab(end)).l),
22177       a = nogamma(start.a, end.a),
22178       b = nogamma(start.b, end.b),
22179       opacity = nogamma(start.opacity, end.opacity);
22180   return function(t) {
22181     start.l = l(t);
22182     start.a = a(t);
22183     start.b = b(t);
22184     start.opacity = opacity(t);
22185     return start + "";
22186   };
22187 }
22188
22189 function hcl$1(hue$$1) {
22190   return function(start, end) {
22191     var h = hue$$1((start = hcl(start)).h, (end = hcl(end)).h),
22192         c = nogamma(start.c, end.c),
22193         l = nogamma(start.l, end.l),
22194         opacity = nogamma(start.opacity, end.opacity);
22195     return function(t) {
22196       start.h = h(t);
22197       start.c = c(t);
22198       start.l = l(t);
22199       start.opacity = opacity(t);
22200       return start + "";
22201     };
22202   }
22203 }
22204
22205 var hcl$2 = hcl$1(hue);
22206 var hclLong = hcl$1(nogamma);
22207
22208 function cubehelix$1(hue$$1) {
22209   return (function cubehelixGamma(y) {
22210     y = +y;
22211
22212     function cubehelix$$1(start, end) {
22213       var h = hue$$1((start = cubehelix(start)).h, (end = cubehelix(end)).h),
22214           s = nogamma(start.s, end.s),
22215           l = nogamma(start.l, end.l),
22216           opacity = nogamma(start.opacity, end.opacity);
22217       return function(t) {
22218         start.h = h(t);
22219         start.s = s(t);
22220         start.l = l(Math.pow(t, y));
22221         start.opacity = opacity(t);
22222         return start + "";
22223       };
22224     }
22225
22226     cubehelix$$1.gamma = cubehelixGamma;
22227
22228     return cubehelix$$1;
22229   })(1);
22230 }
22231
22232 var cubehelix$2 = cubehelix$1(hue);
22233 var cubehelixLong = cubehelix$1(nogamma);
22234
22235 var quantize = function(interpolator, n) {
22236   var samples = new Array(n);
22237   for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));
22238   return samples;
22239 };
22240
22241 var frame = 0;
22242 var timeout = 0;
22243 var interval = 0;
22244 var pokeDelay = 1000;
22245 var taskHead;
22246 var taskTail;
22247 var clockLast = 0;
22248 var clockNow = 0;
22249 var clockSkew = 0;
22250 var clock = typeof performance === "object" && performance.now ? performance : Date;
22251 var setFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : function(f) { setTimeout(f, 17); };
22252
22253 function now() {
22254   return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
22255 }
22256
22257 function clearNow() {
22258   clockNow = 0;
22259 }
22260
22261 function Timer() {
22262   this._call =
22263   this._time =
22264   this._next = null;
22265 }
22266
22267 Timer.prototype = timer.prototype = {
22268   constructor: Timer,
22269   restart: function(callback, delay, time) {
22270     if (typeof callback !== "function") throw new TypeError("callback is not a function");
22271     time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
22272     if (!this._next && taskTail !== this) {
22273       if (taskTail) taskTail._next = this;
22274       else taskHead = this;
22275       taskTail = this;
22276     }
22277     this._call = callback;
22278     this._time = time;
22279     sleep();
22280   },
22281   stop: function() {
22282     if (this._call) {
22283       this._call = null;
22284       this._time = Infinity;
22285       sleep();
22286     }
22287   }
22288 };
22289
22290 function timer(callback, delay, time) {
22291   var t = new Timer;
22292   t.restart(callback, delay, time);
22293   return t;
22294 }
22295
22296 function timerFlush() {
22297   now(); // Get the current time, if not already set.
22298   ++frame; // Pretend we’ve set an alarm, if we haven’t already.
22299   var t = taskHead, e;
22300   while (t) {
22301     if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
22302     t = t._next;
22303   }
22304   --frame;
22305 }
22306
22307 function wake() {
22308   clockNow = (clockLast = clock.now()) + clockSkew;
22309   frame = timeout = 0;
22310   try {
22311     timerFlush();
22312   } finally {
22313     frame = 0;
22314     nap();
22315     clockNow = 0;
22316   }
22317 }
22318
22319 function poke() {
22320   var now = clock.now(), delay = now - clockLast;
22321   if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
22322 }
22323
22324 function nap() {
22325   var t0, t1 = taskHead, t2, time = Infinity;
22326   while (t1) {
22327     if (t1._call) {
22328       if (time > t1._time) time = t1._time;
22329       t0 = t1, t1 = t1._next;
22330     } else {
22331       t2 = t1._next, t1._next = null;
22332       t1 = t0 ? t0._next = t2 : taskHead = t2;
22333     }
22334   }
22335   taskTail = t0;
22336   sleep(time);
22337 }
22338
22339 function sleep(time) {
22340   if (frame) return; // Soonest alarm already set, or will be.
22341   if (timeout) timeout = clearTimeout(timeout);
22342   var delay = time - clockNow;
22343   if (delay > 24) {
22344     if (time < Infinity) timeout = setTimeout(wake, delay);
22345     if (interval) interval = clearInterval(interval);
22346   } else {
22347     if (!interval) clockLast = clockNow, interval = setInterval(poke, pokeDelay);
22348     frame = 1, setFrame(wake);
22349   }
22350 }
22351
22352 var timeout$1 = function(callback, delay, time) {
22353   var t = new Timer;
22354   delay = delay == null ? 0 : +delay;
22355   t.restart(function(elapsed) {
22356     t.stop();
22357     callback(elapsed + delay);
22358   }, delay, time);
22359   return t;
22360 };
22361
22362 var interval$1 = function(callback, delay, time) {
22363   var t = new Timer, total = delay;
22364   if (delay == null) return t.restart(callback, delay, time), t;
22365   delay = +delay, time = time == null ? now() : +time;
22366   t.restart(function tick(elapsed) {
22367     elapsed += total;
22368     t.restart(tick, total += delay, time);
22369     callback(elapsed);
22370   }, delay, time);
22371   return t;
22372 };
22373
22374 var emptyOn = dispatch("start", "end", "interrupt");
22375 var emptyTween = [];
22376
22377 var CREATED = 0;
22378 var SCHEDULED = 1;
22379 var STARTING = 2;
22380 var STARTED = 3;
22381 var RUNNING = 4;
22382 var ENDING = 5;
22383 var ENDED = 6;
22384
22385 var schedule = function(node, name, id, index, group, timing) {
22386   var schedules = node.__transition;
22387   if (!schedules) node.__transition = {};
22388   else if (id in schedules) return;
22389   create(node, id, {
22390     name: name,
22391     index: index, // For context during callback.
22392     group: group, // For context during callback.
22393     on: emptyOn,
22394     tween: emptyTween,
22395     time: timing.time,
22396     delay: timing.delay,
22397     duration: timing.duration,
22398     ease: timing.ease,
22399     timer: null,
22400     state: CREATED
22401   });
22402 };
22403
22404 function init(node, id) {
22405   var schedule = node.__transition;
22406   if (!schedule || !(schedule = schedule[id]) || schedule.state > CREATED) throw new Error("too late");
22407   return schedule;
22408 }
22409
22410 function set$1(node, id) {
22411   var schedule = node.__transition;
22412   if (!schedule || !(schedule = schedule[id]) || schedule.state > STARTING) throw new Error("too late");
22413   return schedule;
22414 }
22415
22416 function get$1(node, id) {
22417   var schedule = node.__transition;
22418   if (!schedule || !(schedule = schedule[id])) throw new Error("too late");
22419   return schedule;
22420 }
22421
22422 function create(node, id, self) {
22423   var schedules = node.__transition,
22424       tween;
22425
22426   // Initialize the self timer when the transition is created.
22427   // Note the actual delay is not known until the first callback!
22428   schedules[id] = self;
22429   self.timer = timer(schedule, 0, self.time);
22430
22431   function schedule(elapsed) {
22432     self.state = SCHEDULED;
22433     self.timer.restart(start, self.delay, self.time);
22434
22435     // If the elapsed delay is less than our first sleep, start immediately.
22436     if (self.delay <= elapsed) start(elapsed - self.delay);
22437   }
22438
22439   function start(elapsed) {
22440     var i, j, n, o;
22441
22442     // If the state is not SCHEDULED, then we previously errored on start.
22443     if (self.state !== SCHEDULED) return stop();
22444
22445     for (i in schedules) {
22446       o = schedules[i];
22447       if (o.name !== self.name) continue;
22448
22449       // While this element already has a starting transition during this frame,
22450       // defer starting an interrupting transition until that transition has a
22451       // chance to tick (and possibly end); see d3/d3-transition#54!
22452       if (o.state === STARTED) return timeout$1(start);
22453
22454       // Interrupt the active transition, if any.
22455       // Dispatch the interrupt event.
22456       if (o.state === RUNNING) {
22457         o.state = ENDED;
22458         o.timer.stop();
22459         o.on.call("interrupt", node, node.__data__, o.index, o.group);
22460         delete schedules[i];
22461       }
22462
22463       // Cancel any pre-empted transitions. No interrupt event is dispatched
22464       // because the cancelled transitions never started. Note that this also
22465       // removes this transition from the pending list!
22466       else if (+i < id) {
22467         o.state = ENDED;
22468         o.timer.stop();
22469         delete schedules[i];
22470       }
22471     }
22472
22473     // Defer the first tick to end of the current frame; see d3/d3#1576.
22474     // Note the transition may be canceled after start and before the first tick!
22475     // Note this must be scheduled before the start event; see d3/d3-transition#16!
22476     // Assuming this is successful, subsequent callbacks go straight to tick.
22477     timeout$1(function() {
22478       if (self.state === STARTED) {
22479         self.state = RUNNING;
22480         self.timer.restart(tick, self.delay, self.time);
22481         tick(elapsed);
22482       }
22483     });
22484
22485     // Dispatch the start event.
22486     // Note this must be done before the tween are initialized.
22487     self.state = STARTING;
22488     self.on.call("start", node, node.__data__, self.index, self.group);
22489     if (self.state !== STARTING) return; // interrupted
22490     self.state = STARTED;
22491
22492     // Initialize the tween, deleting null tween.
22493     tween = new Array(n = self.tween.length);
22494     for (i = 0, j = -1; i < n; ++i) {
22495       if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
22496         tween[++j] = o;
22497       }
22498     }
22499     tween.length = j + 1;
22500   }
22501
22502   function tick(elapsed) {
22503     var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
22504         i = -1,
22505         n = tween.length;
22506
22507     while (++i < n) {
22508       tween[i].call(null, t);
22509     }
22510
22511     // Dispatch the end event.
22512     if (self.state === ENDING) {
22513       self.on.call("end", node, node.__data__, self.index, self.group);
22514       stop();
22515     }
22516   }
22517
22518   function stop() {
22519     self.state = ENDED;
22520     self.timer.stop();
22521     delete schedules[id];
22522     for (var i in schedules) return; // eslint-disable-line no-unused-vars
22523     delete node.__transition;
22524   }
22525 }
22526
22527 var interrupt = function(node, name) {
22528   var schedules = node.__transition,
22529       schedule,
22530       active,
22531       empty = true,
22532       i;
22533
22534   if (!schedules) return;
22535
22536   name = name == null ? null : name + "";
22537
22538   for (i in schedules) {
22539     if ((schedule = schedules[i]).name !== name) { empty = false; continue; }
22540     active = schedule.state > STARTING && schedule.state < ENDING;
22541     schedule.state = ENDED;
22542     schedule.timer.stop();
22543     if (active) schedule.on.call("interrupt", node, node.__data__, schedule.index, schedule.group);
22544     delete schedules[i];
22545   }
22546
22547   if (empty) delete node.__transition;
22548 };
22549
22550 var selection_interrupt = function(name) {
22551   return this.each(function() {
22552     interrupt(this, name);
22553   });
22554 };
22555
22556 function tweenRemove(id, name) {
22557   var tween0, tween1;
22558   return function() {
22559     var schedule = set$1(this, id),
22560         tween = schedule.tween;
22561
22562     // If this node shared tween with the previous node,
22563     // just assign the updated shared tween and we’re done!
22564     // Otherwise, copy-on-write.
22565     if (tween !== tween0) {
22566       tween1 = tween0 = tween;
22567       for (var i = 0, n = tween1.length; i < n; ++i) {
22568         if (tween1[i].name === name) {
22569           tween1 = tween1.slice();
22570           tween1.splice(i, 1);
22571           break;
22572         }
22573       }
22574     }
22575
22576     schedule.tween = tween1;
22577   };
22578 }
22579
22580 function tweenFunction(id, name, value) {
22581   var tween0, tween1;
22582   if (typeof value !== "function") throw new Error;
22583   return function() {
22584     var schedule = set$1(this, id),
22585         tween = schedule.tween;
22586
22587     // If this node shared tween with the previous node,
22588     // just assign the updated shared tween and we’re done!
22589     // Otherwise, copy-on-write.
22590     if (tween !== tween0) {
22591       tween1 = (tween0 = tween).slice();
22592       for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) {
22593         if (tween1[i].name === name) {
22594           tween1[i] = t;
22595           break;
22596         }
22597       }
22598       if (i === n) tween1.push(t);
22599     }
22600
22601     schedule.tween = tween1;
22602   };
22603 }
22604
22605 var transition_tween = function(name, value) {
22606   var id = this._id;
22607
22608   name += "";
22609
22610   if (arguments.length < 2) {
22611     var tween = get$1(this.node(), id).tween;
22612     for (var i = 0, n = tween.length, t; i < n; ++i) {
22613       if ((t = tween[i]).name === name) {
22614         return t.value;
22615       }
22616     }
22617     return null;
22618   }
22619
22620   return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
22621 };
22622
22623 function tweenValue(transition, name, value) {
22624   var id = transition._id;
22625
22626   transition.each(function() {
22627     var schedule = set$1(this, id);
22628     (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
22629   });
22630
22631   return function(node) {
22632     return get$1(node, id).value[name];
22633   };
22634 }
22635
22636 var interpolate$$1 = function(a, b) {
22637   var c;
22638   return (typeof b === "number" ? reinterpolate
22639       : b instanceof color ? interpolateRgb
22640       : (c = color(b)) ? (b = c, interpolateRgb)
22641       : interpolateString)(a, b);
22642 };
22643
22644 function attrRemove$1(name) {
22645   return function() {
22646     this.removeAttribute(name);
22647   };
22648 }
22649
22650 function attrRemoveNS$1(fullname) {
22651   return function() {
22652     this.removeAttributeNS(fullname.space, fullname.local);
22653   };
22654 }
22655
22656 function attrConstant$1(name, interpolate$$1, value1) {
22657   var value00,
22658       interpolate0;
22659   return function() {
22660     var value0 = this.getAttribute(name);
22661     return value0 === value1 ? null
22662         : value0 === value00 ? interpolate0
22663         : interpolate0 = interpolate$$1(value00 = value0, value1);
22664   };
22665 }
22666
22667 function attrConstantNS$1(fullname, interpolate$$1, value1) {
22668   var value00,
22669       interpolate0;
22670   return function() {
22671     var value0 = this.getAttributeNS(fullname.space, fullname.local);
22672     return value0 === value1 ? null
22673         : value0 === value00 ? interpolate0
22674         : interpolate0 = interpolate$$1(value00 = value0, value1);
22675   };
22676 }
22677
22678 function attrFunction$1(name, interpolate$$1, value) {
22679   var value00,
22680       value10,
22681       interpolate0;
22682   return function() {
22683     var value0, value1 = value(this);
22684     if (value1 == null) return void this.removeAttribute(name);
22685     value0 = this.getAttribute(name);
22686     return value0 === value1 ? null
22687         : value0 === value00 && value1 === value10 ? interpolate0
22688         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22689   };
22690 }
22691
22692 function attrFunctionNS$1(fullname, interpolate$$1, value) {
22693   var value00,
22694       value10,
22695       interpolate0;
22696   return function() {
22697     var value0, value1 = value(this);
22698     if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
22699     value0 = this.getAttributeNS(fullname.space, fullname.local);
22700     return value0 === value1 ? null
22701         : value0 === value00 && value1 === value10 ? interpolate0
22702         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22703   };
22704 }
22705
22706 var transition_attr = function(name, value) {
22707   var fullname = namespace(name), i = fullname === "transform" ? interpolateTransformSvg : interpolate$$1;
22708   return this.attrTween(name, typeof value === "function"
22709       ? (fullname.local ? attrFunctionNS$1 : attrFunction$1)(fullname, i, tweenValue(this, "attr." + name, value))
22710       : value == null ? (fullname.local ? attrRemoveNS$1 : attrRemove$1)(fullname)
22711       : (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value + ""));
22712 };
22713
22714 function attrTweenNS(fullname, value) {
22715   function tween() {
22716     var node = this, i = value.apply(node, arguments);
22717     return i && function(t) {
22718       node.setAttributeNS(fullname.space, fullname.local, i(t));
22719     };
22720   }
22721   tween._value = value;
22722   return tween;
22723 }
22724
22725 function attrTween(name, value) {
22726   function tween() {
22727     var node = this, i = value.apply(node, arguments);
22728     return i && function(t) {
22729       node.setAttribute(name, i(t));
22730     };
22731   }
22732   tween._value = value;
22733   return tween;
22734 }
22735
22736 var transition_attrTween = function(name, value) {
22737   var key = "attr." + name;
22738   if (arguments.length < 2) return (key = this.tween(key)) && key._value;
22739   if (value == null) return this.tween(key, null);
22740   if (typeof value !== "function") throw new Error;
22741   var fullname = namespace(name);
22742   return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
22743 };
22744
22745 function delayFunction(id, value) {
22746   return function() {
22747     init(this, id).delay = +value.apply(this, arguments);
22748   };
22749 }
22750
22751 function delayConstant(id, value) {
22752   return value = +value, function() {
22753     init(this, id).delay = value;
22754   };
22755 }
22756
22757 var transition_delay = function(value) {
22758   var id = this._id;
22759
22760   return arguments.length
22761       ? this.each((typeof value === "function"
22762           ? delayFunction
22763           : delayConstant)(id, value))
22764       : get$1(this.node(), id).delay;
22765 };
22766
22767 function durationFunction(id, value) {
22768   return function() {
22769     set$1(this, id).duration = +value.apply(this, arguments);
22770   };
22771 }
22772
22773 function durationConstant(id, value) {
22774   return value = +value, function() {
22775     set$1(this, id).duration = value;
22776   };
22777 }
22778
22779 var transition_duration = function(value) {
22780   var id = this._id;
22781
22782   return arguments.length
22783       ? this.each((typeof value === "function"
22784           ? durationFunction
22785           : durationConstant)(id, value))
22786       : get$1(this.node(), id).duration;
22787 };
22788
22789 function easeConstant(id, value) {
22790   if (typeof value !== "function") throw new Error;
22791   return function() {
22792     set$1(this, id).ease = value;
22793   };
22794 }
22795
22796 var transition_ease = function(value) {
22797   var id = this._id;
22798
22799   return arguments.length
22800       ? this.each(easeConstant(id, value))
22801       : get$1(this.node(), id).ease;
22802 };
22803
22804 var transition_filter = function(match) {
22805   if (typeof match !== "function") match = matcher$1(match);
22806
22807   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
22808     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
22809       if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
22810         subgroup.push(node);
22811       }
22812     }
22813   }
22814
22815   return new Transition(subgroups, this._parents, this._name, this._id);
22816 };
22817
22818 var transition_merge = function(transition) {
22819   if (transition._id !== this._id) throw new Error;
22820
22821   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) {
22822     for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
22823       if (node = group0[i] || group1[i]) {
22824         merge[i] = node;
22825       }
22826     }
22827   }
22828
22829   for (; j < m0; ++j) {
22830     merges[j] = groups0[j];
22831   }
22832
22833   return new Transition(merges, this._parents, this._name, this._id);
22834 };
22835
22836 function start(name) {
22837   return (name + "").trim().split(/^|\s+/).every(function(t) {
22838     var i = t.indexOf(".");
22839     if (i >= 0) t = t.slice(0, i);
22840     return !t || t === "start";
22841   });
22842 }
22843
22844 function onFunction(id, name, listener) {
22845   var on0, on1, sit = start(name) ? init : set$1;
22846   return function() {
22847     var schedule = sit(this, id),
22848         on = schedule.on;
22849
22850     // If this node shared a dispatch with the previous node,
22851     // just assign the updated shared dispatch and we’re done!
22852     // Otherwise, copy-on-write.
22853     if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
22854
22855     schedule.on = on1;
22856   };
22857 }
22858
22859 var transition_on = function(name, listener) {
22860   var id = this._id;
22861
22862   return arguments.length < 2
22863       ? get$1(this.node(), id).on.on(name)
22864       : this.each(onFunction(id, name, listener));
22865 };
22866
22867 function removeFunction(id) {
22868   return function() {
22869     var parent = this.parentNode;
22870     for (var i in this.__transition) if (+i !== id) return;
22871     if (parent) parent.removeChild(this);
22872   };
22873 }
22874
22875 var transition_remove = function() {
22876   return this.on("end.remove", removeFunction(this._id));
22877 };
22878
22879 var transition_select = function(select$$1) {
22880   var name = this._name,
22881       id = this._id;
22882
22883   if (typeof select$$1 !== "function") select$$1 = selector(select$$1);
22884
22885   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
22886     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
22887       if ((node = group[i]) && (subnode = select$$1.call(node, node.__data__, i, group))) {
22888         if ("__data__" in node) subnode.__data__ = node.__data__;
22889         subgroup[i] = subnode;
22890         schedule(subgroup[i], name, id, i, subgroup, get$1(node, id));
22891       }
22892     }
22893   }
22894
22895   return new Transition(subgroups, this._parents, name, id);
22896 };
22897
22898 var transition_selectAll = function(select$$1) {
22899   var name = this._name,
22900       id = this._id;
22901
22902   if (typeof select$$1 !== "function") select$$1 = selectorAll(select$$1);
22903
22904   for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
22905     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
22906       if (node = group[i]) {
22907         for (var children = select$$1.call(node, node.__data__, i, group), child, inherit = get$1(node, id), k = 0, l = children.length; k < l; ++k) {
22908           if (child = children[k]) {
22909             schedule(child, name, id, k, children, inherit);
22910           }
22911         }
22912         subgroups.push(children);
22913         parents.push(node);
22914       }
22915     }
22916   }
22917
22918   return new Transition(subgroups, parents, name, id);
22919 };
22920
22921 var Selection$1 = selection.prototype.constructor;
22922
22923 var transition_selection = function() {
22924   return new Selection$1(this._groups, this._parents);
22925 };
22926
22927 function styleRemove$1(name, interpolate$$2) {
22928   var value00,
22929       value10,
22930       interpolate0;
22931   return function() {
22932     var style = window$1(this).getComputedStyle(this, null),
22933         value0 = style.getPropertyValue(name),
22934         value1 = (this.style.removeProperty(name), style.getPropertyValue(name));
22935     return value0 === value1 ? null
22936         : value0 === value00 && value1 === value10 ? interpolate0
22937         : interpolate0 = interpolate$$2(value00 = value0, value10 = value1);
22938   };
22939 }
22940
22941 function styleRemoveEnd(name) {
22942   return function() {
22943     this.style.removeProperty(name);
22944   };
22945 }
22946
22947 function styleConstant$1(name, interpolate$$2, value1) {
22948   var value00,
22949       interpolate0;
22950   return function() {
22951     var value0 = window$1(this).getComputedStyle(this, null).getPropertyValue(name);
22952     return value0 === value1 ? null
22953         : value0 === value00 ? interpolate0
22954         : interpolate0 = interpolate$$2(value00 = value0, value1);
22955   };
22956 }
22957
22958 function styleFunction$1(name, interpolate$$2, value) {
22959   var value00,
22960       value10,
22961       interpolate0;
22962   return function() {
22963     var style = window$1(this).getComputedStyle(this, null),
22964         value0 = style.getPropertyValue(name),
22965         value1 = value(this);
22966     if (value1 == null) value1 = (this.style.removeProperty(name), style.getPropertyValue(name));
22967     return value0 === value1 ? null
22968         : value0 === value00 && value1 === value10 ? interpolate0
22969         : interpolate0 = interpolate$$2(value00 = value0, value10 = value1);
22970   };
22971 }
22972
22973 var transition_style = function(name, value, priority) {
22974   var i = (name += "") === "transform" ? interpolateTransformCss : interpolate$$1;
22975   return value == null ? this
22976           .styleTween(name, styleRemove$1(name, i))
22977           .on("end.style." + name, styleRemoveEnd(name))
22978       : this.styleTween(name, typeof value === "function"
22979           ? styleFunction$1(name, i, tweenValue(this, "style." + name, value))
22980           : styleConstant$1(name, i, value + ""), priority);
22981 };
22982
22983 function styleTween(name, value, priority) {
22984   function tween() {
22985     var node = this, i = value.apply(node, arguments);
22986     return i && function(t) {
22987       node.style.setProperty(name, i(t), priority);
22988     };
22989   }
22990   tween._value = value;
22991   return tween;
22992 }
22993
22994 var transition_styleTween = function(name, value, priority) {
22995   var key = "style." + (name += "");
22996   if (arguments.length < 2) return (key = this.tween(key)) && key._value;
22997   if (value == null) return this.tween(key, null);
22998   if (typeof value !== "function") throw new Error;
22999   return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
23000 };
23001
23002 function textConstant$1(value) {
23003   return function() {
23004     this.textContent = value;
23005   };
23006 }
23007
23008 function textFunction$1(value) {
23009   return function() {
23010     var value1 = value(this);
23011     this.textContent = value1 == null ? "" : value1;
23012   };
23013 }
23014
23015 var transition_text = function(value) {
23016   return this.tween("text", typeof value === "function"
23017       ? textFunction$1(tweenValue(this, "text", value))
23018       : textConstant$1(value == null ? "" : value + ""));
23019 };
23020
23021 var transition_transition = function() {
23022   var name = this._name,
23023       id0 = this._id,
23024       id1 = newId();
23025
23026   for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
23027     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
23028       if (node = group[i]) {
23029         var inherit = get$1(node, id0);
23030         schedule(node, name, id1, i, group, {
23031           time: inherit.time + inherit.delay + inherit.duration,
23032           delay: 0,
23033           duration: inherit.duration,
23034           ease: inherit.ease
23035         });
23036       }
23037     }
23038   }
23039
23040   return new Transition(groups, this._parents, name, id1);
23041 };
23042
23043 var id = 0;
23044
23045 function Transition(groups, parents, name, id) {
23046   this._groups = groups;
23047   this._parents = parents;
23048   this._name = name;
23049   this._id = id;
23050 }
23051
23052 function transition(name) {
23053   return selection().transition(name);
23054 }
23055
23056 function newId() {
23057   return ++id;
23058 }
23059
23060 var selection_prototype = selection.prototype;
23061
23062 Transition.prototype = transition.prototype = {
23063   constructor: Transition,
23064   select: transition_select,
23065   selectAll: transition_selectAll,
23066   filter: transition_filter,
23067   merge: transition_merge,
23068   selection: transition_selection,
23069   transition: transition_transition,
23070   call: selection_prototype.call,
23071   nodes: selection_prototype.nodes,
23072   node: selection_prototype.node,
23073   size: selection_prototype.size,
23074   empty: selection_prototype.empty,
23075   each: selection_prototype.each,
23076   on: transition_on,
23077   attr: transition_attr,
23078   attrTween: transition_attrTween,
23079   style: transition_style,
23080   styleTween: transition_styleTween,
23081   text: transition_text,
23082   remove: transition_remove,
23083   tween: transition_tween,
23084   delay: transition_delay,
23085   duration: transition_duration,
23086   ease: transition_ease
23087 };
23088
23089 function linear$1(t) {
23090   return +t;
23091 }
23092
23093 function quadIn(t) {
23094   return t * t;
23095 }
23096
23097 function quadOut(t) {
23098   return t * (2 - t);
23099 }
23100
23101 function quadInOut(t) {
23102   return ((t *= 2) <= 1 ? t * t : --t * (2 - t) + 1) / 2;
23103 }
23104
23105 function cubicIn(t) {
23106   return t * t * t;
23107 }
23108
23109 function cubicOut(t) {
23110   return --t * t * t + 1;
23111 }
23112
23113 function cubicInOut(t) {
23114   return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
23115 }
23116
23117 var exponent = 3;
23118
23119 var polyIn = (function custom(e) {
23120   e = +e;
23121
23122   function polyIn(t) {
23123     return Math.pow(t, e);
23124   }
23125
23126   polyIn.exponent = custom;
23127
23128   return polyIn;
23129 })(exponent);
23130
23131 var polyOut = (function custom(e) {
23132   e = +e;
23133
23134   function polyOut(t) {
23135     return 1 - Math.pow(1 - t, e);
23136   }
23137
23138   polyOut.exponent = custom;
23139
23140   return polyOut;
23141 })(exponent);
23142
23143 var polyInOut = (function custom(e) {
23144   e = +e;
23145
23146   function polyInOut(t) {
23147     return ((t *= 2) <= 1 ? Math.pow(t, e) : 2 - Math.pow(2 - t, e)) / 2;
23148   }
23149
23150   polyInOut.exponent = custom;
23151
23152   return polyInOut;
23153 })(exponent);
23154
23155 var pi = Math.PI;
23156 var halfPi = pi / 2;
23157
23158 function sinIn(t) {
23159   return 1 - Math.cos(t * halfPi);
23160 }
23161
23162 function sinOut(t) {
23163   return Math.sin(t * halfPi);
23164 }
23165
23166 function sinInOut(t) {
23167   return (1 - Math.cos(pi * t)) / 2;
23168 }
23169
23170 function expIn(t) {
23171   return Math.pow(2, 10 * t - 10);
23172 }
23173
23174 function expOut(t) {
23175   return 1 - Math.pow(2, -10 * t);
23176 }
23177
23178 function expInOut(t) {
23179   return ((t *= 2) <= 1 ? Math.pow(2, 10 * t - 10) : 2 - Math.pow(2, 10 - 10 * t)) / 2;
23180 }
23181
23182 function circleIn(t) {
23183   return 1 - Math.sqrt(1 - t * t);
23184 }
23185
23186 function circleOut(t) {
23187   return Math.sqrt(1 - --t * t);
23188 }
23189
23190 function circleInOut(t) {
23191   return ((t *= 2) <= 1 ? 1 - Math.sqrt(1 - t * t) : Math.sqrt(1 - (t -= 2) * t) + 1) / 2;
23192 }
23193
23194 var b1 = 4 / 11;
23195 var b2 = 6 / 11;
23196 var b3 = 8 / 11;
23197 var b4 = 3 / 4;
23198 var b5 = 9 / 11;
23199 var b6 = 10 / 11;
23200 var b7 = 15 / 16;
23201 var b8 = 21 / 22;
23202 var b9 = 63 / 64;
23203 var b0 = 1 / b1 / b1;
23204
23205 function bounceIn(t) {
23206   return 1 - bounceOut(1 - t);
23207 }
23208
23209 function bounceOut(t) {
23210   return (t = +t) < b1 ? b0 * t * t : t < b3 ? b0 * (t -= b2) * t + b4 : t < b6 ? b0 * (t -= b5) * t + b7 : b0 * (t -= b8) * t + b9;
23211 }
23212
23213 function bounceInOut(t) {
23214   return ((t *= 2) <= 1 ? 1 - bounceOut(1 - t) : bounceOut(t - 1) + 1) / 2;
23215 }
23216
23217 var overshoot = 1.70158;
23218
23219 var backIn = (function custom(s) {
23220   s = +s;
23221
23222   function backIn(t) {
23223     return t * t * ((s + 1) * t - s);
23224   }
23225
23226   backIn.overshoot = custom;
23227
23228   return backIn;
23229 })(overshoot);
23230
23231 var backOut = (function custom(s) {
23232   s = +s;
23233
23234   function backOut(t) {
23235     return --t * t * ((s + 1) * t + s) + 1;
23236   }
23237
23238   backOut.overshoot = custom;
23239
23240   return backOut;
23241 })(overshoot);
23242
23243 var backInOut = (function custom(s) {
23244   s = +s;
23245
23246   function backInOut(t) {
23247     return ((t *= 2) < 1 ? t * t * ((s + 1) * t - s) : (t -= 2) * t * ((s + 1) * t + s) + 2) / 2;
23248   }
23249
23250   backInOut.overshoot = custom;
23251
23252   return backInOut;
23253 })(overshoot);
23254
23255 var tau = 2 * Math.PI;
23256 var amplitude = 1;
23257 var period = 0.3;
23258
23259 var elasticIn = (function custom(a, p) {
23260   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23261
23262   function elasticIn(t) {
23263     return a * Math.pow(2, 10 * --t) * Math.sin((s - t) / p);
23264   }
23265
23266   elasticIn.amplitude = function(a) { return custom(a, p * tau); };
23267   elasticIn.period = function(p) { return custom(a, p); };
23268
23269   return elasticIn;
23270 })(amplitude, period);
23271
23272 var elasticOut = (function custom(a, p) {
23273   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23274
23275   function elasticOut(t) {
23276     return 1 - a * Math.pow(2, -10 * (t = +t)) * Math.sin((t + s) / p);
23277   }
23278
23279   elasticOut.amplitude = function(a) { return custom(a, p * tau); };
23280   elasticOut.period = function(p) { return custom(a, p); };
23281
23282   return elasticOut;
23283 })(amplitude, period);
23284
23285 var elasticInOut = (function custom(a, p) {
23286   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23287
23288   function elasticInOut(t) {
23289     return ((t = t * 2 - 1) < 0
23290         ? a * Math.pow(2, 10 * t) * Math.sin((s - t) / p)
23291         : 2 - a * Math.pow(2, -10 * t) * Math.sin((s + t) / p)) / 2;
23292   }
23293
23294   elasticInOut.amplitude = function(a) { return custom(a, p * tau); };
23295   elasticInOut.period = function(p) { return custom(a, p); };
23296
23297   return elasticInOut;
23298 })(amplitude, period);
23299
23300 var defaultTiming = {
23301   time: null, // Set on use.
23302   delay: 0,
23303   duration: 250,
23304   ease: cubicInOut
23305 };
23306
23307 function inherit(node, id) {
23308   var timing;
23309   while (!(timing = node.__transition) || !(timing = timing[id])) {
23310     if (!(node = node.parentNode)) {
23311       return defaultTiming.time = now(), defaultTiming;
23312     }
23313   }
23314   return timing;
23315 }
23316
23317 var selection_transition = function(name) {
23318   var id,
23319       timing;
23320
23321   if (name instanceof Transition) {
23322     id = name._id, name = name._name;
23323   } else {
23324     id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
23325   }
23326
23327   for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
23328     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
23329       if (node = group[i]) {
23330         schedule(node, name, id, i, group, timing || inherit(node, id));
23331       }
23332     }
23333   }
23334
23335   return new Transition(groups, this._parents, name, id);
23336 };
23337
23338 selection.prototype.interrupt = selection_interrupt;
23339 selection.prototype.transition = selection_transition;
23340
23341 var root$1 = [null];
23342
23343 var active = function(node, name) {
23344   var schedules = node.__transition,
23345       schedule,
23346       i;
23347
23348   if (schedules) {
23349     name = name == null ? null : name + "";
23350     for (i in schedules) {
23351       if ((schedule = schedules[i]).state > SCHEDULED && schedule.name === name) {
23352         return new Transition([[node]], root$1, name, +i);
23353       }
23354     }
23355   }
23356
23357   return null;
23358 };
23359
23360 var constant$4 = function(x) {
23361   return function() {
23362     return x;
23363   };
23364 };
23365
23366 var BrushEvent = function(target, type, selection) {
23367   this.target = target;
23368   this.type = type;
23369   this.selection = selection;
23370 };
23371
23372 function nopropagation$1() {
23373   event.stopImmediatePropagation();
23374 }
23375
23376 var noevent$1 = function() {
23377   event.preventDefault();
23378   event.stopImmediatePropagation();
23379 };
23380
23381 var MODE_DRAG = {name: "drag"};
23382 var MODE_SPACE = {name: "space"};
23383 var MODE_HANDLE = {name: "handle"};
23384 var MODE_CENTER = {name: "center"};
23385
23386 var X = {
23387   name: "x",
23388   handles: ["e", "w"].map(type$2),
23389   input: function(x, e) { return x && [[x[0], e[0][1]], [x[1], e[1][1]]]; },
23390   output: function(xy) { return xy && [xy[0][0], xy[1][0]]; }
23391 };
23392
23393 var Y = {
23394   name: "y",
23395   handles: ["n", "s"].map(type$2),
23396   input: function(y, e) { return y && [[e[0][0], y[0]], [e[1][0], y[1]]]; },
23397   output: function(xy) { return xy && [xy[0][1], xy[1][1]]; }
23398 };
23399
23400 var XY = {
23401   name: "xy",
23402   handles: ["n", "e", "s", "w", "nw", "ne", "se", "sw"].map(type$2),
23403   input: function(xy) { return xy; },
23404   output: function(xy) { return xy; }
23405 };
23406
23407 var cursors = {
23408   overlay: "crosshair",
23409   selection: "move",
23410   n: "ns-resize",
23411   e: "ew-resize",
23412   s: "ns-resize",
23413   w: "ew-resize",
23414   nw: "nwse-resize",
23415   ne: "nesw-resize",
23416   se: "nwse-resize",
23417   sw: "nesw-resize"
23418 };
23419
23420 var flipX = {
23421   e: "w",
23422   w: "e",
23423   nw: "ne",
23424   ne: "nw",
23425   se: "sw",
23426   sw: "se"
23427 };
23428
23429 var flipY = {
23430   n: "s",
23431   s: "n",
23432   nw: "sw",
23433   ne: "se",
23434   se: "ne",
23435   sw: "nw"
23436 };
23437
23438 var signsX = {
23439   overlay: +1,
23440   selection: +1,
23441   n: null,
23442   e: +1,
23443   s: null,
23444   w: -1,
23445   nw: -1,
23446   ne: +1,
23447   se: +1,
23448   sw: -1
23449 };
23450
23451 var signsY = {
23452   overlay: +1,
23453   selection: +1,
23454   n: -1,
23455   e: null,
23456   s: +1,
23457   w: null,
23458   nw: -1,
23459   ne: -1,
23460   se: +1,
23461   sw: +1
23462 };
23463
23464 function type$2(t) {
23465   return {type: t};
23466 }
23467
23468 // Ignore right-click, since that should open the context menu.
23469 function defaultFilter() {
23470   return !event.button;
23471 }
23472
23473 function defaultExtent() {
23474   var svg = this.ownerSVGElement || this;
23475   return [[0, 0], [svg.width.baseVal.value, svg.height.baseVal.value]];
23476 }
23477
23478 // Like d3.local, but with the name “__brush” rather than auto-generated.
23479 function local$$1(node) {
23480   while (!node.__brush) if (!(node = node.parentNode)) return;
23481   return node.__brush;
23482 }
23483
23484 function empty(extent) {
23485   return extent[0][0] === extent[1][0]
23486       || extent[0][1] === extent[1][1];
23487 }
23488
23489 function brushSelection(node) {
23490   var state = node.__brush;
23491   return state ? state.dim.output(state.selection) : null;
23492 }
23493
23494 function brushX() {
23495   return brush$1(X);
23496 }
23497
23498 function brushY() {
23499   return brush$1(Y);
23500 }
23501
23502 var brush = function() {
23503   return brush$1(XY);
23504 };
23505
23506 function brush$1(dim) {
23507   var extent = defaultExtent,
23508       filter = defaultFilter,
23509       listeners = dispatch(brush, "start", "brush", "end"),
23510       handleSize = 6,
23511       touchending;
23512
23513   function brush(group) {
23514     var overlay = group
23515         .property("__brush", initialize)
23516       .selectAll(".overlay")
23517       .data([type$2("overlay")]);
23518
23519     overlay.enter().append("rect")
23520         .attr("class", "overlay")
23521         .attr("pointer-events", "all")
23522         .attr("cursor", cursors.overlay)
23523       .merge(overlay)
23524         .each(function() {
23525           var extent = local$$1(this).extent;
23526           select(this)
23527               .attr("x", extent[0][0])
23528               .attr("y", extent[0][1])
23529               .attr("width", extent[1][0] - extent[0][0])
23530               .attr("height", extent[1][1] - extent[0][1]);
23531         });
23532
23533     group.selectAll(".selection")
23534       .data([type$2("selection")])
23535       .enter().append("rect")
23536         .attr("class", "selection")
23537         .attr("cursor", cursors.selection)
23538         .attr("fill", "#777")
23539         .attr("fill-opacity", 0.3)
23540         .attr("stroke", "#fff")
23541         .attr("shape-rendering", "crispEdges");
23542
23543     var handle = group.selectAll(".handle")
23544       .data(dim.handles, function(d) { return d.type; });
23545
23546     handle.exit().remove();
23547
23548     handle.enter().append("rect")
23549         .attr("class", function(d) { return "handle handle--" + d.type; })
23550         .attr("cursor", function(d) { return cursors[d.type]; });
23551
23552     group
23553         .each(redraw)
23554         .attr("fill", "none")
23555         .attr("pointer-events", "all")
23556         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
23557         .on("mousedown.brush touchstart.brush", started);
23558   }
23559
23560   brush.move = function(group, selection$$1) {
23561     if (group.selection) {
23562       group
23563           .on("start.brush", function() { emitter(this, arguments).beforestart().start(); })
23564           .on("interrupt.brush end.brush", function() { emitter(this, arguments).end(); })
23565           .tween("brush", function() {
23566             var that = this,
23567                 state = that.__brush,
23568                 emit = emitter(that, arguments),
23569                 selection0 = state.selection,
23570                 selection1 = dim.input(typeof selection$$1 === "function" ? selection$$1.apply(this, arguments) : selection$$1, state.extent),
23571                 i = interpolateValue(selection0, selection1);
23572
23573             function tween(t) {
23574               state.selection = t === 1 && empty(selection1) ? null : i(t);
23575               redraw.call(that);
23576               emit.brush();
23577             }
23578
23579             return selection0 && selection1 ? tween : tween(1);
23580           });
23581     } else {
23582       group
23583           .each(function() {
23584             var that = this,
23585                 args = arguments,
23586                 state = that.__brush,
23587                 selection1 = dim.input(typeof selection$$1 === "function" ? selection$$1.apply(that, args) : selection$$1, state.extent),
23588                 emit = emitter(that, args).beforestart();
23589
23590             interrupt(that);
23591             state.selection = selection1 == null || empty(selection1) ? null : selection1;
23592             redraw.call(that);
23593             emit.start().brush().end();
23594           });
23595     }
23596   };
23597
23598   function redraw() {
23599     var group = select(this),
23600         selection$$1 = local$$1(this).selection;
23601
23602     if (selection$$1) {
23603       group.selectAll(".selection")
23604           .style("display", null)
23605           .attr("x", selection$$1[0][0])
23606           .attr("y", selection$$1[0][1])
23607           .attr("width", selection$$1[1][0] - selection$$1[0][0])
23608           .attr("height", selection$$1[1][1] - selection$$1[0][1]);
23609
23610       group.selectAll(".handle")
23611           .style("display", null)
23612           .attr("x", function(d) { return d.type[d.type.length - 1] === "e" ? selection$$1[1][0] - handleSize / 2 : selection$$1[0][0] - handleSize / 2; })
23613           .attr("y", function(d) { return d.type[0] === "s" ? selection$$1[1][1] - handleSize / 2 : selection$$1[0][1] - handleSize / 2; })
23614           .attr("width", function(d) { return d.type === "n" || d.type === "s" ? selection$$1[1][0] - selection$$1[0][0] + handleSize : handleSize; })
23615           .attr("height", function(d) { return d.type === "e" || d.type === "w" ? selection$$1[1][1] - selection$$1[0][1] + handleSize : handleSize; });
23616     }
23617
23618     else {
23619       group.selectAll(".selection,.handle")
23620           .style("display", "none")
23621           .attr("x", null)
23622           .attr("y", null)
23623           .attr("width", null)
23624           .attr("height", null);
23625     }
23626   }
23627
23628   function emitter(that, args) {
23629     return that.__brush.emitter || new Emitter(that, args);
23630   }
23631
23632   function Emitter(that, args) {
23633     this.that = that;
23634     this.args = args;
23635     this.state = that.__brush;
23636     this.active = 0;
23637   }
23638
23639   Emitter.prototype = {
23640     beforestart: function() {
23641       if (++this.active === 1) this.state.emitter = this, this.starting = true;
23642       return this;
23643     },
23644     start: function() {
23645       if (this.starting) this.starting = false, this.emit("start");
23646       return this;
23647     },
23648     brush: function() {
23649       this.emit("brush");
23650       return this;
23651     },
23652     end: function() {
23653       if (--this.active === 0) delete this.state.emitter, this.emit("end");
23654       return this;
23655     },
23656     emit: function(type) {
23657       customEvent(new BrushEvent(brush, type, dim.output(this.state.selection)), listeners.apply, listeners, [type, this.that, this.args]);
23658     }
23659   };
23660
23661   function started() {
23662     if (event.touches) { if (event.changedTouches.length < event.touches.length) return noevent$1(); }
23663     else if (touchending) return;
23664     if (!filter.apply(this, arguments)) return;
23665
23666     var that = this,
23667         type = event.target.__data__.type,
23668         mode = (event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (event.altKey ? MODE_CENTER : MODE_HANDLE),
23669         signX = dim === Y ? null : signsX[type],
23670         signY = dim === X ? null : signsY[type],
23671         state = local$$1(that),
23672         extent = state.extent,
23673         selection$$1 = state.selection,
23674         W = extent[0][0], w0, w1,
23675         N = extent[0][1], n0, n1,
23676         E = extent[1][0], e0, e1,
23677         S = extent[1][1], s0, s1,
23678         dx,
23679         dy,
23680         moving,
23681         shifting = signX && signY && event.shiftKey,
23682         lockX,
23683         lockY,
23684         point0 = mouse(that),
23685         point = point0,
23686         emit = emitter(that, arguments).beforestart();
23687
23688     if (type === "overlay") {
23689       state.selection = selection$$1 = [
23690         [w0 = dim === Y ? W : point0[0], n0 = dim === X ? N : point0[1]],
23691         [e0 = dim === Y ? E : w0, s0 = dim === X ? S : n0]
23692       ];
23693     } else {
23694       w0 = selection$$1[0][0];
23695       n0 = selection$$1[0][1];
23696       e0 = selection$$1[1][0];
23697       s0 = selection$$1[1][1];
23698     }
23699
23700     w1 = w0;
23701     n1 = n0;
23702     e1 = e0;
23703     s1 = s0;
23704
23705     var group = select(that)
23706         .attr("pointer-events", "none");
23707
23708     var overlay = group.selectAll(".overlay")
23709         .attr("cursor", cursors[type]);
23710
23711     if (event.touches) {
23712       group
23713           .on("touchmove.brush", moved, true)
23714           .on("touchend.brush touchcancel.brush", ended, true);
23715     } else {
23716       var view = select(event.view)
23717           .on("keydown.brush", keydowned, true)
23718           .on("keyup.brush", keyupped, true)
23719           .on("mousemove.brush", moved, true)
23720           .on("mouseup.brush", ended, true);
23721
23722       dragDisable(event.view);
23723     }
23724
23725     nopropagation$1();
23726     interrupt(that);
23727     redraw.call(that);
23728     emit.start();
23729
23730     function moved() {
23731       var point1 = mouse(that);
23732       if (shifting && !lockX && !lockY) {
23733         if (Math.abs(point1[0] - point[0]) > Math.abs(point1[1] - point[1])) lockY = true;
23734         else lockX = true;
23735       }
23736       point = point1;
23737       moving = true;
23738       noevent$1();
23739       move();
23740     }
23741
23742     function move() {
23743       var t;
23744
23745       dx = point[0] - point0[0];
23746       dy = point[1] - point0[1];
23747
23748       switch (mode) {
23749         case MODE_SPACE:
23750         case MODE_DRAG: {
23751           if (signX) dx = Math.max(W - w0, Math.min(E - e0, dx)), w1 = w0 + dx, e1 = e0 + dx;
23752           if (signY) dy = Math.max(N - n0, Math.min(S - s0, dy)), n1 = n0 + dy, s1 = s0 + dy;
23753           break;
23754         }
23755         case MODE_HANDLE: {
23756           if (signX < 0) dx = Math.max(W - w0, Math.min(E - w0, dx)), w1 = w0 + dx, e1 = e0;
23757           else if (signX > 0) dx = Math.max(W - e0, Math.min(E - e0, dx)), w1 = w0, e1 = e0 + dx;
23758           if (signY < 0) dy = Math.max(N - n0, Math.min(S - n0, dy)), n1 = n0 + dy, s1 = s0;
23759           else if (signY > 0) dy = Math.max(N - s0, Math.min(S - s0, dy)), n1 = n0, s1 = s0 + dy;
23760           break;
23761         }
23762         case MODE_CENTER: {
23763           if (signX) w1 = Math.max(W, Math.min(E, w0 - dx * signX)), e1 = Math.max(W, Math.min(E, e0 + dx * signX));
23764           if (signY) n1 = Math.max(N, Math.min(S, n0 - dy * signY)), s1 = Math.max(N, Math.min(S, s0 + dy * signY));
23765           break;
23766         }
23767       }
23768
23769       if (e1 < w1) {
23770         signX *= -1;
23771         t = w0, w0 = e0, e0 = t;
23772         t = w1, w1 = e1, e1 = t;
23773         if (type in flipX) overlay.attr("cursor", cursors[type = flipX[type]]);
23774       }
23775
23776       if (s1 < n1) {
23777         signY *= -1;
23778         t = n0, n0 = s0, s0 = t;
23779         t = n1, n1 = s1, s1 = t;
23780         if (type in flipY) overlay.attr("cursor", cursors[type = flipY[type]]);
23781       }
23782
23783       if (state.selection) selection$$1 = state.selection; // May be set by brush.move!
23784       if (lockX) w1 = selection$$1[0][0], e1 = selection$$1[1][0];
23785       if (lockY) n1 = selection$$1[0][1], s1 = selection$$1[1][1];
23786
23787       if (selection$$1[0][0] !== w1
23788           || selection$$1[0][1] !== n1
23789           || selection$$1[1][0] !== e1
23790           || selection$$1[1][1] !== s1) {
23791         state.selection = [[w1, n1], [e1, s1]];
23792         redraw.call(that);
23793         emit.brush();
23794       }
23795     }
23796
23797     function ended() {
23798       nopropagation$1();
23799       if (event.touches) {
23800         if (event.touches.length) return;
23801         if (touchending) clearTimeout(touchending);
23802         touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
23803         group.on("touchmove.brush touchend.brush touchcancel.brush", null);
23804       } else {
23805         yesdrag(event.view, moving);
23806         view.on("keydown.brush keyup.brush mousemove.brush mouseup.brush", null);
23807       }
23808       group.attr("pointer-events", "all");
23809       overlay.attr("cursor", cursors.overlay);
23810       if (state.selection) selection$$1 = state.selection; // May be set by brush.move (on start)!
23811       if (empty(selection$$1)) state.selection = null, redraw.call(that);
23812       emit.end();
23813     }
23814
23815     function keydowned() {
23816       switch (event.keyCode) {
23817         case 16: { // SHIFT
23818           shifting = signX && signY;
23819           break;
23820         }
23821         case 18: { // ALT
23822           if (mode === MODE_HANDLE) {
23823             if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
23824             if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
23825             mode = MODE_CENTER;
23826             move();
23827           }
23828           break;
23829         }
23830         case 32: { // SPACE; takes priority over ALT
23831           if (mode === MODE_HANDLE || mode === MODE_CENTER) {
23832             if (signX < 0) e0 = e1 - dx; else if (signX > 0) w0 = w1 - dx;
23833             if (signY < 0) s0 = s1 - dy; else if (signY > 0) n0 = n1 - dy;
23834             mode = MODE_SPACE;
23835             overlay.attr("cursor", cursors.selection);
23836             move();
23837           }
23838           break;
23839         }
23840         default: return;
23841       }
23842       noevent$1();
23843     }
23844
23845     function keyupped() {
23846       switch (event.keyCode) {
23847         case 16: { // SHIFT
23848           if (shifting) {
23849             lockX = lockY = shifting = false;
23850             move();
23851           }
23852           break;
23853         }
23854         case 18: { // ALT
23855           if (mode === MODE_CENTER) {
23856             if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
23857             if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
23858             mode = MODE_HANDLE;
23859             move();
23860           }
23861           break;
23862         }
23863         case 32: { // SPACE
23864           if (mode === MODE_SPACE) {
23865             if (event.altKey) {
23866               if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
23867               if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
23868               mode = MODE_CENTER;
23869             } else {
23870               if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
23871               if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
23872               mode = MODE_HANDLE;
23873             }
23874             overlay.attr("cursor", cursors[type]);
23875             move();
23876           }
23877           break;
23878         }
23879         default: return;
23880       }
23881       noevent$1();
23882     }
23883   }
23884
23885   function initialize() {
23886     var state = this.__brush || {selection: null};
23887     state.extent = extent.apply(this, arguments);
23888     state.dim = dim;
23889     return state;
23890   }
23891
23892   brush.extent = function(_) {
23893     return arguments.length ? (extent = typeof _ === "function" ? _ : constant$4([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), brush) : extent;
23894   };
23895
23896   brush.filter = function(_) {
23897     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$4(!!_), brush) : filter;
23898   };
23899
23900   brush.handleSize = function(_) {
23901     return arguments.length ? (handleSize = +_, brush) : handleSize;
23902   };
23903
23904   brush.on = function() {
23905     var value = listeners.on.apply(listeners, arguments);
23906     return value === listeners ? brush : value;
23907   };
23908
23909   return brush;
23910 }
23911
23912 var cos = Math.cos;
23913 var sin = Math.sin;
23914 var pi$1 = Math.PI;
23915 var halfPi$1 = pi$1 / 2;
23916 var tau$1 = pi$1 * 2;
23917 var max$1 = Math.max;
23918
23919 function compareValue(compare) {
23920   return function(a, b) {
23921     return compare(
23922       a.source.value + a.target.value,
23923       b.source.value + b.target.value
23924     );
23925   };
23926 }
23927
23928 var chord = function() {
23929   var padAngle = 0,
23930       sortGroups = null,
23931       sortSubgroups = null,
23932       sortChords = null;
23933
23934   function chord(matrix) {
23935     var n = matrix.length,
23936         groupSums = [],
23937         groupIndex = sequence(n),
23938         subgroupIndex = [],
23939         chords = [],
23940         groups = chords.groups = new Array(n),
23941         subgroups = new Array(n * n),
23942         k,
23943         x,
23944         x0,
23945         dx,
23946         i,
23947         j;
23948
23949     // Compute the sum.
23950     k = 0, i = -1; while (++i < n) {
23951       x = 0, j = -1; while (++j < n) {
23952         x += matrix[i][j];
23953       }
23954       groupSums.push(x);
23955       subgroupIndex.push(sequence(n));
23956       k += x;
23957     }
23958
23959     // Sort groups…
23960     if (sortGroups) groupIndex.sort(function(a, b) {
23961       return sortGroups(groupSums[a], groupSums[b]);
23962     });
23963
23964     // Sort subgroups…
23965     if (sortSubgroups) subgroupIndex.forEach(function(d, i) {
23966       d.sort(function(a, b) {
23967         return sortSubgroups(matrix[i][a], matrix[i][b]);
23968       });
23969     });
23970
23971     // Convert the sum to scaling factor for [0, 2pi].
23972     // TODO Allow start and end angle to be specified?
23973     // TODO Allow padding to be specified as percentage?
23974     k = max$1(0, tau$1 - padAngle * n) / k;
23975     dx = k ? padAngle : tau$1 / n;
23976
23977     // Compute the start and end angle for each group and subgroup.
23978     // Note: Opera has a bug reordering object literal properties!
23979     x = 0, i = -1; while (++i < n) {
23980       x0 = x, j = -1; while (++j < n) {
23981         var di = groupIndex[i],
23982             dj = subgroupIndex[di][j],
23983             v = matrix[di][dj],
23984             a0 = x,
23985             a1 = x += v * k;
23986         subgroups[dj * n + di] = {
23987           index: di,
23988           subindex: dj,
23989           startAngle: a0,
23990           endAngle: a1,
23991           value: v
23992         };
23993       }
23994       groups[di] = {
23995         index: di,
23996         startAngle: x0,
23997         endAngle: x,
23998         value: groupSums[di]
23999       };
24000       x += dx;
24001     }
24002
24003     // Generate chords for each (non-empty) subgroup-subgroup link.
24004     i = -1; while (++i < n) {
24005       j = i - 1; while (++j < n) {
24006         var source = subgroups[j * n + i],
24007             target = subgroups[i * n + j];
24008         if (source.value || target.value) {
24009           chords.push(source.value < target.value
24010               ? {source: target, target: source}
24011               : {source: source, target: target});
24012         }
24013       }
24014     }
24015
24016     return sortChords ? chords.sort(sortChords) : chords;
24017   }
24018
24019   chord.padAngle = function(_) {
24020     return arguments.length ? (padAngle = max$1(0, _), chord) : padAngle;
24021   };
24022
24023   chord.sortGroups = function(_) {
24024     return arguments.length ? (sortGroups = _, chord) : sortGroups;
24025   };
24026
24027   chord.sortSubgroups = function(_) {
24028     return arguments.length ? (sortSubgroups = _, chord) : sortSubgroups;
24029   };
24030
24031   chord.sortChords = function(_) {
24032     return arguments.length ? (_ == null ? sortChords = null : (sortChords = compareValue(_))._ = _, chord) : sortChords && sortChords._;
24033   };
24034
24035   return chord;
24036 };
24037
24038 var slice$2 = Array.prototype.slice;
24039
24040 var constant$5 = function(x) {
24041   return function() {
24042     return x;
24043   };
24044 };
24045
24046 var pi$2 = Math.PI;
24047 var tau$2 = 2 * pi$2;
24048 var epsilon$1 = 1e-6;
24049 var tauEpsilon = tau$2 - epsilon$1;
24050
24051 function Path() {
24052   this._x0 = this._y0 = // start of current subpath
24053   this._x1 = this._y1 = null; // end of current subpath
24054   this._ = "";
24055 }
24056
24057 function path() {
24058   return new Path;
24059 }
24060
24061 Path.prototype = path.prototype = {
24062   constructor: Path,
24063   moveTo: function(x, y) {
24064     this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y);
24065   },
24066   closePath: function() {
24067     if (this._x1 !== null) {
24068       this._x1 = this._x0, this._y1 = this._y0;
24069       this._ += "Z";
24070     }
24071   },
24072   lineTo: function(x, y) {
24073     this._ += "L" + (this._x1 = +x) + "," + (this._y1 = +y);
24074   },
24075   quadraticCurveTo: function(x1, y1, x, y) {
24076     this._ += "Q" + (+x1) + "," + (+y1) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
24077   },
24078   bezierCurveTo: function(x1, y1, x2, y2, x, y) {
24079     this._ += "C" + (+x1) + "," + (+y1) + "," + (+x2) + "," + (+y2) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
24080   },
24081   arcTo: function(x1, y1, x2, y2, r) {
24082     x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;
24083     var x0 = this._x1,
24084         y0 = this._y1,
24085         x21 = x2 - x1,
24086         y21 = y2 - y1,
24087         x01 = x0 - x1,
24088         y01 = y0 - y1,
24089         l01_2 = x01 * x01 + y01 * y01;
24090
24091     // Is the radius negative? Error.
24092     if (r < 0) throw new Error("negative radius: " + r);
24093
24094     // Is this path empty? Move to (x1,y1).
24095     if (this._x1 === null) {
24096       this._ += "M" + (this._x1 = x1) + "," + (this._y1 = y1);
24097     }
24098
24099     // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.
24100     else if (!(l01_2 > epsilon$1)) {}
24101
24102     // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?
24103     // Equivalently, is (x1,y1) coincident with (x2,y2)?
24104     // Or, is the radius zero? Line to (x1,y1).
24105     else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon$1) || !r) {
24106       this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1);
24107     }
24108
24109     // Otherwise, draw an arc!
24110     else {
24111       var x20 = x2 - x0,
24112           y20 = y2 - y0,
24113           l21_2 = x21 * x21 + y21 * y21,
24114           l20_2 = x20 * x20 + y20 * y20,
24115           l21 = Math.sqrt(l21_2),
24116           l01 = Math.sqrt(l01_2),
24117           l = r * Math.tan((pi$2 - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),
24118           t01 = l / l01,
24119           t21 = l / l21;
24120
24121       // If the start tangent is not coincident with (x0,y0), line to.
24122       if (Math.abs(t01 - 1) > epsilon$1) {
24123         this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01);
24124       }
24125
24126       this._ += "A" + r + "," + r + ",0,0," + (+(y01 * x20 > x01 * y20)) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21);
24127     }
24128   },
24129   arc: function(x, y, r, a0, a1, ccw) {
24130     x = +x, y = +y, r = +r;
24131     var dx = r * Math.cos(a0),
24132         dy = r * Math.sin(a0),
24133         x0 = x + dx,
24134         y0 = y + dy,
24135         cw = 1 ^ ccw,
24136         da = ccw ? a0 - a1 : a1 - a0;
24137
24138     // Is the radius negative? Error.
24139     if (r < 0) throw new Error("negative radius: " + r);
24140
24141     // Is this path empty? Move to (x0,y0).
24142     if (this._x1 === null) {
24143       this._ += "M" + x0 + "," + y0;
24144     }
24145
24146     // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).
24147     else if (Math.abs(this._x1 - x0) > epsilon$1 || Math.abs(this._y1 - y0) > epsilon$1) {
24148       this._ += "L" + x0 + "," + y0;
24149     }
24150
24151     // Is this arc empty? We’re done.
24152     if (!r) return;
24153
24154     // Does the angle go the wrong way? Flip the direction.
24155     if (da < 0) da = da % tau$2 + tau$2;
24156
24157     // Is this a complete circle? Draw two arcs to complete the circle.
24158     if (da > tauEpsilon) {
24159       this._ += "A" + r + "," + r + ",0,1," + cw + "," + (x - dx) + "," + (y - dy) + "A" + r + "," + r + ",0,1," + cw + "," + (this._x1 = x0) + "," + (this._y1 = y0);
24160     }
24161
24162     // Is this arc non-empty? Draw an arc!
24163     else if (da > epsilon$1) {
24164       this._ += "A" + r + "," + r + ",0," + (+(da >= pi$2)) + "," + cw + "," + (this._x1 = x + r * Math.cos(a1)) + "," + (this._y1 = y + r * Math.sin(a1));
24165     }
24166   },
24167   rect: function(x, y, w, h) {
24168     this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y) + "h" + (+w) + "v" + (+h) + "h" + (-w) + "Z";
24169   },
24170   toString: function() {
24171     return this._;
24172   }
24173 };
24174
24175 function defaultSource(d) {
24176   return d.source;
24177 }
24178
24179 function defaultTarget(d) {
24180   return d.target;
24181 }
24182
24183 function defaultRadius(d) {
24184   return d.radius;
24185 }
24186
24187 function defaultStartAngle(d) {
24188   return d.startAngle;
24189 }
24190
24191 function defaultEndAngle(d) {
24192   return d.endAngle;
24193 }
24194
24195 var ribbon = function() {
24196   var source = defaultSource,
24197       target = defaultTarget,
24198       radius = defaultRadius,
24199       startAngle = defaultStartAngle,
24200       endAngle = defaultEndAngle,
24201       context = null;
24202
24203   function ribbon() {
24204     var buffer,
24205         argv = slice$2.call(arguments),
24206         s = source.apply(this, argv),
24207         t = target.apply(this, argv),
24208         sr = +radius.apply(this, (argv[0] = s, argv)),
24209         sa0 = startAngle.apply(this, argv) - halfPi$1,
24210         sa1 = endAngle.apply(this, argv) - halfPi$1,
24211         sx0 = sr * cos(sa0),
24212         sy0 = sr * sin(sa0),
24213         tr = +radius.apply(this, (argv[0] = t, argv)),
24214         ta0 = startAngle.apply(this, argv) - halfPi$1,
24215         ta1 = endAngle.apply(this, argv) - halfPi$1;
24216
24217     if (!context) context = buffer = path();
24218
24219     context.moveTo(sx0, sy0);
24220     context.arc(0, 0, sr, sa0, sa1);
24221     if (sa0 !== ta0 || sa1 !== ta1) { // TODO sr !== tr?
24222       context.quadraticCurveTo(0, 0, tr * cos(ta0), tr * sin(ta0));
24223       context.arc(0, 0, tr, ta0, ta1);
24224     }
24225     context.quadraticCurveTo(0, 0, sx0, sy0);
24226     context.closePath();
24227
24228     if (buffer) return context = null, buffer + "" || null;
24229   }
24230
24231   ribbon.radius = function(_) {
24232     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$5(+_), ribbon) : radius;
24233   };
24234
24235   ribbon.startAngle = function(_) {
24236     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : startAngle;
24237   };
24238
24239   ribbon.endAngle = function(_) {
24240     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : endAngle;
24241   };
24242
24243   ribbon.source = function(_) {
24244     return arguments.length ? (source = _, ribbon) : source;
24245   };
24246
24247   ribbon.target = function(_) {
24248     return arguments.length ? (target = _, ribbon) : target;
24249   };
24250
24251   ribbon.context = function(_) {
24252     return arguments.length ? ((context = _ == null ? null : _), ribbon) : context;
24253   };
24254
24255   return ribbon;
24256 };
24257
24258 var prefix = "$";
24259
24260 function Map() {}
24261
24262 Map.prototype = map$1.prototype = {
24263   constructor: Map,
24264   has: function(key) {
24265     return (prefix + key) in this;
24266   },
24267   get: function(key) {
24268     return this[prefix + key];
24269   },
24270   set: function(key, value) {
24271     this[prefix + key] = value;
24272     return this;
24273   },
24274   remove: function(key) {
24275     var property = prefix + key;
24276     return property in this && delete this[property];
24277   },
24278   clear: function() {
24279     for (var property in this) if (property[0] === prefix) delete this[property];
24280   },
24281   keys: function() {
24282     var keys = [];
24283     for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));
24284     return keys;
24285   },
24286   values: function() {
24287     var values = [];
24288     for (var property in this) if (property[0] === prefix) values.push(this[property]);
24289     return values;
24290   },
24291   entries: function() {
24292     var entries = [];
24293     for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});
24294     return entries;
24295   },
24296   size: function() {
24297     var size = 0;
24298     for (var property in this) if (property[0] === prefix) ++size;
24299     return size;
24300   },
24301   empty: function() {
24302     for (var property in this) if (property[0] === prefix) return false;
24303     return true;
24304   },
24305   each: function(f) {
24306     for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);
24307   }
24308 };
24309
24310 function map$1(object, f) {
24311   var map = new Map;
24312
24313   // Copy constructor.
24314   if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });
24315
24316   // Index array by numeric index or specified key function.
24317   else if (Array.isArray(object)) {
24318     var i = -1,
24319         n = object.length,
24320         o;
24321
24322     if (f == null) while (++i < n) map.set(i, object[i]);
24323     else while (++i < n) map.set(f(o = object[i], i, object), o);
24324   }
24325
24326   // Convert object to map.
24327   else if (object) for (var key in object) map.set(key, object[key]);
24328
24329   return map;
24330 }
24331
24332 var nest = function() {
24333   var keys = [],
24334       sortKeys = [],
24335       sortValues,
24336       rollup,
24337       nest;
24338
24339   function apply(array, depth, createResult, setResult) {
24340     if (depth >= keys.length) return rollup != null
24341         ? rollup(array) : (sortValues != null
24342         ? array.sort(sortValues)
24343         : array);
24344
24345     var i = -1,
24346         n = array.length,
24347         key = keys[depth++],
24348         keyValue,
24349         value,
24350         valuesByKey = map$1(),
24351         values,
24352         result = createResult();
24353
24354     while (++i < n) {
24355       if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) {
24356         values.push(value);
24357       } else {
24358         valuesByKey.set(keyValue, [value]);
24359       }
24360     }
24361
24362     valuesByKey.each(function(values, key) {
24363       setResult(result, key, apply(values, depth, createResult, setResult));
24364     });
24365
24366     return result;
24367   }
24368
24369   function entries(map, depth) {
24370     if (++depth > keys.length) return map;
24371     var array, sortKey = sortKeys[depth - 1];
24372     if (rollup != null && depth >= keys.length) array = map.entries();
24373     else array = [], map.each(function(v, k) { array.push({key: k, values: entries(v, depth)}); });
24374     return sortKey != null ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array;
24375   }
24376
24377   return nest = {
24378     object: function(array) { return apply(array, 0, createObject, setObject); },
24379     map: function(array) { return apply(array, 0, createMap, setMap); },
24380     entries: function(array) { return entries(apply(array, 0, createMap, setMap), 0); },
24381     key: function(d) { keys.push(d); return nest; },
24382     sortKeys: function(order) { sortKeys[keys.length - 1] = order; return nest; },
24383     sortValues: function(order) { sortValues = order; return nest; },
24384     rollup: function(f) { rollup = f; return nest; }
24385   };
24386 };
24387
24388 function createObject() {
24389   return {};
24390 }
24391
24392 function setObject(object, key, value) {
24393   object[key] = value;
24394 }
24395
24396 function createMap() {
24397   return map$1();
24398 }
24399
24400 function setMap(map, key, value) {
24401   map.set(key, value);
24402 }
24403
24404 function Set() {}
24405
24406 var proto = map$1.prototype;
24407
24408 Set.prototype = set$2.prototype = {
24409   constructor: Set,
24410   has: proto.has,
24411   add: function(value) {
24412     value += "";
24413     this[prefix + value] = value;
24414     return this;
24415   },
24416   remove: proto.remove,
24417   clear: proto.clear,
24418   values: proto.keys,
24419   size: proto.size,
24420   empty: proto.empty,
24421   each: proto.each
24422 };
24423
24424 function set$2(object, f) {
24425   var set = new Set;
24426
24427   // Copy constructor.
24428   if (object instanceof Set) object.each(function(value) { set.add(value); });
24429
24430   // Otherwise, assume it’s an array.
24431   else if (object) {
24432     var i = -1, n = object.length;
24433     if (f == null) while (++i < n) set.add(object[i]);
24434     else while (++i < n) set.add(f(object[i], i, object));
24435   }
24436
24437   return set;
24438 }
24439
24440 var keys = function(map) {
24441   var keys = [];
24442   for (var key in map) keys.push(key);
24443   return keys;
24444 };
24445
24446 var values = function(map) {
24447   var values = [];
24448   for (var key in map) values.push(map[key]);
24449   return values;
24450 };
24451
24452 var entries = function(map) {
24453   var entries = [];
24454   for (var key in map) entries.push({key: key, value: map[key]});
24455   return entries;
24456 };
24457
24458 function objectConverter(columns) {
24459   return new Function("d", "return {" + columns.map(function(name, i) {
24460     return JSON.stringify(name) + ": d[" + i + "]";
24461   }).join(",") + "}");
24462 }
24463
24464 function customConverter(columns, f) {
24465   var object = objectConverter(columns);
24466   return function(row, i) {
24467     return f(object(row), i, columns);
24468   };
24469 }
24470
24471 // Compute unique columns in order of discovery.
24472 function inferColumns(rows) {
24473   var columnSet = Object.create(null),
24474       columns = [];
24475
24476   rows.forEach(function(row) {
24477     for (var column in row) {
24478       if (!(column in columnSet)) {
24479         columns.push(columnSet[column] = column);
24480       }
24481     }
24482   });
24483
24484   return columns;
24485 }
24486
24487 var dsv = function(delimiter) {
24488   var reFormat = new RegExp("[\"" + delimiter + "\n\r]"),
24489       delimiterCode = delimiter.charCodeAt(0);
24490
24491   function parse(text, f) {
24492     var convert, columns, rows = parseRows(text, function(row, i) {
24493       if (convert) return convert(row, i - 1);
24494       columns = row, convert = f ? customConverter(row, f) : objectConverter(row);
24495     });
24496     rows.columns = columns;
24497     return rows;
24498   }
24499
24500   function parseRows(text, f) {
24501     var EOL = {}, // sentinel value for end-of-line
24502         EOF = {}, // sentinel value for end-of-file
24503         rows = [], // output rows
24504         N = text.length,
24505         I = 0, // current character index
24506         n = 0, // the current line number
24507         t, // the current token
24508         eol; // is the current token followed by EOL?
24509
24510     function token() {
24511       if (I >= N) return EOF; // special case: end of file
24512       if (eol) return eol = false, EOL; // special case: end of line
24513
24514       // special case: quotes
24515       var j = I, c;
24516       if (text.charCodeAt(j) === 34) {
24517         var i = j;
24518         while (i++ < N) {
24519           if (text.charCodeAt(i) === 34) {
24520             if (text.charCodeAt(i + 1) !== 34) break;
24521             ++i;
24522           }
24523         }
24524         I = i + 2;
24525         c = text.charCodeAt(i + 1);
24526         if (c === 13) {
24527           eol = true;
24528           if (text.charCodeAt(i + 2) === 10) ++I;
24529         } else if (c === 10) {
24530           eol = true;
24531         }
24532         return text.slice(j + 1, i).replace(/""/g, "\"");
24533       }
24534
24535       // common case: find next delimiter or newline
24536       while (I < N) {
24537         var k = 1;
24538         c = text.charCodeAt(I++);
24539         if (c === 10) eol = true; // \n
24540         else if (c === 13) { eol = true; if (text.charCodeAt(I) === 10) ++I, ++k; } // \r|\r\n
24541         else if (c !== delimiterCode) continue;
24542         return text.slice(j, I - k);
24543       }
24544
24545       // special case: last token before EOF
24546       return text.slice(j);
24547     }
24548
24549     while ((t = token()) !== EOF) {
24550       var a = [];
24551       while (t !== EOL && t !== EOF) {
24552         a.push(t);
24553         t = token();
24554       }
24555       if (f && (a = f(a, n++)) == null) continue;
24556       rows.push(a);
24557     }
24558
24559     return rows;
24560   }
24561
24562   function format(rows, columns) {
24563     if (columns == null) columns = inferColumns(rows);
24564     return [columns.map(formatValue).join(delimiter)].concat(rows.map(function(row) {
24565       return columns.map(function(column) {
24566         return formatValue(row[column]);
24567       }).join(delimiter);
24568     })).join("\n");
24569   }
24570
24571   function formatRows(rows) {
24572     return rows.map(formatRow).join("\n");
24573   }
24574
24575   function formatRow(row) {
24576     return row.map(formatValue).join(delimiter);
24577   }
24578
24579   function formatValue(text) {
24580     return text == null ? ""
24581         : reFormat.test(text += "") ? "\"" + text.replace(/\"/g, "\"\"") + "\""
24582         : text;
24583   }
24584
24585   return {
24586     parse: parse,
24587     parseRows: parseRows,
24588     format: format,
24589     formatRows: formatRows
24590   };
24591 };
24592
24593 var csv = dsv(",");
24594
24595 var csvParse = csv.parse;
24596 var csvParseRows = csv.parseRows;
24597 var csvFormat = csv.format;
24598 var csvFormatRows = csv.formatRows;
24599
24600 var tsv = dsv("\t");
24601
24602 var tsvParse = tsv.parse;
24603 var tsvParseRows = tsv.parseRows;
24604 var tsvFormat = tsv.format;
24605 var tsvFormatRows = tsv.formatRows;
24606
24607 var center$1 = function(x, y) {
24608   var nodes;
24609
24610   if (x == null) x = 0;
24611   if (y == null) y = 0;
24612
24613   function force() {
24614     var i,
24615         n = nodes.length,
24616         node,
24617         sx = 0,
24618         sy = 0;
24619
24620     for (i = 0; i < n; ++i) {
24621       node = nodes[i], sx += node.x, sy += node.y;
24622     }
24623
24624     for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) {
24625       node = nodes[i], node.x -= sx, node.y -= sy;
24626     }
24627   }
24628
24629   force.initialize = function(_) {
24630     nodes = _;
24631   };
24632
24633   force.x = function(_) {
24634     return arguments.length ? (x = +_, force) : x;
24635   };
24636
24637   force.y = function(_) {
24638     return arguments.length ? (y = +_, force) : y;
24639   };
24640
24641   return force;
24642 };
24643
24644 var constant$6 = function(x) {
24645   return function() {
24646     return x;
24647   };
24648 };
24649
24650 var jiggle = function() {
24651   return (Math.random() - 0.5) * 1e-6;
24652 };
24653
24654 var tree_add = function(d) {
24655   var x = +this._x.call(null, d),
24656       y = +this._y.call(null, d);
24657   return add(this.cover(x, y), x, y, d);
24658 };
24659
24660 function add(tree, x, y, d) {
24661   if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points
24662
24663   var parent,
24664       node = tree._root,
24665       leaf = {data: d},
24666       x0 = tree._x0,
24667       y0 = tree._y0,
24668       x1 = tree._x1,
24669       y1 = tree._y1,
24670       xm,
24671       ym,
24672       xp,
24673       yp,
24674       right,
24675       bottom,
24676       i,
24677       j;
24678
24679   // If the tree is empty, initialize the root as a leaf.
24680   if (!node) return tree._root = leaf, tree;
24681
24682   // Find the existing leaf for the new point, or add it.
24683   while (node.length) {
24684     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24685     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24686     if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree;
24687   }
24688
24689   // Is the new point is exactly coincident with the existing point?
24690   xp = +tree._x.call(null, node.data);
24691   yp = +tree._y.call(null, node.data);
24692   if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree;
24693
24694   // Otherwise, split the leaf node until the old and new point are separated.
24695   do {
24696     parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4);
24697     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24698     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24699   } while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm)));
24700   return parent[j] = node, parent[i] = leaf, tree;
24701 }
24702
24703 function addAll(data) {
24704   var d, i, n = data.length,
24705       x,
24706       y,
24707       xz = new Array(n),
24708       yz = new Array(n),
24709       x0 = Infinity,
24710       y0 = Infinity,
24711       x1 = -Infinity,
24712       y1 = -Infinity;
24713
24714   // Compute the points and their extent.
24715   for (i = 0; i < n; ++i) {
24716     if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue;
24717     xz[i] = x;
24718     yz[i] = y;
24719     if (x < x0) x0 = x;
24720     if (x > x1) x1 = x;
24721     if (y < y0) y0 = y;
24722     if (y > y1) y1 = y;
24723   }
24724
24725   // If there were no (valid) points, inherit the existing extent.
24726   if (x1 < x0) x0 = this._x0, x1 = this._x1;
24727   if (y1 < y0) y0 = this._y0, y1 = this._y1;
24728
24729   // Expand the tree to cover the new points.
24730   this.cover(x0, y0).cover(x1, y1);
24731
24732   // Add the new points.
24733   for (i = 0; i < n; ++i) {
24734     add(this, xz[i], yz[i], data[i]);
24735   }
24736
24737   return this;
24738 }
24739
24740 var tree_cover = function(x, y) {
24741   if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points
24742
24743   var x0 = this._x0,
24744       y0 = this._y0,
24745       x1 = this._x1,
24746       y1 = this._y1;
24747
24748   // If the quadtree has no extent, initialize them.
24749   // Integer extent are necessary so that if we later double the extent,
24750   // the existing quadrant boundaries don’t change due to floating point error!
24751   if (isNaN(x0)) {
24752     x1 = (x0 = Math.floor(x)) + 1;
24753     y1 = (y0 = Math.floor(y)) + 1;
24754   }
24755
24756   // Otherwise, double repeatedly to cover.
24757   else if (x0 > x || x > x1 || y0 > y || y > y1) {
24758     var z = x1 - x0,
24759         node = this._root,
24760         parent,
24761         i;
24762
24763     switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) {
24764       case 0: {
24765         do parent = new Array(4), parent[i] = node, node = parent;
24766         while (z *= 2, x1 = x0 + z, y1 = y0 + z, x > x1 || y > y1);
24767         break;
24768       }
24769       case 1: {
24770         do parent = new Array(4), parent[i] = node, node = parent;
24771         while (z *= 2, x0 = x1 - z, y1 = y0 + z, x0 > x || y > y1);
24772         break;
24773       }
24774       case 2: {
24775         do parent = new Array(4), parent[i] = node, node = parent;
24776         while (z *= 2, x1 = x0 + z, y0 = y1 - z, x > x1 || y0 > y);
24777         break;
24778       }
24779       case 3: {
24780         do parent = new Array(4), parent[i] = node, node = parent;
24781         while (z *= 2, x0 = x1 - z, y0 = y1 - z, x0 > x || y0 > y);
24782         break;
24783       }
24784     }
24785
24786     if (this._root && this._root.length) this._root = node;
24787   }
24788
24789   // If the quadtree covers the point already, just return.
24790   else return this;
24791
24792   this._x0 = x0;
24793   this._y0 = y0;
24794   this._x1 = x1;
24795   this._y1 = y1;
24796   return this;
24797 };
24798
24799 var tree_data = function() {
24800   var data = [];
24801   this.visit(function(node) {
24802     if (!node.length) do data.push(node.data); while (node = node.next)
24803   });
24804   return data;
24805 };
24806
24807 var tree_extent = function(_) {
24808   return arguments.length
24809       ? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1])
24810       : isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]];
24811 };
24812
24813 var Quad = function(node, x0, y0, x1, y1) {
24814   this.node = node;
24815   this.x0 = x0;
24816   this.y0 = y0;
24817   this.x1 = x1;
24818   this.y1 = y1;
24819 };
24820
24821 var tree_find = function(x, y, radius) {
24822   var data,
24823       x0 = this._x0,
24824       y0 = this._y0,
24825       x1,
24826       y1,
24827       x2,
24828       y2,
24829       x3 = this._x1,
24830       y3 = this._y1,
24831       quads = [],
24832       node = this._root,
24833       q,
24834       i;
24835
24836   if (node) quads.push(new Quad(node, x0, y0, x3, y3));
24837   if (radius == null) radius = Infinity;
24838   else {
24839     x0 = x - radius, y0 = y - radius;
24840     x3 = x + radius, y3 = y + radius;
24841     radius *= radius;
24842   }
24843
24844   while (q = quads.pop()) {
24845
24846     // Stop searching if this quadrant can’t contain a closer node.
24847     if (!(node = q.node)
24848         || (x1 = q.x0) > x3
24849         || (y1 = q.y0) > y3
24850         || (x2 = q.x1) < x0
24851         || (y2 = q.y1) < y0) continue;
24852
24853     // Bisect the current quadrant.
24854     if (node.length) {
24855       var xm = (x1 + x2) / 2,
24856           ym = (y1 + y2) / 2;
24857
24858       quads.push(
24859         new Quad(node[3], xm, ym, x2, y2),
24860         new Quad(node[2], x1, ym, xm, y2),
24861         new Quad(node[1], xm, y1, x2, ym),
24862         new Quad(node[0], x1, y1, xm, ym)
24863       );
24864
24865       // Visit the closest quadrant first.
24866       if (i = (y >= ym) << 1 | (x >= xm)) {
24867         q = quads[quads.length - 1];
24868         quads[quads.length - 1] = quads[quads.length - 1 - i];
24869         quads[quads.length - 1 - i] = q;
24870       }
24871     }
24872
24873     // Visit this point. (Visiting coincident points isn’t necessary!)
24874     else {
24875       var dx = x - +this._x.call(null, node.data),
24876           dy = y - +this._y.call(null, node.data),
24877           d2 = dx * dx + dy * dy;
24878       if (d2 < radius) {
24879         var d = Math.sqrt(radius = d2);
24880         x0 = x - d, y0 = y - d;
24881         x3 = x + d, y3 = y + d;
24882         data = node.data;
24883       }
24884     }
24885   }
24886
24887   return data;
24888 };
24889
24890 var tree_remove = function(d) {
24891   if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points
24892
24893   var parent,
24894       node = this._root,
24895       retainer,
24896       previous,
24897       next,
24898       x0 = this._x0,
24899       y0 = this._y0,
24900       x1 = this._x1,
24901       y1 = this._y1,
24902       x,
24903       y,
24904       xm,
24905       ym,
24906       right,
24907       bottom,
24908       i,
24909       j;
24910
24911   // If the tree is empty, initialize the root as a leaf.
24912   if (!node) return this;
24913
24914   // Find the leaf node for the point.
24915   // While descending, also retain the deepest parent with a non-removed sibling.
24916   if (node.length) while (true) {
24917     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24918     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24919     if (!(parent = node, node = node[i = bottom << 1 | right])) return this;
24920     if (!node.length) break;
24921     if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i;
24922   }
24923
24924   // Find the point to remove.
24925   while (node.data !== d) if (!(previous = node, node = node.next)) return this;
24926   if (next = node.next) delete node.next;
24927
24928   // If there are multiple coincident points, remove just the point.
24929   if (previous) return (next ? previous.next = next : delete previous.next), this;
24930
24931   // If this is the root point, remove it.
24932   if (!parent) return this._root = next, this;
24933
24934   // Remove this leaf.
24935   next ? parent[i] = next : delete parent[i];
24936
24937   // If the parent now contains exactly one leaf, collapse superfluous parents.
24938   if ((node = parent[0] || parent[1] || parent[2] || parent[3])
24939       && node === (parent[3] || parent[2] || parent[1] || parent[0])
24940       && !node.length) {
24941     if (retainer) retainer[j] = node;
24942     else this._root = node;
24943   }
24944
24945   return this;
24946 };
24947
24948 function removeAll(data) {
24949   for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]);
24950   return this;
24951 }
24952
24953 var tree_root = function() {
24954   return this._root;
24955 };
24956
24957 var tree_size = function() {
24958   var size = 0;
24959   this.visit(function(node) {
24960     if (!node.length) do ++size; while (node = node.next)
24961   });
24962   return size;
24963 };
24964
24965 var tree_visit = function(callback) {
24966   var quads = [], q, node = this._root, child, x0, y0, x1, y1;
24967   if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1));
24968   while (q = quads.pop()) {
24969     if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) {
24970       var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
24971       if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
24972       if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
24973       if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
24974       if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
24975     }
24976   }
24977   return this;
24978 };
24979
24980 var tree_visitAfter = function(callback) {
24981   var quads = [], next = [], q;
24982   if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1));
24983   while (q = quads.pop()) {
24984     var node = q.node;
24985     if (node.length) {
24986       var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
24987       if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
24988       if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
24989       if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
24990       if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
24991     }
24992     next.push(q);
24993   }
24994   while (q = next.pop()) {
24995     callback(q.node, q.x0, q.y0, q.x1, q.y1);
24996   }
24997   return this;
24998 };
24999
25000 function defaultX(d) {
25001   return d[0];
25002 }
25003
25004 var tree_x = function(_) {
25005   return arguments.length ? (this._x = _, this) : this._x;
25006 };
25007
25008 function defaultY(d) {
25009   return d[1];
25010 }
25011
25012 var tree_y = function(_) {
25013   return arguments.length ? (this._y = _, this) : this._y;
25014 };
25015
25016 function quadtree(nodes, x, y) {
25017   var tree = new Quadtree(x == null ? defaultX : x, y == null ? defaultY : y, NaN, NaN, NaN, NaN);
25018   return nodes == null ? tree : tree.addAll(nodes);
25019 }
25020
25021 function Quadtree(x, y, x0, y0, x1, y1) {
25022   this._x = x;
25023   this._y = y;
25024   this._x0 = x0;
25025   this._y0 = y0;
25026   this._x1 = x1;
25027   this._y1 = y1;
25028   this._root = undefined;
25029 }
25030
25031 function leaf_copy(leaf) {
25032   var copy = {data: leaf.data}, next = copy;
25033   while (leaf = leaf.next) next = next.next = {data: leaf.data};
25034   return copy;
25035 }
25036
25037 var treeProto = quadtree.prototype = Quadtree.prototype;
25038
25039 treeProto.copy = function() {
25040   var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1),
25041       node = this._root,
25042       nodes,
25043       child;
25044
25045   if (!node) return copy;
25046
25047   if (!node.length) return copy._root = leaf_copy(node), copy;
25048
25049   nodes = [{source: node, target: copy._root = new Array(4)}];
25050   while (node = nodes.pop()) {
25051     for (var i = 0; i < 4; ++i) {
25052       if (child = node.source[i]) {
25053         if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)});
25054         else node.target[i] = leaf_copy(child);
25055       }
25056     }
25057   }
25058
25059   return copy;
25060 };
25061
25062 treeProto.add = tree_add;
25063 treeProto.addAll = addAll;
25064 treeProto.cover = tree_cover;
25065 treeProto.data = tree_data;
25066 treeProto.extent = tree_extent;
25067 treeProto.find = tree_find;
25068 treeProto.remove = tree_remove;
25069 treeProto.removeAll = removeAll;
25070 treeProto.root = tree_root;
25071 treeProto.size = tree_size;
25072 treeProto.visit = tree_visit;
25073 treeProto.visitAfter = tree_visitAfter;
25074 treeProto.x = tree_x;
25075 treeProto.y = tree_y;
25076
25077 function x(d) {
25078   return d.x + d.vx;
25079 }
25080
25081 function y(d) {
25082   return d.y + d.vy;
25083 }
25084
25085 var collide = function(radius) {
25086   var nodes,
25087       radii,
25088       strength = 1,
25089       iterations = 1;
25090
25091   if (typeof radius !== "function") radius = constant$6(radius == null ? 1 : +radius);
25092
25093   function force() {
25094     var i, n = nodes.length,
25095         tree,
25096         node,
25097         xi,
25098         yi,
25099         ri,
25100         ri2;
25101
25102     for (var k = 0; k < iterations; ++k) {
25103       tree = quadtree(nodes, x, y).visitAfter(prepare);
25104       for (i = 0; i < n; ++i) {
25105         node = nodes[i];
25106         ri = radii[node.index], ri2 = ri * ri;
25107         xi = node.x + node.vx;
25108         yi = node.y + node.vy;
25109         tree.visit(apply);
25110       }
25111     }
25112
25113     function apply(quad, x0, y0, x1, y1) {
25114       var data = quad.data, rj = quad.r, r = ri + rj;
25115       if (data) {
25116         if (data.index > node.index) {
25117           var x = xi - data.x - data.vx,
25118               y = yi - data.y - data.vy,
25119               l = x * x + y * y;
25120           if (l < r * r) {
25121             if (x === 0) x = jiggle(), l += x * x;
25122             if (y === 0) y = jiggle(), l += y * y;
25123             l = (r - (l = Math.sqrt(l))) / l * strength;
25124             node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
25125             node.vy += (y *= l) * r;
25126             data.vx -= x * (r = 1 - r);
25127             data.vy -= y * r;
25128           }
25129         }
25130         return;
25131       }
25132       return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r;
25133     }
25134   }
25135
25136   function prepare(quad) {
25137     if (quad.data) return quad.r = radii[quad.data.index];
25138     for (var i = quad.r = 0; i < 4; ++i) {
25139       if (quad[i] && quad[i].r > quad.r) {
25140         quad.r = quad[i].r;
25141       }
25142     }
25143   }
25144
25145   function initialize() {
25146     if (!nodes) return;
25147     var i, n = nodes.length, node;
25148     radii = new Array(n);
25149     for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes);
25150   }
25151
25152   force.initialize = function(_) {
25153     nodes = _;
25154     initialize();
25155   };
25156
25157   force.iterations = function(_) {
25158     return arguments.length ? (iterations = +_, force) : iterations;
25159   };
25160
25161   force.strength = function(_) {
25162     return arguments.length ? (strength = +_, force) : strength;
25163   };
25164
25165   force.radius = function(_) {
25166     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : radius;
25167   };
25168
25169   return force;
25170 };
25171
25172 function index$3(d) {
25173   return d.index;
25174 }
25175
25176 function find(nodeById, nodeId) {
25177   var node = nodeById.get(nodeId);
25178   if (!node) throw new Error("missing: " + nodeId);
25179   return node;
25180 }
25181
25182 var link = function(links) {
25183   var id = index$3,
25184       strength = defaultStrength,
25185       strengths,
25186       distance = constant$6(30),
25187       distances,
25188       nodes,
25189       count,
25190       bias,
25191       iterations = 1;
25192
25193   if (links == null) links = [];
25194
25195   function defaultStrength(link) {
25196     return 1 / Math.min(count[link.source.index], count[link.target.index]);
25197   }
25198
25199   function force(alpha) {
25200     for (var k = 0, n = links.length; k < iterations; ++k) {
25201       for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) {
25202         link = links[i], source = link.source, target = link.target;
25203         x = target.x + target.vx - source.x - source.vx || jiggle();
25204         y = target.y + target.vy - source.y - source.vy || jiggle();
25205         l = Math.sqrt(x * x + y * y);
25206         l = (l - distances[i]) / l * alpha * strengths[i];
25207         x *= l, y *= l;
25208         target.vx -= x * (b = bias[i]);
25209         target.vy -= y * b;
25210         source.vx += x * (b = 1 - b);
25211         source.vy += y * b;
25212       }
25213     }
25214   }
25215
25216   function initialize() {
25217     if (!nodes) return;
25218
25219     var i,
25220         n = nodes.length,
25221         m = links.length,
25222         nodeById = map$1(nodes, id),
25223         link;
25224
25225     for (i = 0, count = new Array(n); i < m; ++i) {
25226       link = links[i], link.index = i;
25227       if (typeof link.source !== "object") link.source = find(nodeById, link.source);
25228       if (typeof link.target !== "object") link.target = find(nodeById, link.target);
25229       count[link.source.index] = (count[link.source.index] || 0) + 1;
25230       count[link.target.index] = (count[link.target.index] || 0) + 1;
25231     }
25232
25233     for (i = 0, bias = new Array(m); i < m; ++i) {
25234       link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]);
25235     }
25236
25237     strengths = new Array(m), initializeStrength();
25238     distances = new Array(m), initializeDistance();
25239   }
25240
25241   function initializeStrength() {
25242     if (!nodes) return;
25243
25244     for (var i = 0, n = links.length; i < n; ++i) {
25245       strengths[i] = +strength(links[i], i, links);
25246     }
25247   }
25248
25249   function initializeDistance() {
25250     if (!nodes) return;
25251
25252     for (var i = 0, n = links.length; i < n; ++i) {
25253       distances[i] = +distance(links[i], i, links);
25254     }
25255   }
25256
25257   force.initialize = function(_) {
25258     nodes = _;
25259     initialize();
25260   };
25261
25262   force.links = function(_) {
25263     return arguments.length ? (links = _, initialize(), force) : links;
25264   };
25265
25266   force.id = function(_) {
25267     return arguments.length ? (id = _, force) : id;
25268   };
25269
25270   force.iterations = function(_) {
25271     return arguments.length ? (iterations = +_, force) : iterations;
25272   };
25273
25274   force.strength = function(_) {
25275     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initializeStrength(), force) : strength;
25276   };
25277
25278   force.distance = function(_) {
25279     return arguments.length ? (distance = typeof _ === "function" ? _ : constant$6(+_), initializeDistance(), force) : distance;
25280   };
25281
25282   return force;
25283 };
25284
25285 function x$1(d) {
25286   return d.x;
25287 }
25288
25289 function y$1(d) {
25290   return d.y;
25291 }
25292
25293 var initialRadius = 10;
25294 var initialAngle = Math.PI * (3 - Math.sqrt(5));
25295
25296 var simulation = function(nodes) {
25297   var simulation,
25298       alpha = 1,
25299       alphaMin = 0.001,
25300       alphaDecay = 1 - Math.pow(alphaMin, 1 / 300),
25301       alphaTarget = 0,
25302       velocityDecay = 0.6,
25303       forces = map$1(),
25304       stepper = timer(step),
25305       event = dispatch("tick", "end");
25306
25307   if (nodes == null) nodes = [];
25308
25309   function step() {
25310     tick();
25311     event.call("tick", simulation);
25312     if (alpha < alphaMin) {
25313       stepper.stop();
25314       event.call("end", simulation);
25315     }
25316   }
25317
25318   function tick() {
25319     var i, n = nodes.length, node;
25320
25321     alpha += (alphaTarget - alpha) * alphaDecay;
25322
25323     forces.each(function(force) {
25324       force(alpha);
25325     });
25326
25327     for (i = 0; i < n; ++i) {
25328       node = nodes[i];
25329       if (node.fx == null) node.x += node.vx *= velocityDecay;
25330       else node.x = node.fx, node.vx = 0;
25331       if (node.fy == null) node.y += node.vy *= velocityDecay;
25332       else node.y = node.fy, node.vy = 0;
25333     }
25334   }
25335
25336   function initializeNodes() {
25337     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25338       node = nodes[i], node.index = i;
25339       if (isNaN(node.x) || isNaN(node.y)) {
25340         var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle;
25341         node.x = radius * Math.cos(angle);
25342         node.y = radius * Math.sin(angle);
25343       }
25344       if (isNaN(node.vx) || isNaN(node.vy)) {
25345         node.vx = node.vy = 0;
25346       }
25347     }
25348   }
25349
25350   function initializeForce(force) {
25351     if (force.initialize) force.initialize(nodes);
25352     return force;
25353   }
25354
25355   initializeNodes();
25356
25357   return simulation = {
25358     tick: tick,
25359
25360     restart: function() {
25361       return stepper.restart(step), simulation;
25362     },
25363
25364     stop: function() {
25365       return stepper.stop(), simulation;
25366     },
25367
25368     nodes: function(_) {
25369       return arguments.length ? (nodes = _, initializeNodes(), forces.each(initializeForce), simulation) : nodes;
25370     },
25371
25372     alpha: function(_) {
25373       return arguments.length ? (alpha = +_, simulation) : alpha;
25374     },
25375
25376     alphaMin: function(_) {
25377       return arguments.length ? (alphaMin = +_, simulation) : alphaMin;
25378     },
25379
25380     alphaDecay: function(_) {
25381       return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay;
25382     },
25383
25384     alphaTarget: function(_) {
25385       return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget;
25386     },
25387
25388     velocityDecay: function(_) {
25389       return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay;
25390     },
25391
25392     force: function(name, _) {
25393       return arguments.length > 1 ? ((_ == null ? forces.remove(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name);
25394     },
25395
25396     find: function(x, y, radius) {
25397       var i = 0,
25398           n = nodes.length,
25399           dx,
25400           dy,
25401           d2,
25402           node,
25403           closest;
25404
25405       if (radius == null) radius = Infinity;
25406       else radius *= radius;
25407
25408       for (i = 0; i < n; ++i) {
25409         node = nodes[i];
25410         dx = x - node.x;
25411         dy = y - node.y;
25412         d2 = dx * dx + dy * dy;
25413         if (d2 < radius) closest = node, radius = d2;
25414       }
25415
25416       return closest;
25417     },
25418
25419     on: function(name, _) {
25420       return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name);
25421     }
25422   };
25423 };
25424
25425 var manyBody = function() {
25426   var nodes,
25427       node,
25428       alpha,
25429       strength = constant$6(-30),
25430       strengths,
25431       distanceMin2 = 1,
25432       distanceMax2 = Infinity,
25433       theta2 = 0.81;
25434
25435   function force(_) {
25436     var i, n = nodes.length, tree = quadtree(nodes, x$1, y$1).visitAfter(accumulate);
25437     for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
25438   }
25439
25440   function initialize() {
25441     if (!nodes) return;
25442     var i, n = nodes.length, node;
25443     strengths = new Array(n);
25444     for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes);
25445   }
25446
25447   function accumulate(quad) {
25448     var strength = 0, q, c, x$$1, y$$1, i;
25449
25450     // For internal nodes, accumulate forces from child quadrants.
25451     if (quad.length) {
25452       for (x$$1 = y$$1 = i = 0; i < 4; ++i) {
25453         if ((q = quad[i]) && (c = q.value)) {
25454           strength += c, x$$1 += c * q.x, y$$1 += c * q.y;
25455         }
25456       }
25457       quad.x = x$$1 / strength;
25458       quad.y = y$$1 / strength;
25459     }
25460
25461     // For leaf nodes, accumulate forces from coincident quadrants.
25462     else {
25463       q = quad;
25464       q.x = q.data.x;
25465       q.y = q.data.y;
25466       do strength += strengths[q.data.index];
25467       while (q = q.next);
25468     }
25469
25470     quad.value = strength;
25471   }
25472
25473   function apply(quad, x1, _, x2) {
25474     if (!quad.value) return true;
25475
25476     var x$$1 = quad.x - node.x,
25477         y$$1 = quad.y - node.y,
25478         w = x2 - x1,
25479         l = x$$1 * x$$1 + y$$1 * y$$1;
25480
25481     // Apply the Barnes-Hut approximation if possible.
25482     // Limit forces for very close nodes; randomize direction if coincident.
25483     if (w * w / theta2 < l) {
25484       if (l < distanceMax2) {
25485         if (x$$1 === 0) x$$1 = jiggle(), l += x$$1 * x$$1;
25486         if (y$$1 === 0) y$$1 = jiggle(), l += y$$1 * y$$1;
25487         if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
25488         node.vx += x$$1 * quad.value * alpha / l;
25489         node.vy += y$$1 * quad.value * alpha / l;
25490       }
25491       return true;
25492     }
25493
25494     // Otherwise, process points directly.
25495     else if (quad.length || l >= distanceMax2) return;
25496
25497     // Limit forces for very close nodes; randomize direction if coincident.
25498     if (quad.data !== node || quad.next) {
25499       if (x$$1 === 0) x$$1 = jiggle(), l += x$$1 * x$$1;
25500       if (y$$1 === 0) y$$1 = jiggle(), l += y$$1 * y$$1;
25501       if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
25502     }
25503
25504     do if (quad.data !== node) {
25505       w = strengths[quad.data.index] * alpha / l;
25506       node.vx += x$$1 * w;
25507       node.vy += y$$1 * w;
25508     } while (quad = quad.next);
25509   }
25510
25511   force.initialize = function(_) {
25512     nodes = _;
25513     initialize();
25514   };
25515
25516   force.strength = function(_) {
25517     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25518   };
25519
25520   force.distanceMin = function(_) {
25521     return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
25522   };
25523
25524   force.distanceMax = function(_) {
25525     return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
25526   };
25527
25528   force.theta = function(_) {
25529     return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
25530   };
25531
25532   return force;
25533 };
25534
25535 var x$2 = function(x) {
25536   var strength = constant$6(0.1),
25537       nodes,
25538       strengths,
25539       xz;
25540
25541   if (typeof x !== "function") x = constant$6(x == null ? 0 : +x);
25542
25543   function force(alpha) {
25544     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25545       node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha;
25546     }
25547   }
25548
25549   function initialize() {
25550     if (!nodes) return;
25551     var i, n = nodes.length;
25552     strengths = new Array(n);
25553     xz = new Array(n);
25554     for (i = 0; i < n; ++i) {
25555       strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
25556     }
25557   }
25558
25559   force.initialize = function(_) {
25560     nodes = _;
25561     initialize();
25562   };
25563
25564   force.strength = function(_) {
25565     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25566   };
25567
25568   force.x = function(_) {
25569     return arguments.length ? (x = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : x;
25570   };
25571
25572   return force;
25573 };
25574
25575 var y$2 = function(y) {
25576   var strength = constant$6(0.1),
25577       nodes,
25578       strengths,
25579       yz;
25580
25581   if (typeof y !== "function") y = constant$6(y == null ? 0 : +y);
25582
25583   function force(alpha) {
25584     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25585       node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha;
25586     }
25587   }
25588
25589   function initialize() {
25590     if (!nodes) return;
25591     var i, n = nodes.length;
25592     strengths = new Array(n);
25593     yz = new Array(n);
25594     for (i = 0; i < n; ++i) {
25595       strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
25596     }
25597   }
25598
25599   force.initialize = function(_) {
25600     nodes = _;
25601     initialize();
25602   };
25603
25604   force.strength = function(_) {
25605     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25606   };
25607
25608   force.y = function(_) {
25609     return arguments.length ? (y = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : y;
25610   };
25611
25612   return force;
25613 };
25614
25615 // Computes the decimal coefficient and exponent of the specified number x with
25616 // significant digits p, where x is positive and p is in [1, 21] or undefined.
25617 // For example, formatDecimal(1.23) returns ["123", 0].
25618 var formatDecimal = function(x, p) {
25619   if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
25620   var i, coefficient = x.slice(0, i);
25621
25622   // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
25623   // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
25624   return [
25625     coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
25626     +x.slice(i + 1)
25627   ];
25628 };
25629
25630 var exponent$1 = function(x) {
25631   return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;
25632 };
25633
25634 var formatGroup = function(grouping, thousands) {
25635   return function(value, width) {
25636     var i = value.length,
25637         t = [],
25638         j = 0,
25639         g = grouping[0],
25640         length = 0;
25641
25642     while (i > 0 && g > 0) {
25643       if (length + g + 1 > width) g = Math.max(1, width - length);
25644       t.push(value.substring(i -= g, i + g));
25645       if ((length += g + 1) > width) break;
25646       g = grouping[j = (j + 1) % grouping.length];
25647     }
25648
25649     return t.reverse().join(thousands);
25650   };
25651 };
25652
25653 var formatNumerals = function(numerals) {
25654   return function(value) {
25655     return value.replace(/[0-9]/g, function(i) {
25656       return numerals[+i];
25657     });
25658   };
25659 };
25660
25661 var formatDefault = function(x, p) {
25662   x = x.toPrecision(p);
25663
25664   out: for (var n = x.length, i = 1, i0 = -1, i1; i < n; ++i) {
25665     switch (x[i]) {
25666       case ".": i0 = i1 = i; break;
25667       case "0": if (i0 === 0) i0 = i; i1 = i; break;
25668       case "e": break out;
25669       default: if (i0 > 0) i0 = 0; break;
25670     }
25671   }
25672
25673   return i0 > 0 ? x.slice(0, i0) + x.slice(i1 + 1) : x;
25674 };
25675
25676 var prefixExponent;
25677
25678 var formatPrefixAuto = function(x, p) {
25679   var d = formatDecimal(x, p);
25680   if (!d) return x + "";
25681   var coefficient = d[0],
25682       exponent = d[1],
25683       i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
25684       n = coefficient.length;
25685   return i === n ? coefficient
25686       : i > n ? coefficient + new Array(i - n + 1).join("0")
25687       : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
25688       : "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!
25689 };
25690
25691 var formatRounded = function(x, p) {
25692   var d = formatDecimal(x, p);
25693   if (!d) return x + "";
25694   var coefficient = d[0],
25695       exponent = d[1];
25696   return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
25697       : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
25698       : coefficient + new Array(exponent - coefficient.length + 2).join("0");
25699 };
25700
25701 var formatTypes = {
25702   "": formatDefault,
25703   "%": function(x, p) { return (x * 100).toFixed(p); },
25704   "b": function(x) { return Math.round(x).toString(2); },
25705   "c": function(x) { return x + ""; },
25706   "d": function(x) { return Math.round(x).toString(10); },
25707   "e": function(x, p) { return x.toExponential(p); },
25708   "f": function(x, p) { return x.toFixed(p); },
25709   "g": function(x, p) { return x.toPrecision(p); },
25710   "o": function(x) { return Math.round(x).toString(8); },
25711   "p": function(x, p) { return formatRounded(x * 100, p); },
25712   "r": formatRounded,
25713   "s": formatPrefixAuto,
25714   "X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
25715   "x": function(x) { return Math.round(x).toString(16); }
25716 };
25717
25718 // [[fill]align][sign][symbol][0][width][,][.precision][type]
25719 var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;
25720
25721 function formatSpecifier(specifier) {
25722   return new FormatSpecifier(specifier);
25723 }
25724
25725 formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
25726
25727 function FormatSpecifier(specifier) {
25728   if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
25729
25730   var match,
25731       fill = match[1] || " ",
25732       align = match[2] || ">",
25733       sign = match[3] || "-",
25734       symbol = match[4] || "",
25735       zero = !!match[5],
25736       width = match[6] && +match[6],
25737       comma = !!match[7],
25738       precision = match[8] && +match[8].slice(1),
25739       type = match[9] || "";
25740
25741   // The "n" type is an alias for ",g".
25742   if (type === "n") comma = true, type = "g";
25743
25744   // Map invalid types to the default format.
25745   else if (!formatTypes[type]) type = "";
25746
25747   // If zero fill is specified, padding goes after sign and before digits.
25748   if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
25749
25750   this.fill = fill;
25751   this.align = align;
25752   this.sign = sign;
25753   this.symbol = symbol;
25754   this.zero = zero;
25755   this.width = width;
25756   this.comma = comma;
25757   this.precision = precision;
25758   this.type = type;
25759 }
25760
25761 FormatSpecifier.prototype.toString = function() {
25762   return this.fill
25763       + this.align
25764       + this.sign
25765       + this.symbol
25766       + (this.zero ? "0" : "")
25767       + (this.width == null ? "" : Math.max(1, this.width | 0))
25768       + (this.comma ? "," : "")
25769       + (this.precision == null ? "" : "." + Math.max(0, this.precision | 0))
25770       + this.type;
25771 };
25772
25773 var identity$3 = function(x) {
25774   return x;
25775 };
25776
25777 var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
25778
25779 var formatLocale = function(locale) {
25780   var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity$3,
25781       currency = locale.currency,
25782       decimal = locale.decimal,
25783       numerals = locale.numerals ? formatNumerals(locale.numerals) : identity$3,
25784       percent = locale.percent || "%";
25785
25786   function newFormat(specifier) {
25787     specifier = formatSpecifier(specifier);
25788
25789     var fill = specifier.fill,
25790         align = specifier.align,
25791         sign = specifier.sign,
25792         symbol = specifier.symbol,
25793         zero = specifier.zero,
25794         width = specifier.width,
25795         comma = specifier.comma,
25796         precision = specifier.precision,
25797         type = specifier.type;
25798
25799     // Compute the prefix and suffix.
25800     // For SI-prefix, the suffix is lazily computed.
25801     var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
25802         suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? percent : "";
25803
25804     // What format function should we use?
25805     // Is this an integer type?
25806     // Can this type generate exponential notation?
25807     var formatType = formatTypes[type],
25808         maybeSuffix = !type || /[defgprs%]/.test(type);
25809
25810     // Set the default precision if not specified,
25811     // or clamp the specified precision to the supported range.
25812     // For significant precision, it must be in [1, 21].
25813     // For fixed precision, it must be in [0, 20].
25814     precision = precision == null ? (type ? 6 : 12)
25815         : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
25816         : Math.max(0, Math.min(20, precision));
25817
25818     function format(value) {
25819       var valuePrefix = prefix,
25820           valueSuffix = suffix,
25821           i, n, c;
25822
25823       if (type === "c") {
25824         valueSuffix = formatType(value) + valueSuffix;
25825         value = "";
25826       } else {
25827         value = +value;
25828
25829         // Perform the initial formatting.
25830         var valueNegative = value < 0;
25831         value = formatType(Math.abs(value), precision);
25832
25833         // If a negative value rounds to zero during formatting, treat as positive.
25834         if (valueNegative && +value === 0) valueNegative = false;
25835
25836         // Compute the prefix and suffix.
25837         valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
25838         valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
25839
25840         // Break the formatted value into the integer “value” part that can be
25841         // grouped, and fractional or exponential “suffix” part that is not.
25842         if (maybeSuffix) {
25843           i = -1, n = value.length;
25844           while (++i < n) {
25845             if (c = value.charCodeAt(i), 48 > c || c > 57) {
25846               valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
25847               value = value.slice(0, i);
25848               break;
25849             }
25850           }
25851         }
25852       }
25853
25854       // If the fill character is not "0", grouping is applied before padding.
25855       if (comma && !zero) value = group(value, Infinity);
25856
25857       // Compute the padding.
25858       var length = valuePrefix.length + value.length + valueSuffix.length,
25859           padding = length < width ? new Array(width - length + 1).join(fill) : "";
25860
25861       // If the fill character is "0", grouping is applied after padding.
25862       if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
25863
25864       // Reconstruct the final output based on the desired alignment.
25865       switch (align) {
25866         case "<": value = valuePrefix + value + valueSuffix + padding; break;
25867         case "=": value = valuePrefix + padding + value + valueSuffix; break;
25868         case "^": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;
25869         default: value = padding + valuePrefix + value + valueSuffix; break;
25870       }
25871
25872       return numerals(value);
25873     }
25874
25875     format.toString = function() {
25876       return specifier + "";
25877     };
25878
25879     return format;
25880   }
25881
25882   function formatPrefix(specifier, value) {
25883     var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
25884         e = Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3,
25885         k = Math.pow(10, -e),
25886         prefix = prefixes[8 + e / 3];
25887     return function(value) {
25888       return f(k * value) + prefix;
25889     };
25890   }
25891
25892   return {
25893     format: newFormat,
25894     formatPrefix: formatPrefix
25895   };
25896 };
25897
25898 var locale$1;
25899 var format;
25900 var formatPrefix;
25901
25902 defaultLocale({
25903   decimal: ".",
25904   thousands: ",",
25905   grouping: [3],
25906   currency: ["$", ""]
25907 });
25908
25909 function defaultLocale(definition) {
25910   locale$1 = formatLocale(definition);
25911   format = locale$1.format;
25912   formatPrefix = locale$1.formatPrefix;
25913   return locale$1;
25914 }
25915
25916 var precisionFixed = function(step) {
25917   return Math.max(0, -exponent$1(Math.abs(step)));
25918 };
25919
25920 var precisionPrefix = function(step, value) {
25921   return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3 - exponent$1(Math.abs(step)));
25922 };
25923
25924 var precisionRound = function(step, max) {
25925   step = Math.abs(step), max = Math.abs(max) - step;
25926   return Math.max(0, exponent$1(max) - exponent$1(step)) + 1;
25927 };
25928
25929 // Adds floating point numbers with twice the normal precision.
25930 // Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and
25931 // Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3)
25932 // 305–363 (1997).
25933 // Code adapted from GeographicLib by Charles F. F. Karney,
25934 // http://geographiclib.sourceforge.net/
25935
25936 var adder = function() {
25937   return new Adder;
25938 };
25939
25940 function Adder() {
25941   this.reset();
25942 }
25943
25944 Adder.prototype = {
25945   constructor: Adder,
25946   reset: function() {
25947     this.s = // rounded value
25948     this.t = 0; // exact error
25949   },
25950   add: function(y) {
25951     add$1(temp, y, this.t);
25952     add$1(this, temp.s, this.s);
25953     if (this.s) this.t += temp.t;
25954     else this.s = temp.t;
25955   },
25956   valueOf: function() {
25957     return this.s;
25958   }
25959 };
25960
25961 var temp = new Adder;
25962
25963 function add$1(adder, a, b) {
25964   var x = adder.s = a + b,
25965       bv = x - a,
25966       av = x - bv;
25967   adder.t = (a - av) + (b - bv);
25968 }
25969
25970 var epsilon$2 = 1e-6;
25971 var epsilon2$1 = 1e-12;
25972 var pi$3 = Math.PI;
25973 var halfPi$2 = pi$3 / 2;
25974 var quarterPi = pi$3 / 4;
25975 var tau$3 = pi$3 * 2;
25976
25977 var degrees$1 = 180 / pi$3;
25978 var radians = pi$3 / 180;
25979
25980 var abs = Math.abs;
25981 var atan = Math.atan;
25982 var atan2 = Math.atan2;
25983 var cos$1 = Math.cos;
25984 var ceil = Math.ceil;
25985 var exp = Math.exp;
25986
25987 var log = Math.log;
25988 var pow = Math.pow;
25989 var sin$1 = Math.sin;
25990 var sign = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; };
25991 var sqrt = Math.sqrt;
25992 var tan = Math.tan;
25993
25994 function acos(x) {
25995   return x > 1 ? 0 : x < -1 ? pi$3 : Math.acos(x);
25996 }
25997
25998 function asin(x) {
25999   return x > 1 ? halfPi$2 : x < -1 ? -halfPi$2 : Math.asin(x);
26000 }
26001
26002 function haversin(x) {
26003   return (x = sin$1(x / 2)) * x;
26004 }
26005
26006 function noop$1() {}
26007
26008 function streamGeometry(geometry, stream) {
26009   if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
26010     streamGeometryType[geometry.type](geometry, stream);
26011   }
26012 }
26013
26014 var streamObjectType = {
26015   Feature: function(object, stream) {
26016     streamGeometry(object.geometry, stream);
26017   },
26018   FeatureCollection: function(object, stream) {
26019     var features = object.features, i = -1, n = features.length;
26020     while (++i < n) streamGeometry(features[i].geometry, stream);
26021   }
26022 };
26023
26024 var streamGeometryType = {
26025   Sphere: function(object, stream) {
26026     stream.sphere();
26027   },
26028   Point: function(object, stream) {
26029     object = object.coordinates;
26030     stream.point(object[0], object[1], object[2]);
26031   },
26032   MultiPoint: function(object, stream) {
26033     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26034     while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]);
26035   },
26036   LineString: function(object, stream) {
26037     streamLine(object.coordinates, stream, 0);
26038   },
26039   MultiLineString: function(object, stream) {
26040     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26041     while (++i < n) streamLine(coordinates[i], stream, 0);
26042   },
26043   Polygon: function(object, stream) {
26044     streamPolygon(object.coordinates, stream);
26045   },
26046   MultiPolygon: function(object, stream) {
26047     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26048     while (++i < n) streamPolygon(coordinates[i], stream);
26049   },
26050   GeometryCollection: function(object, stream) {
26051     var geometries = object.geometries, i = -1, n = geometries.length;
26052     while (++i < n) streamGeometry(geometries[i], stream);
26053   }
26054 };
26055
26056 function streamLine(coordinates, stream, closed) {
26057   var i = -1, n = coordinates.length - closed, coordinate;
26058   stream.lineStart();
26059   while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
26060   stream.lineEnd();
26061 }
26062
26063 function streamPolygon(coordinates, stream) {
26064   var i = -1, n = coordinates.length;
26065   stream.polygonStart();
26066   while (++i < n) streamLine(coordinates[i], stream, 1);
26067   stream.polygonEnd();
26068 }
26069
26070 var geoStream = function(object, stream) {
26071   if (object && streamObjectType.hasOwnProperty(object.type)) {
26072     streamObjectType[object.type](object, stream);
26073   } else {
26074     streamGeometry(object, stream);
26075   }
26076 };
26077
26078 var areaRingSum = adder();
26079
26080 var areaSum = adder();
26081 var lambda00;
26082 var phi00;
26083 var lambda0;
26084 var cosPhi0;
26085 var sinPhi0;
26086
26087 var areaStream = {
26088   point: noop$1,
26089   lineStart: noop$1,
26090   lineEnd: noop$1,
26091   polygonStart: function() {
26092     areaRingSum.reset();
26093     areaStream.lineStart = areaRingStart;
26094     areaStream.lineEnd = areaRingEnd;
26095   },
26096   polygonEnd: function() {
26097     var areaRing = +areaRingSum;
26098     areaSum.add(areaRing < 0 ? tau$3 + areaRing : areaRing);
26099     this.lineStart = this.lineEnd = this.point = noop$1;
26100   },
26101   sphere: function() {
26102     areaSum.add(tau$3);
26103   }
26104 };
26105
26106 function areaRingStart() {
26107   areaStream.point = areaPointFirst;
26108 }
26109
26110 function areaRingEnd() {
26111   areaPoint(lambda00, phi00);
26112 }
26113
26114 function areaPointFirst(lambda, phi) {
26115   areaStream.point = areaPoint;
26116   lambda00 = lambda, phi00 = phi;
26117   lambda *= radians, phi *= radians;
26118   lambda0 = lambda, cosPhi0 = cos$1(phi = phi / 2 + quarterPi), sinPhi0 = sin$1(phi);
26119 }
26120
26121 function areaPoint(lambda, phi) {
26122   lambda *= radians, phi *= radians;
26123   phi = phi / 2 + quarterPi; // half the angular distance from south pole
26124
26125   // Spherical excess E for a spherical triangle with vertices: south pole,
26126   // previous point, current point.  Uses a formula derived from Cagnoli’s
26127   // theorem.  See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
26128   var dLambda = lambda - lambda0,
26129       sdLambda = dLambda >= 0 ? 1 : -1,
26130       adLambda = sdLambda * dLambda,
26131       cosPhi = cos$1(phi),
26132       sinPhi = sin$1(phi),
26133       k = sinPhi0 * sinPhi,
26134       u = cosPhi0 * cosPhi + k * cos$1(adLambda),
26135       v = k * sdLambda * sin$1(adLambda);
26136   areaRingSum.add(atan2(v, u));
26137
26138   // Advance the previous points.
26139   lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
26140 }
26141
26142 var area = function(object) {
26143   areaSum.reset();
26144   geoStream(object, areaStream);
26145   return areaSum * 2;
26146 };
26147
26148 function spherical(cartesian) {
26149   return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
26150 }
26151
26152 function cartesian(spherical) {
26153   var lambda = spherical[0], phi = spherical[1], cosPhi = cos$1(phi);
26154   return [cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi)];
26155 }
26156
26157 function cartesianDot(a, b) {
26158   return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
26159 }
26160
26161 function cartesianCross(a, b) {
26162   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]];
26163 }
26164
26165 // TODO return a
26166 function cartesianAddInPlace(a, b) {
26167   a[0] += b[0], a[1] += b[1], a[2] += b[2];
26168 }
26169
26170 function cartesianScale(vector, k) {
26171   return [vector[0] * k, vector[1] * k, vector[2] * k];
26172 }
26173
26174 // TODO return d
26175 function cartesianNormalizeInPlace(d) {
26176   var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
26177   d[0] /= l, d[1] /= l, d[2] /= l;
26178 }
26179
26180 var lambda0$1;
26181 var phi0;
26182 var lambda1;
26183 var phi1;
26184 var lambda2;
26185 var lambda00$1;
26186 var phi00$1;
26187 var p0;
26188 var deltaSum = adder();
26189 var ranges;
26190 var range;
26191
26192 var boundsStream = {
26193   point: boundsPoint,
26194   lineStart: boundsLineStart,
26195   lineEnd: boundsLineEnd,
26196   polygonStart: function() {
26197     boundsStream.point = boundsRingPoint;
26198     boundsStream.lineStart = boundsRingStart;
26199     boundsStream.lineEnd = boundsRingEnd;
26200     deltaSum.reset();
26201     areaStream.polygonStart();
26202   },
26203   polygonEnd: function() {
26204     areaStream.polygonEnd();
26205     boundsStream.point = boundsPoint;
26206     boundsStream.lineStart = boundsLineStart;
26207     boundsStream.lineEnd = boundsLineEnd;
26208     if (areaRingSum < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
26209     else if (deltaSum > epsilon$2) phi1 = 90;
26210     else if (deltaSum < -epsilon$2) phi0 = -90;
26211     range[0] = lambda0$1, range[1] = lambda1;
26212   }
26213 };
26214
26215 function boundsPoint(lambda, phi) {
26216   ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
26217   if (phi < phi0) phi0 = phi;
26218   if (phi > phi1) phi1 = phi;
26219 }
26220
26221 function linePoint(lambda, phi) {
26222   var p = cartesian([lambda * radians, phi * radians]);
26223   if (p0) {
26224     var normal = cartesianCross(p0, p),
26225         equatorial = [normal[1], -normal[0], 0],
26226         inflection = cartesianCross(equatorial, normal);
26227     cartesianNormalizeInPlace(inflection);
26228     inflection = spherical(inflection);
26229     var delta = lambda - lambda2,
26230         sign$$1 = delta > 0 ? 1 : -1,
26231         lambdai = inflection[0] * degrees$1 * sign$$1,
26232         phii,
26233         antimeridian = abs(delta) > 180;
26234     if (antimeridian ^ (sign$$1 * lambda2 < lambdai && lambdai < sign$$1 * lambda)) {
26235       phii = inflection[1] * degrees$1;
26236       if (phii > phi1) phi1 = phii;
26237     } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign$$1 * lambda2 < lambdai && lambdai < sign$$1 * lambda)) {
26238       phii = -inflection[1] * degrees$1;
26239       if (phii < phi0) phi0 = phii;
26240     } else {
26241       if (phi < phi0) phi0 = phi;
26242       if (phi > phi1) phi1 = phi;
26243     }
26244     if (antimeridian) {
26245       if (lambda < lambda2) {
26246         if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
26247       } else {
26248         if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
26249       }
26250     } else {
26251       if (lambda1 >= lambda0$1) {
26252         if (lambda < lambda0$1) lambda0$1 = lambda;
26253         if (lambda > lambda1) lambda1 = lambda;
26254       } else {
26255         if (lambda > lambda2) {
26256           if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
26257         } else {
26258           if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
26259         }
26260       }
26261     }
26262   } else {
26263     ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
26264   }
26265   if (phi < phi0) phi0 = phi;
26266   if (phi > phi1) phi1 = phi;
26267   p0 = p, lambda2 = lambda;
26268 }
26269
26270 function boundsLineStart() {
26271   boundsStream.point = linePoint;
26272 }
26273
26274 function boundsLineEnd() {
26275   range[0] = lambda0$1, range[1] = lambda1;
26276   boundsStream.point = boundsPoint;
26277   p0 = null;
26278 }
26279
26280 function boundsRingPoint(lambda, phi) {
26281   if (p0) {
26282     var delta = lambda - lambda2;
26283     deltaSum.add(abs(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
26284   } else {
26285     lambda00$1 = lambda, phi00$1 = phi;
26286   }
26287   areaStream.point(lambda, phi);
26288   linePoint(lambda, phi);
26289 }
26290
26291 function boundsRingStart() {
26292   areaStream.lineStart();
26293 }
26294
26295 function boundsRingEnd() {
26296   boundsRingPoint(lambda00$1, phi00$1);
26297   areaStream.lineEnd();
26298   if (abs(deltaSum) > epsilon$2) lambda0$1 = -(lambda1 = 180);
26299   range[0] = lambda0$1, range[1] = lambda1;
26300   p0 = null;
26301 }
26302
26303 // Finds the left-right distance between two longitudes.
26304 // This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
26305 // the distance between ±180° to be 360°.
26306 function angle(lambda0, lambda1) {
26307   return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
26308 }
26309
26310 function rangeCompare(a, b) {
26311   return a[0] - b[0];
26312 }
26313
26314 function rangeContains(range, x) {
26315   return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
26316 }
26317
26318 var bounds = function(feature) {
26319   var i, n, a, b, merged, deltaMax, delta;
26320
26321   phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
26322   ranges = [];
26323   geoStream(feature, boundsStream);
26324
26325   // First, sort ranges by their minimum longitudes.
26326   if (n = ranges.length) {
26327     ranges.sort(rangeCompare);
26328
26329     // Then, merge any ranges that overlap.
26330     for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
26331       b = ranges[i];
26332       if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
26333         if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
26334         if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
26335       } else {
26336         merged.push(a = b);
26337       }
26338     }
26339
26340     // Finally, find the largest gap between the merged ranges.
26341     // The final bounding box will be the inverse of this gap.
26342     for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
26343       b = merged[i];
26344       if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
26345     }
26346   }
26347
26348   ranges = range = null;
26349
26350   return lambda0$1 === Infinity || phi0 === Infinity
26351       ? [[NaN, NaN], [NaN, NaN]]
26352       : [[lambda0$1, phi0], [lambda1, phi1]];
26353 };
26354
26355 var W0;
26356 var W1;
26357 var X0;
26358 var Y0;
26359 var Z0;
26360 var X1;
26361 var Y1;
26362 var Z1;
26363 var X2;
26364 var Y2;
26365 var Z2;
26366 var lambda00$2;
26367 var phi00$2;
26368 var x0;
26369 var y0;
26370 var z0; // previous point
26371
26372 var centroidStream = {
26373   sphere: noop$1,
26374   point: centroidPoint,
26375   lineStart: centroidLineStart,
26376   lineEnd: centroidLineEnd,
26377   polygonStart: function() {
26378     centroidStream.lineStart = centroidRingStart;
26379     centroidStream.lineEnd = centroidRingEnd;
26380   },
26381   polygonEnd: function() {
26382     centroidStream.lineStart = centroidLineStart;
26383     centroidStream.lineEnd = centroidLineEnd;
26384   }
26385 };
26386
26387 // Arithmetic mean of Cartesian vectors.
26388 function centroidPoint(lambda, phi) {
26389   lambda *= radians, phi *= radians;
26390   var cosPhi = cos$1(phi);
26391   centroidPointCartesian(cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi));
26392 }
26393
26394 function centroidPointCartesian(x, y, z) {
26395   ++W0;
26396   X0 += (x - X0) / W0;
26397   Y0 += (y - Y0) / W0;
26398   Z0 += (z - Z0) / W0;
26399 }
26400
26401 function centroidLineStart() {
26402   centroidStream.point = centroidLinePointFirst;
26403 }
26404
26405 function centroidLinePointFirst(lambda, phi) {
26406   lambda *= radians, phi *= radians;
26407   var cosPhi = cos$1(phi);
26408   x0 = cosPhi * cos$1(lambda);
26409   y0 = cosPhi * sin$1(lambda);
26410   z0 = sin$1(phi);
26411   centroidStream.point = centroidLinePoint;
26412   centroidPointCartesian(x0, y0, z0);
26413 }
26414
26415 function centroidLinePoint(lambda, phi) {
26416   lambda *= radians, phi *= radians;
26417   var cosPhi = cos$1(phi),
26418       x = cosPhi * cos$1(lambda),
26419       y = cosPhi * sin$1(lambda),
26420       z = sin$1(phi),
26421       w = atan2(sqrt((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
26422   W1 += w;
26423   X1 += w * (x0 + (x0 = x));
26424   Y1 += w * (y0 + (y0 = y));
26425   Z1 += w * (z0 + (z0 = z));
26426   centroidPointCartesian(x0, y0, z0);
26427 }
26428
26429 function centroidLineEnd() {
26430   centroidStream.point = centroidPoint;
26431 }
26432
26433 // See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
26434 // J. Applied Mechanics 42, 239 (1975).
26435 function centroidRingStart() {
26436   centroidStream.point = centroidRingPointFirst;
26437 }
26438
26439 function centroidRingEnd() {
26440   centroidRingPoint(lambda00$2, phi00$2);
26441   centroidStream.point = centroidPoint;
26442 }
26443
26444 function centroidRingPointFirst(lambda, phi) {
26445   lambda00$2 = lambda, phi00$2 = phi;
26446   lambda *= radians, phi *= radians;
26447   centroidStream.point = centroidRingPoint;
26448   var cosPhi = cos$1(phi);
26449   x0 = cosPhi * cos$1(lambda);
26450   y0 = cosPhi * sin$1(lambda);
26451   z0 = sin$1(phi);
26452   centroidPointCartesian(x0, y0, z0);
26453 }
26454
26455 function centroidRingPoint(lambda, phi) {
26456   lambda *= radians, phi *= radians;
26457   var cosPhi = cos$1(phi),
26458       x = cosPhi * cos$1(lambda),
26459       y = cosPhi * sin$1(lambda),
26460       z = sin$1(phi),
26461       cx = y0 * z - z0 * y,
26462       cy = z0 * x - x0 * z,
26463       cz = x0 * y - y0 * x,
26464       m = sqrt(cx * cx + cy * cy + cz * cz),
26465       w = asin(m), // line weight = angle
26466       v = m && -w / m; // area weight multiplier
26467   X2 += v * cx;
26468   Y2 += v * cy;
26469   Z2 += v * cz;
26470   W1 += w;
26471   X1 += w * (x0 + (x0 = x));
26472   Y1 += w * (y0 + (y0 = y));
26473   Z1 += w * (z0 + (z0 = z));
26474   centroidPointCartesian(x0, y0, z0);
26475 }
26476
26477 var d3GeoCentroid = function(object) {
26478   W0 = W1 =
26479   X0 = Y0 = Z0 =
26480   X1 = Y1 = Z1 =
26481   X2 = Y2 = Z2 = 0;
26482   geoStream(object, centroidStream);
26483
26484   var x = X2,
26485       y = Y2,
26486       z = Z2,
26487       m = x * x + y * y + z * z;
26488
26489   // If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
26490   if (m < epsilon2$1) {
26491     x = X1, y = Y1, z = Z1;
26492     // If the feature has zero length, fall back to arithmetic mean of point vectors.
26493     if (W1 < epsilon$2) x = X0, y = Y0, z = Z0;
26494     m = x * x + y * y + z * z;
26495     // If the feature still has an undefined ccentroid, then return.
26496     if (m < epsilon2$1) return [NaN, NaN];
26497   }
26498
26499   return [atan2(y, x) * degrees$1, asin(z / sqrt(m)) * degrees$1];
26500 };
26501
26502 var constant$7 = function(x) {
26503   return function() {
26504     return x;
26505   };
26506 };
26507
26508 var compose = function(a, b) {
26509
26510   function compose(x, y) {
26511     return x = a(x, y), b(x[0], x[1]);
26512   }
26513
26514   if (a.invert && b.invert) compose.invert = function(x, y) {
26515     return x = b.invert(x, y), x && a.invert(x[0], x[1]);
26516   };
26517
26518   return compose;
26519 };
26520
26521 function rotationIdentity(lambda, phi) {
26522   return [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
26523 }
26524
26525 rotationIdentity.invert = rotationIdentity;
26526
26527 function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
26528   return (deltaLambda %= tau$3) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma))
26529     : rotationLambda(deltaLambda))
26530     : (deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma)
26531     : rotationIdentity);
26532 }
26533
26534 function forwardRotationLambda(deltaLambda) {
26535   return function(lambda, phi) {
26536     return lambda += deltaLambda, [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
26537   };
26538 }
26539
26540 function rotationLambda(deltaLambda) {
26541   var rotation = forwardRotationLambda(deltaLambda);
26542   rotation.invert = forwardRotationLambda(-deltaLambda);
26543   return rotation;
26544 }
26545
26546 function rotationPhiGamma(deltaPhi, deltaGamma) {
26547   var cosDeltaPhi = cos$1(deltaPhi),
26548       sinDeltaPhi = sin$1(deltaPhi),
26549       cosDeltaGamma = cos$1(deltaGamma),
26550       sinDeltaGamma = sin$1(deltaGamma);
26551
26552   function rotation(lambda, phi) {
26553     var cosPhi = cos$1(phi),
26554         x = cos$1(lambda) * cosPhi,
26555         y = sin$1(lambda) * cosPhi,
26556         z = sin$1(phi),
26557         k = z * cosDeltaPhi + x * sinDeltaPhi;
26558     return [
26559       atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi),
26560       asin(k * cosDeltaGamma + y * sinDeltaGamma)
26561     ];
26562   }
26563
26564   rotation.invert = function(lambda, phi) {
26565     var cosPhi = cos$1(phi),
26566         x = cos$1(lambda) * cosPhi,
26567         y = sin$1(lambda) * cosPhi,
26568         z = sin$1(phi),
26569         k = z * cosDeltaGamma - y * sinDeltaGamma;
26570     return [
26571       atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi),
26572       asin(k * cosDeltaPhi - x * sinDeltaPhi)
26573     ];
26574   };
26575
26576   return rotation;
26577 }
26578
26579 var rotation = function(rotate) {
26580   rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
26581
26582   function forward(coordinates) {
26583     coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
26584     return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
26585   }
26586
26587   forward.invert = function(coordinates) {
26588     coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
26589     return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
26590   };
26591
26592   return forward;
26593 };
26594
26595 // Generates a circle centered at [0°, 0°], with a given radius and precision.
26596 function circleStream(stream, radius, delta, direction, t0, t1) {
26597   if (!delta) return;
26598   var cosRadius = cos$1(radius),
26599       sinRadius = sin$1(radius),
26600       step = direction * delta;
26601   if (t0 == null) {
26602     t0 = radius + direction * tau$3;
26603     t1 = radius - step / 2;
26604   } else {
26605     t0 = circleRadius(cosRadius, t0);
26606     t1 = circleRadius(cosRadius, t1);
26607     if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau$3;
26608   }
26609   for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
26610     point = spherical([cosRadius, -sinRadius * cos$1(t), -sinRadius * sin$1(t)]);
26611     stream.point(point[0], point[1]);
26612   }
26613 }
26614
26615 // Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
26616 function circleRadius(cosRadius, point) {
26617   point = cartesian(point), point[0] -= cosRadius;
26618   cartesianNormalizeInPlace(point);
26619   var radius = acos(-point[1]);
26620   return ((-point[2] < 0 ? -radius : radius) + tau$3 - epsilon$2) % tau$3;
26621 }
26622
26623 var circle = function() {
26624   var center = constant$7([0, 0]),
26625       radius = constant$7(90),
26626       precision = constant$7(6),
26627       ring,
26628       rotate,
26629       stream = {point: point};
26630
26631   function point(x, y) {
26632     ring.push(x = rotate(x, y));
26633     x[0] *= degrees$1, x[1] *= degrees$1;
26634   }
26635
26636   function circle() {
26637     var c = center.apply(this, arguments),
26638         r = radius.apply(this, arguments) * radians,
26639         p = precision.apply(this, arguments) * radians;
26640     ring = [];
26641     rotate = rotateRadians(-c[0] * radians, -c[1] * radians, 0).invert;
26642     circleStream(stream, r, p, 1);
26643     c = {type: "Polygon", coordinates: [ring]};
26644     ring = rotate = null;
26645     return c;
26646   }
26647
26648   circle.center = function(_) {
26649     return arguments.length ? (center = typeof _ === "function" ? _ : constant$7([+_[0], +_[1]]), circle) : center;
26650   };
26651
26652   circle.radius = function(_) {
26653     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$7(+_), circle) : radius;
26654   };
26655
26656   circle.precision = function(_) {
26657     return arguments.length ? (precision = typeof _ === "function" ? _ : constant$7(+_), circle) : precision;
26658   };
26659
26660   return circle;
26661 };
26662
26663 var clipBuffer = function() {
26664   var lines = [],
26665       line;
26666   return {
26667     point: function(x, y) {
26668       line.push([x, y]);
26669     },
26670     lineStart: function() {
26671       lines.push(line = []);
26672     },
26673     lineEnd: noop$1,
26674     rejoin: function() {
26675       if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
26676     },
26677     result: function() {
26678       var result = lines;
26679       lines = [];
26680       line = null;
26681       return result;
26682     }
26683   };
26684 };
26685
26686 var clipLine = function(a, b, x0, y0, x1, y1) {
26687   var ax = a[0],
26688       ay = a[1],
26689       bx = b[0],
26690       by = b[1],
26691       t0 = 0,
26692       t1 = 1,
26693       dx = bx - ax,
26694       dy = by - ay,
26695       r;
26696
26697   r = x0 - ax;
26698   if (!dx && r > 0) return;
26699   r /= dx;
26700   if (dx < 0) {
26701     if (r < t0) return;
26702     if (r < t1) t1 = r;
26703   } else if (dx > 0) {
26704     if (r > t1) return;
26705     if (r > t0) t0 = r;
26706   }
26707
26708   r = x1 - ax;
26709   if (!dx && r < 0) return;
26710   r /= dx;
26711   if (dx < 0) {
26712     if (r > t1) return;
26713     if (r > t0) t0 = r;
26714   } else if (dx > 0) {
26715     if (r < t0) return;
26716     if (r < t1) t1 = r;
26717   }
26718
26719   r = y0 - ay;
26720   if (!dy && r > 0) return;
26721   r /= dy;
26722   if (dy < 0) {
26723     if (r < t0) return;
26724     if (r < t1) t1 = r;
26725   } else if (dy > 0) {
26726     if (r > t1) return;
26727     if (r > t0) t0 = r;
26728   }
26729
26730   r = y1 - ay;
26731   if (!dy && r < 0) return;
26732   r /= dy;
26733   if (dy < 0) {
26734     if (r > t1) return;
26735     if (r > t0) t0 = r;
26736   } else if (dy > 0) {
26737     if (r < t0) return;
26738     if (r < t1) t1 = r;
26739   }
26740
26741   if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
26742   if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
26743   return true;
26744 };
26745
26746 var pointEqual = function(a, b) {
26747   return abs(a[0] - b[0]) < epsilon$2 && abs(a[1] - b[1]) < epsilon$2;
26748 };
26749
26750 function Intersection(point, points, other, entry) {
26751   this.x = point;
26752   this.z = points;
26753   this.o = other; // another intersection
26754   this.e = entry; // is an entry?
26755   this.v = false; // visited
26756   this.n = this.p = null; // next & previous
26757 }
26758
26759 // A generalized polygon clipping algorithm: given a polygon that has been cut
26760 // into its visible line segments, and rejoins the segments by interpolating
26761 // along the clip edge.
26762 var clipPolygon = function(segments, compareIntersection, startInside, interpolate, stream) {
26763   var subject = [],
26764       clip = [],
26765       i,
26766       n;
26767
26768   segments.forEach(function(segment) {
26769     if ((n = segment.length - 1) <= 0) return;
26770     var n, p0 = segment[0], p1 = segment[n], x;
26771
26772     // If the first and last points of a segment are coincident, then treat as a
26773     // closed ring. TODO if all rings are closed, then the winding order of the
26774     // exterior ring should be checked.
26775     if (pointEqual(p0, p1)) {
26776       stream.lineStart();
26777       for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]);
26778       stream.lineEnd();
26779       return;
26780     }
26781
26782     subject.push(x = new Intersection(p0, segment, null, true));
26783     clip.push(x.o = new Intersection(p0, null, x, false));
26784     subject.push(x = new Intersection(p1, segment, null, false));
26785     clip.push(x.o = new Intersection(p1, null, x, true));
26786   });
26787
26788   if (!subject.length) return;
26789
26790   clip.sort(compareIntersection);
26791   link$1(subject);
26792   link$1(clip);
26793
26794   for (i = 0, n = clip.length; i < n; ++i) {
26795     clip[i].e = startInside = !startInside;
26796   }
26797
26798   var start = subject[0],
26799       points,
26800       point;
26801
26802   while (1) {
26803     // Find first unvisited intersection.
26804     var current = start,
26805         isSubject = true;
26806     while (current.v) if ((current = current.n) === start) return;
26807     points = current.z;
26808     stream.lineStart();
26809     do {
26810       current.v = current.o.v = true;
26811       if (current.e) {
26812         if (isSubject) {
26813           for (i = 0, n = points.length; i < n; ++i) stream.point((point = points[i])[0], point[1]);
26814         } else {
26815           interpolate(current.x, current.n.x, 1, stream);
26816         }
26817         current = current.n;
26818       } else {
26819         if (isSubject) {
26820           points = current.p.z;
26821           for (i = points.length - 1; i >= 0; --i) stream.point((point = points[i])[0], point[1]);
26822         } else {
26823           interpolate(current.x, current.p.x, -1, stream);
26824         }
26825         current = current.p;
26826       }
26827       current = current.o;
26828       points = current.z;
26829       isSubject = !isSubject;
26830     } while (!current.v);
26831     stream.lineEnd();
26832   }
26833 };
26834
26835 function link$1(array) {
26836   if (!(n = array.length)) return;
26837   var n,
26838       i = 0,
26839       a = array[0],
26840       b;
26841   while (++i < n) {
26842     a.n = b = array[i];
26843     b.p = a;
26844     a = b;
26845   }
26846   a.n = b = array[0];
26847   b.p = a;
26848 }
26849
26850 var clipMax = 1e9;
26851 var clipMin = -clipMax;
26852
26853 // TODO Use d3-polygon’s polygonContains here for the ring check?
26854 // TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
26855
26856 function clipExtent(x0, y0, x1, y1) {
26857
26858   function visible(x, y) {
26859     return x0 <= x && x <= x1 && y0 <= y && y <= y1;
26860   }
26861
26862   function interpolate(from, to, direction, stream) {
26863     var a = 0, a1 = 0;
26864     if (from == null
26865         || (a = corner(from, direction)) !== (a1 = corner(to, direction))
26866         || comparePoint(from, to) < 0 ^ direction > 0) {
26867       do stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
26868       while ((a = (a + direction + 4) % 4) !== a1);
26869     } else {
26870       stream.point(to[0], to[1]);
26871     }
26872   }
26873
26874   function corner(p, direction) {
26875     return abs(p[0] - x0) < epsilon$2 ? direction > 0 ? 0 : 3
26876         : abs(p[0] - x1) < epsilon$2 ? direction > 0 ? 2 : 1
26877         : abs(p[1] - y0) < epsilon$2 ? direction > 0 ? 1 : 0
26878         : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
26879   }
26880
26881   function compareIntersection(a, b) {
26882     return comparePoint(a.x, b.x);
26883   }
26884
26885   function comparePoint(a, b) {
26886     var ca = corner(a, 1),
26887         cb = corner(b, 1);
26888     return ca !== cb ? ca - cb
26889         : ca === 0 ? b[1] - a[1]
26890         : ca === 1 ? a[0] - b[0]
26891         : ca === 2 ? a[1] - b[1]
26892         : b[0] - a[0];
26893   }
26894
26895   return function(stream) {
26896     var activeStream = stream,
26897         bufferStream = clipBuffer(),
26898         segments,
26899         polygon,
26900         ring,
26901         x__, y__, v__, // first point
26902         x_, y_, v_, // previous point
26903         first,
26904         clean;
26905
26906     var clipStream = {
26907       point: point,
26908       lineStart: lineStart,
26909       lineEnd: lineEnd,
26910       polygonStart: polygonStart,
26911       polygonEnd: polygonEnd
26912     };
26913
26914     function point(x, y) {
26915       if (visible(x, y)) activeStream.point(x, y);
26916     }
26917
26918     function polygonInside() {
26919       var winding = 0;
26920
26921       for (var i = 0, n = polygon.length; i < n; ++i) {
26922         for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
26923           a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
26924           if (a1 <= y1) { if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding; }
26925           else { if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding; }
26926         }
26927       }
26928
26929       return winding;
26930     }
26931
26932     // Buffer geometry within a polygon and then clip it en masse.
26933     function polygonStart() {
26934       activeStream = bufferStream, segments = [], polygon = [], clean = true;
26935     }
26936
26937     function polygonEnd() {
26938       var startInside = polygonInside(),
26939           cleanInside = clean && startInside,
26940           visible = (segments = merge(segments)).length;
26941       if (cleanInside || visible) {
26942         stream.polygonStart();
26943         if (cleanInside) {
26944           stream.lineStart();
26945           interpolate(null, null, 1, stream);
26946           stream.lineEnd();
26947         }
26948         if (visible) {
26949           clipPolygon(segments, compareIntersection, startInside, interpolate, stream);
26950         }
26951         stream.polygonEnd();
26952       }
26953       activeStream = stream, segments = polygon = ring = null;
26954     }
26955
26956     function lineStart() {
26957       clipStream.point = linePoint;
26958       if (polygon) polygon.push(ring = []);
26959       first = true;
26960       v_ = false;
26961       x_ = y_ = NaN;
26962     }
26963
26964     // TODO rather than special-case polygons, simply handle them separately.
26965     // Ideally, coincident intersection points should be jittered to avoid
26966     // clipping issues.
26967     function lineEnd() {
26968       if (segments) {
26969         linePoint(x__, y__);
26970         if (v__ && v_) bufferStream.rejoin();
26971         segments.push(bufferStream.result());
26972       }
26973       clipStream.point = point;
26974       if (v_) activeStream.lineEnd();
26975     }
26976
26977     function linePoint(x, y) {
26978       var v = visible(x, y);
26979       if (polygon) ring.push([x, y]);
26980       if (first) {
26981         x__ = x, y__ = y, v__ = v;
26982         first = false;
26983         if (v) {
26984           activeStream.lineStart();
26985           activeStream.point(x, y);
26986         }
26987       } else {
26988         if (v && v_) activeStream.point(x, y);
26989         else {
26990           var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
26991               b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
26992           if (clipLine(a, b, x0, y0, x1, y1)) {
26993             if (!v_) {
26994               activeStream.lineStart();
26995               activeStream.point(a[0], a[1]);
26996             }
26997             activeStream.point(b[0], b[1]);
26998             if (!v) activeStream.lineEnd();
26999             clean = false;
27000           } else if (v) {
27001             activeStream.lineStart();
27002             activeStream.point(x, y);
27003             clean = false;
27004           }
27005         }
27006       }
27007       x_ = x, y_ = y, v_ = v;
27008     }
27009
27010     return clipStream;
27011   };
27012 }
27013
27014 var extent$1 = function() {
27015   var x0 = 0,
27016       y0 = 0,
27017       x1 = 960,
27018       y1 = 500,
27019       cache,
27020       cacheStream,
27021       clip;
27022
27023   return clip = {
27024     stream: function(stream) {
27025       return cache && cacheStream === stream ? cache : cache = clipExtent(x0, y0, x1, y1)(cacheStream = stream);
27026     },
27027     extent: function(_) {
27028       return arguments.length ? (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1], cache = cacheStream = null, clip) : [[x0, y0], [x1, y1]];
27029     }
27030   };
27031 };
27032
27033 var sum$1 = adder();
27034
27035 var polygonContains = function(polygon, point) {
27036   var lambda = point[0],
27037       phi = point[1],
27038       normal = [sin$1(lambda), -cos$1(lambda), 0],
27039       angle = 0,
27040       winding = 0;
27041
27042   sum$1.reset();
27043
27044   for (var i = 0, n = polygon.length; i < n; ++i) {
27045     if (!(m = (ring = polygon[i]).length)) continue;
27046     var ring,
27047         m,
27048         point0 = ring[m - 1],
27049         lambda0 = point0[0],
27050         phi0 = point0[1] / 2 + quarterPi,
27051         sinPhi0 = sin$1(phi0),
27052         cosPhi0 = cos$1(phi0);
27053
27054     for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
27055       var point1 = ring[j],
27056           lambda1 = point1[0],
27057           phi1 = point1[1] / 2 + quarterPi,
27058           sinPhi1 = sin$1(phi1),
27059           cosPhi1 = cos$1(phi1),
27060           delta = lambda1 - lambda0,
27061           sign$$1 = delta >= 0 ? 1 : -1,
27062           absDelta = sign$$1 * delta,
27063           antimeridian = absDelta > pi$3,
27064           k = sinPhi0 * sinPhi1;
27065
27066       sum$1.add(atan2(k * sign$$1 * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta)));
27067       angle += antimeridian ? delta + sign$$1 * tau$3 : delta;
27068
27069       // Are the longitudes either side of the point’s meridian (lambda),
27070       // and are the latitudes smaller than the parallel (phi)?
27071       if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
27072         var arc = cartesianCross(cartesian(point0), cartesian(point1));
27073         cartesianNormalizeInPlace(arc);
27074         var intersection = cartesianCross(normal, arc);
27075         cartesianNormalizeInPlace(intersection);
27076         var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
27077         if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
27078           winding += antimeridian ^ delta >= 0 ? 1 : -1;
27079         }
27080       }
27081     }
27082   }
27083
27084   // First, determine whether the South pole is inside or outside:
27085   //
27086   // It is inside if:
27087   // * the polygon winds around it in a clockwise direction.
27088   // * the polygon does not (cumulatively) wind around it, but has a negative
27089   //   (counter-clockwise) area.
27090   //
27091   // Second, count the (signed) number of times a segment crosses a lambda
27092   // from the point to the South pole.  If it is zero, then the point is the
27093   // same side as the South pole.
27094
27095   return (angle < -epsilon$2 || angle < epsilon$2 && sum$1 < -epsilon$2) ^ (winding & 1);
27096 };
27097
27098 var lengthSum = adder();
27099 var lambda0$2;
27100 var sinPhi0$1;
27101 var cosPhi0$1;
27102
27103 var lengthStream = {
27104   sphere: noop$1,
27105   point: noop$1,
27106   lineStart: lengthLineStart,
27107   lineEnd: noop$1,
27108   polygonStart: noop$1,
27109   polygonEnd: noop$1
27110 };
27111
27112 function lengthLineStart() {
27113   lengthStream.point = lengthPointFirst;
27114   lengthStream.lineEnd = lengthLineEnd;
27115 }
27116
27117 function lengthLineEnd() {
27118   lengthStream.point = lengthStream.lineEnd = noop$1;
27119 }
27120
27121 function lengthPointFirst(lambda, phi) {
27122   lambda *= radians, phi *= radians;
27123   lambda0$2 = lambda, sinPhi0$1 = sin$1(phi), cosPhi0$1 = cos$1(phi);
27124   lengthStream.point = lengthPoint;
27125 }
27126
27127 function lengthPoint(lambda, phi) {
27128   lambda *= radians, phi *= radians;
27129   var sinPhi = sin$1(phi),
27130       cosPhi = cos$1(phi),
27131       delta = abs(lambda - lambda0$2),
27132       cosDelta = cos$1(delta),
27133       sinDelta = sin$1(delta),
27134       x = cosPhi * sinDelta,
27135       y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta,
27136       z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta;
27137   lengthSum.add(atan2(sqrt(x * x + y * y), z));
27138   lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi;
27139 }
27140
27141 var d3GeoLength = function(object) {
27142   lengthSum.reset();
27143   geoStream(object, lengthStream);
27144   return +lengthSum;
27145 };
27146
27147 var coordinates = [null, null];
27148 var object$1 = {type: "LineString", coordinates: coordinates};
27149
27150 var distance = function(a, b) {
27151   coordinates[0] = a;
27152   coordinates[1] = b;
27153   return d3GeoLength(object$1);
27154 };
27155
27156 var containsObjectType = {
27157   Feature: function(object, point) {
27158     return containsGeometry(object.geometry, point);
27159   },
27160   FeatureCollection: function(object, point) {
27161     var features = object.features, i = -1, n = features.length;
27162     while (++i < n) if (containsGeometry(features[i].geometry, point)) return true;
27163     return false;
27164   }
27165 };
27166
27167 var containsGeometryType = {
27168   Sphere: function() {
27169     return true;
27170   },
27171   Point: function(object, point) {
27172     return containsPoint(object.coordinates, point);
27173   },
27174   MultiPoint: function(object, point) {
27175     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27176     while (++i < n) if (containsPoint(coordinates[i], point)) return true;
27177     return false;
27178   },
27179   LineString: function(object, point) {
27180     return containsLine(object.coordinates, point);
27181   },
27182   MultiLineString: function(object, point) {
27183     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27184     while (++i < n) if (containsLine(coordinates[i], point)) return true;
27185     return false;
27186   },
27187   Polygon: function(object, point) {
27188     return containsPolygon(object.coordinates, point);
27189   },
27190   MultiPolygon: function(object, point) {
27191     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27192     while (++i < n) if (containsPolygon(coordinates[i], point)) return true;
27193     return false;
27194   },
27195   GeometryCollection: function(object, point) {
27196     var geometries = object.geometries, i = -1, n = geometries.length;
27197     while (++i < n) if (containsGeometry(geometries[i], point)) return true;
27198     return false;
27199   }
27200 };
27201
27202 function containsGeometry(geometry, point) {
27203   return geometry && containsGeometryType.hasOwnProperty(geometry.type)
27204       ? containsGeometryType[geometry.type](geometry, point)
27205       : false;
27206 }
27207
27208 function containsPoint(coordinates, point) {
27209   return distance(coordinates, point) === 0;
27210 }
27211
27212 function containsLine(coordinates, point) {
27213   var ab = distance(coordinates[0], coordinates[1]),
27214       ao = distance(coordinates[0], point),
27215       ob = distance(point, coordinates[1]);
27216   return ao + ob <= ab + epsilon$2;
27217 }
27218
27219 function containsPolygon(coordinates, point) {
27220   return !!polygonContains(coordinates.map(ringRadians), pointRadians(point));
27221 }
27222
27223 function ringRadians(ring) {
27224   return ring = ring.map(pointRadians), ring.pop(), ring;
27225 }
27226
27227 function pointRadians(point) {
27228   return [point[0] * radians, point[1] * radians];
27229 }
27230
27231 var contains = function(object, point) {
27232   return (object && containsObjectType.hasOwnProperty(object.type)
27233       ? containsObjectType[object.type]
27234       : containsGeometry)(object, point);
27235 };
27236
27237 function graticuleX(y0, y1, dy) {
27238   var y = sequence(y0, y1 - epsilon$2, dy).concat(y1);
27239   return function(x) { return y.map(function(y) { return [x, y]; }); };
27240 }
27241
27242 function graticuleY(x0, x1, dx) {
27243   var x = sequence(x0, x1 - epsilon$2, dx).concat(x1);
27244   return function(y) { return x.map(function(x) { return [x, y]; }); };
27245 }
27246
27247 function graticule() {
27248   var x1, x0, X1, X0,
27249       y1, y0, Y1, Y0,
27250       dx = 10, dy = dx, DX = 90, DY = 360,
27251       x, y, X, Y,
27252       precision = 2.5;
27253
27254   function graticule() {
27255     return {type: "MultiLineString", coordinates: lines()};
27256   }
27257
27258   function lines() {
27259     return sequence(ceil(X0 / DX) * DX, X1, DX).map(X)
27260         .concat(sequence(ceil(Y0 / DY) * DY, Y1, DY).map(Y))
27261         .concat(sequence(ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return abs(x % DX) > epsilon$2; }).map(x))
27262         .concat(sequence(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs(y % DY) > epsilon$2; }).map(y));
27263   }
27264
27265   graticule.lines = function() {
27266     return lines().map(function(coordinates) { return {type: "LineString", coordinates: coordinates}; });
27267   };
27268
27269   graticule.outline = function() {
27270     return {
27271       type: "Polygon",
27272       coordinates: [
27273         X(X0).concat(
27274         Y(Y1).slice(1),
27275         X(X1).reverse().slice(1),
27276         Y(Y0).reverse().slice(1))
27277       ]
27278     };
27279   };
27280
27281   graticule.extent = function(_) {
27282     if (!arguments.length) return graticule.extentMinor();
27283     return graticule.extentMajor(_).extentMinor(_);
27284   };
27285
27286   graticule.extentMajor = function(_) {
27287     if (!arguments.length) return [[X0, Y0], [X1, Y1]];
27288     X0 = +_[0][0], X1 = +_[1][0];
27289     Y0 = +_[0][1], Y1 = +_[1][1];
27290     if (X0 > X1) _ = X0, X0 = X1, X1 = _;
27291     if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
27292     return graticule.precision(precision);
27293   };
27294
27295   graticule.extentMinor = function(_) {
27296     if (!arguments.length) return [[x0, y0], [x1, y1]];
27297     x0 = +_[0][0], x1 = +_[1][0];
27298     y0 = +_[0][1], y1 = +_[1][1];
27299     if (x0 > x1) _ = x0, x0 = x1, x1 = _;
27300     if (y0 > y1) _ = y0, y0 = y1, y1 = _;
27301     return graticule.precision(precision);
27302   };
27303
27304   graticule.step = function(_) {
27305     if (!arguments.length) return graticule.stepMinor();
27306     return graticule.stepMajor(_).stepMinor(_);
27307   };
27308
27309   graticule.stepMajor = function(_) {
27310     if (!arguments.length) return [DX, DY];
27311     DX = +_[0], DY = +_[1];
27312     return graticule;
27313   };
27314
27315   graticule.stepMinor = function(_) {
27316     if (!arguments.length) return [dx, dy];
27317     dx = +_[0], dy = +_[1];
27318     return graticule;
27319   };
27320
27321   graticule.precision = function(_) {
27322     if (!arguments.length) return precision;
27323     precision = +_;
27324     x = graticuleX(y0, y1, 90);
27325     y = graticuleY(x0, x1, precision);
27326     X = graticuleX(Y0, Y1, 90);
27327     Y = graticuleY(X0, X1, precision);
27328     return graticule;
27329   };
27330
27331   return graticule
27332       .extentMajor([[-180, -90 + epsilon$2], [180, 90 - epsilon$2]])
27333       .extentMinor([[-180, -80 - epsilon$2], [180, 80 + epsilon$2]]);
27334 }
27335
27336 function graticule10() {
27337   return graticule()();
27338 }
27339
27340 var interpolate$1 = function(a, b) {
27341   var x0 = a[0] * radians,
27342       y0 = a[1] * radians,
27343       x1 = b[0] * radians,
27344       y1 = b[1] * radians,
27345       cy0 = cos$1(y0),
27346       sy0 = sin$1(y0),
27347       cy1 = cos$1(y1),
27348       sy1 = sin$1(y1),
27349       kx0 = cy0 * cos$1(x0),
27350       ky0 = cy0 * sin$1(x0),
27351       kx1 = cy1 * cos$1(x1),
27352       ky1 = cy1 * sin$1(x1),
27353       d = 2 * asin(sqrt(haversin(y1 - y0) + cy0 * cy1 * haversin(x1 - x0))),
27354       k = sin$1(d);
27355
27356   var interpolate = d ? function(t) {
27357     var B = sin$1(t *= d) / k,
27358         A = sin$1(d - t) / k,
27359         x = A * kx0 + B * kx1,
27360         y = A * ky0 + B * ky1,
27361         z = A * sy0 + B * sy1;
27362     return [
27363       atan2(y, x) * degrees$1,
27364       atan2(z, sqrt(x * x + y * y)) * degrees$1
27365     ];
27366   } : function() {
27367     return [x0 * degrees$1, y0 * degrees$1];
27368   };
27369
27370   interpolate.distance = d;
27371
27372   return interpolate;
27373 };
27374
27375 var identity$4 = function(x) {
27376   return x;
27377 };
27378
27379 var areaSum$1 = adder();
27380 var areaRingSum$1 = adder();
27381 var x00;
27382 var y00;
27383 var x0$1;
27384 var y0$1;
27385
27386 var areaStream$1 = {
27387   point: noop$1,
27388   lineStart: noop$1,
27389   lineEnd: noop$1,
27390   polygonStart: function() {
27391     areaStream$1.lineStart = areaRingStart$1;
27392     areaStream$1.lineEnd = areaRingEnd$1;
27393   },
27394   polygonEnd: function() {
27395     areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop$1;
27396     areaSum$1.add(abs(areaRingSum$1));
27397     areaRingSum$1.reset();
27398   },
27399   result: function() {
27400     var area = areaSum$1 / 2;
27401     areaSum$1.reset();
27402     return area;
27403   }
27404 };
27405
27406 function areaRingStart$1() {
27407   areaStream$1.point = areaPointFirst$1;
27408 }
27409
27410 function areaPointFirst$1(x, y) {
27411   areaStream$1.point = areaPoint$1;
27412   x00 = x0$1 = x, y00 = y0$1 = y;
27413 }
27414
27415 function areaPoint$1(x, y) {
27416   areaRingSum$1.add(y0$1 * x - x0$1 * y);
27417   x0$1 = x, y0$1 = y;
27418 }
27419
27420 function areaRingEnd$1() {
27421   areaPoint$1(x00, y00);
27422 }
27423
27424 var x0$2 = Infinity;
27425 var y0$2 = x0$2;
27426 var x1 = -x0$2;
27427 var y1 = x1;
27428
27429 var boundsStream$1 = {
27430   point: boundsPoint$1,
27431   lineStart: noop$1,
27432   lineEnd: noop$1,
27433   polygonStart: noop$1,
27434   polygonEnd: noop$1,
27435   result: function() {
27436     var bounds = [[x0$2, y0$2], [x1, y1]];
27437     x1 = y1 = -(y0$2 = x0$2 = Infinity);
27438     return bounds;
27439   }
27440 };
27441
27442 function boundsPoint$1(x, y) {
27443   if (x < x0$2) x0$2 = x;
27444   if (x > x1) x1 = x;
27445   if (y < y0$2) y0$2 = y;
27446   if (y > y1) y1 = y;
27447 }
27448
27449 // TODO Enforce positive area for exterior, negative area for interior?
27450
27451 var X0$1 = 0;
27452 var Y0$1 = 0;
27453 var Z0$1 = 0;
27454 var X1$1 = 0;
27455 var Y1$1 = 0;
27456 var Z1$1 = 0;
27457 var X2$1 = 0;
27458 var Y2$1 = 0;
27459 var Z2$1 = 0;
27460 var x00$1;
27461 var y00$1;
27462 var x0$3;
27463 var y0$3;
27464
27465 var centroidStream$1 = {
27466   point: centroidPoint$1,
27467   lineStart: centroidLineStart$1,
27468   lineEnd: centroidLineEnd$1,
27469   polygonStart: function() {
27470     centroidStream$1.lineStart = centroidRingStart$1;
27471     centroidStream$1.lineEnd = centroidRingEnd$1;
27472   },
27473   polygonEnd: function() {
27474     centroidStream$1.point = centroidPoint$1;
27475     centroidStream$1.lineStart = centroidLineStart$1;
27476     centroidStream$1.lineEnd = centroidLineEnd$1;
27477   },
27478   result: function() {
27479     var centroid = Z2$1 ? [X2$1 / Z2$1, Y2$1 / Z2$1]
27480         : Z1$1 ? [X1$1 / Z1$1, Y1$1 / Z1$1]
27481         : Z0$1 ? [X0$1 / Z0$1, Y0$1 / Z0$1]
27482         : [NaN, NaN];
27483     X0$1 = Y0$1 = Z0$1 =
27484     X1$1 = Y1$1 = Z1$1 =
27485     X2$1 = Y2$1 = Z2$1 = 0;
27486     return centroid;
27487   }
27488 };
27489
27490 function centroidPoint$1(x, y) {
27491   X0$1 += x;
27492   Y0$1 += y;
27493   ++Z0$1;
27494 }
27495
27496 function centroidLineStart$1() {
27497   centroidStream$1.point = centroidPointFirstLine;
27498 }
27499
27500 function centroidPointFirstLine(x, y) {
27501   centroidStream$1.point = centroidPointLine;
27502   centroidPoint$1(x0$3 = x, y0$3 = y);
27503 }
27504
27505 function centroidPointLine(x, y) {
27506   var dx = x - x0$3, dy = y - y0$3, z = sqrt(dx * dx + dy * dy);
27507   X1$1 += z * (x0$3 + x) / 2;
27508   Y1$1 += z * (y0$3 + y) / 2;
27509   Z1$1 += z;
27510   centroidPoint$1(x0$3 = x, y0$3 = y);
27511 }
27512
27513 function centroidLineEnd$1() {
27514   centroidStream$1.point = centroidPoint$1;
27515 }
27516
27517 function centroidRingStart$1() {
27518   centroidStream$1.point = centroidPointFirstRing;
27519 }
27520
27521 function centroidRingEnd$1() {
27522   centroidPointRing(x00$1, y00$1);
27523 }
27524
27525 function centroidPointFirstRing(x, y) {
27526   centroidStream$1.point = centroidPointRing;
27527   centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y);
27528 }
27529
27530 function centroidPointRing(x, y) {
27531   var dx = x - x0$3,
27532       dy = y - y0$3,
27533       z = sqrt(dx * dx + dy * dy);
27534
27535   X1$1 += z * (x0$3 + x) / 2;
27536   Y1$1 += z * (y0$3 + y) / 2;
27537   Z1$1 += z;
27538
27539   z = y0$3 * x - x0$3 * y;
27540   X2$1 += z * (x0$3 + x);
27541   Y2$1 += z * (y0$3 + y);
27542   Z2$1 += z * 3;
27543   centroidPoint$1(x0$3 = x, y0$3 = y);
27544 }
27545
27546 function PathContext(context) {
27547   this._context = context;
27548 }
27549
27550 PathContext.prototype = {
27551   _radius: 4.5,
27552   pointRadius: function(_) {
27553     return this._radius = _, this;
27554   },
27555   polygonStart: function() {
27556     this._line = 0;
27557   },
27558   polygonEnd: function() {
27559     this._line = NaN;
27560   },
27561   lineStart: function() {
27562     this._point = 0;
27563   },
27564   lineEnd: function() {
27565     if (this._line === 0) this._context.closePath();
27566     this._point = NaN;
27567   },
27568   point: function(x, y) {
27569     switch (this._point) {
27570       case 0: {
27571         this._context.moveTo(x, y);
27572         this._point = 1;
27573         break;
27574       }
27575       case 1: {
27576         this._context.lineTo(x, y);
27577         break;
27578       }
27579       default: {
27580         this._context.moveTo(x + this._radius, y);
27581         this._context.arc(x, y, this._radius, 0, tau$3);
27582         break;
27583       }
27584     }
27585   },
27586   result: noop$1
27587 };
27588
27589 var lengthSum$1 = adder();
27590 var lengthRing;
27591 var x00$2;
27592 var y00$2;
27593 var x0$4;
27594 var y0$4;
27595
27596 var lengthStream$1 = {
27597   point: noop$1,
27598   lineStart: function() {
27599     lengthStream$1.point = lengthPointFirst$1;
27600   },
27601   lineEnd: function() {
27602     if (lengthRing) lengthPoint$1(x00$2, y00$2);
27603     lengthStream$1.point = noop$1;
27604   },
27605   polygonStart: function() {
27606     lengthRing = true;
27607   },
27608   polygonEnd: function() {
27609     lengthRing = null;
27610   },
27611   result: function() {
27612     var length = +lengthSum$1;
27613     lengthSum$1.reset();
27614     return length;
27615   }
27616 };
27617
27618 function lengthPointFirst$1(x, y) {
27619   lengthStream$1.point = lengthPoint$1;
27620   x00$2 = x0$4 = x, y00$2 = y0$4 = y;
27621 }
27622
27623 function lengthPoint$1(x, y) {
27624   x0$4 -= x, y0$4 -= y;
27625   lengthSum$1.add(sqrt(x0$4 * x0$4 + y0$4 * y0$4));
27626   x0$4 = x, y0$4 = y;
27627 }
27628
27629 function PathString() {
27630   this._string = [];
27631 }
27632
27633 PathString.prototype = {
27634   _circle: circle$1(4.5),
27635   pointRadius: function(_) {
27636     return this._circle = circle$1(_), this;
27637   },
27638   polygonStart: function() {
27639     this._line = 0;
27640   },
27641   polygonEnd: function() {
27642     this._line = NaN;
27643   },
27644   lineStart: function() {
27645     this._point = 0;
27646   },
27647   lineEnd: function() {
27648     if (this._line === 0) this._string.push("Z");
27649     this._point = NaN;
27650   },
27651   point: function(x, y) {
27652     switch (this._point) {
27653       case 0: {
27654         this._string.push("M", x, ",", y);
27655         this._point = 1;
27656         break;
27657       }
27658       case 1: {
27659         this._string.push("L", x, ",", y);
27660         break;
27661       }
27662       default: {
27663         this._string.push("M", x, ",", y, this._circle);
27664         break;
27665       }
27666     }
27667   },
27668   result: function() {
27669     if (this._string.length) {
27670       var result = this._string.join("");
27671       this._string = [];
27672       return result;
27673     }
27674   }
27675 };
27676
27677 function circle$1(radius) {
27678   return "m0," + radius
27679       + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius
27680       + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius
27681       + "z";
27682 }
27683
27684 var index$4 = function(projection, context) {
27685   var pointRadius = 4.5,
27686       projectionStream,
27687       contextStream;
27688
27689   function path(object) {
27690     if (object) {
27691       if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
27692       geoStream(object, projectionStream(contextStream));
27693     }
27694     return contextStream.result();
27695   }
27696
27697   path.area = function(object) {
27698     geoStream(object, projectionStream(areaStream$1));
27699     return areaStream$1.result();
27700   };
27701
27702   path.measure = function(object) {
27703     geoStream(object, projectionStream(lengthStream$1));
27704     return lengthStream$1.result();
27705   };
27706
27707   path.bounds = function(object) {
27708     geoStream(object, projectionStream(boundsStream$1));
27709     return boundsStream$1.result();
27710   };
27711
27712   path.centroid = function(object) {
27713     geoStream(object, projectionStream(centroidStream$1));
27714     return centroidStream$1.result();
27715   };
27716
27717   path.projection = function(_) {
27718     return arguments.length ? (projectionStream = _ == null ? (projection = null, identity$4) : (projection = _).stream, path) : projection;
27719   };
27720
27721   path.context = function(_) {
27722     if (!arguments.length) return context;
27723     contextStream = _ == null ? (context = null, new PathString) : new PathContext(context = _);
27724     if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
27725     return path;
27726   };
27727
27728   path.pointRadius = function(_) {
27729     if (!arguments.length) return pointRadius;
27730     pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
27731     return path;
27732   };
27733
27734   return path.projection(projection).context(context);
27735 };
27736
27737 var clip = function(pointVisible, clipLine, interpolate, start) {
27738   return function(rotate, sink) {
27739     var line = clipLine(sink),
27740         rotatedStart = rotate.invert(start[0], start[1]),
27741         ringBuffer = clipBuffer(),
27742         ringSink = clipLine(ringBuffer),
27743         polygonStarted = false,
27744         polygon,
27745         segments,
27746         ring;
27747
27748     var clip = {
27749       point: point,
27750       lineStart: lineStart,
27751       lineEnd: lineEnd,
27752       polygonStart: function() {
27753         clip.point = pointRing;
27754         clip.lineStart = ringStart;
27755         clip.lineEnd = ringEnd;
27756         segments = [];
27757         polygon = [];
27758       },
27759       polygonEnd: function() {
27760         clip.point = point;
27761         clip.lineStart = lineStart;
27762         clip.lineEnd = lineEnd;
27763         segments = merge(segments);
27764         var startInside = polygonContains(polygon, rotatedStart);
27765         if (segments.length) {
27766           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27767           clipPolygon(segments, compareIntersection, startInside, interpolate, sink);
27768         } else if (startInside) {
27769           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27770           sink.lineStart();
27771           interpolate(null, null, 1, sink);
27772           sink.lineEnd();
27773         }
27774         if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
27775         segments = polygon = null;
27776       },
27777       sphere: function() {
27778         sink.polygonStart();
27779         sink.lineStart();
27780         interpolate(null, null, 1, sink);
27781         sink.lineEnd();
27782         sink.polygonEnd();
27783       }
27784     };
27785
27786     function point(lambda, phi) {
27787       var point = rotate(lambda, phi);
27788       if (pointVisible(lambda = point[0], phi = point[1])) sink.point(lambda, phi);
27789     }
27790
27791     function pointLine(lambda, phi) {
27792       var point = rotate(lambda, phi);
27793       line.point(point[0], point[1]);
27794     }
27795
27796     function lineStart() {
27797       clip.point = pointLine;
27798       line.lineStart();
27799     }
27800
27801     function lineEnd() {
27802       clip.point = point;
27803       line.lineEnd();
27804     }
27805
27806     function pointRing(lambda, phi) {
27807       ring.push([lambda, phi]);
27808       var point = rotate(lambda, phi);
27809       ringSink.point(point[0], point[1]);
27810     }
27811
27812     function ringStart() {
27813       ringSink.lineStart();
27814       ring = [];
27815     }
27816
27817     function ringEnd() {
27818       pointRing(ring[0][0], ring[0][1]);
27819       ringSink.lineEnd();
27820
27821       var clean = ringSink.clean(),
27822           ringSegments = ringBuffer.result(),
27823           i, n = ringSegments.length, m,
27824           segment,
27825           point;
27826
27827       ring.pop();
27828       polygon.push(ring);
27829       ring = null;
27830
27831       if (!n) return;
27832
27833       // No intersections.
27834       if (clean & 1) {
27835         segment = ringSegments[0];
27836         if ((m = segment.length - 1) > 0) {
27837           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27838           sink.lineStart();
27839           for (i = 0; i < m; ++i) sink.point((point = segment[i])[0], point[1]);
27840           sink.lineEnd();
27841         }
27842         return;
27843       }
27844
27845       // Rejoin connected segments.
27846       // TODO reuse ringBuffer.rejoin()?
27847       if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
27848
27849       segments.push(ringSegments.filter(validSegment));
27850     }
27851
27852     return clip;
27853   };
27854 };
27855
27856 function validSegment(segment) {
27857   return segment.length > 1;
27858 }
27859
27860 // Intersections are sorted along the clip edge. For both antimeridian cutting
27861 // and circle clipping, the same comparison is used.
27862 function compareIntersection(a, b) {
27863   return ((a = a.x)[0] < 0 ? a[1] - halfPi$2 - epsilon$2 : halfPi$2 - a[1])
27864        - ((b = b.x)[0] < 0 ? b[1] - halfPi$2 - epsilon$2 : halfPi$2 - b[1]);
27865 }
27866
27867 var clipAntimeridian = clip(
27868   function() { return true; },
27869   clipAntimeridianLine,
27870   clipAntimeridianInterpolate,
27871   [-pi$3, -halfPi$2]
27872 );
27873
27874 // Takes a line and cuts into visible segments. Return values: 0 - there were
27875 // intersections or the line was empty; 1 - no intersections; 2 - there were
27876 // intersections, and the first and last segments should be rejoined.
27877 function clipAntimeridianLine(stream) {
27878   var lambda0 = NaN,
27879       phi0 = NaN,
27880       sign0 = NaN,
27881       clean; // no intersections
27882
27883   return {
27884     lineStart: function() {
27885       stream.lineStart();
27886       clean = 1;
27887     },
27888     point: function(lambda1, phi1) {
27889       var sign1 = lambda1 > 0 ? pi$3 : -pi$3,
27890           delta = abs(lambda1 - lambda0);
27891       if (abs(delta - pi$3) < epsilon$2) { // line crosses a pole
27892         stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi$2 : -halfPi$2);
27893         stream.point(sign0, phi0);
27894         stream.lineEnd();
27895         stream.lineStart();
27896         stream.point(sign1, phi0);
27897         stream.point(lambda1, phi0);
27898         clean = 0;
27899       } else if (sign0 !== sign1 && delta >= pi$3) { // line crosses antimeridian
27900         if (abs(lambda0 - sign0) < epsilon$2) lambda0 -= sign0 * epsilon$2; // handle degeneracies
27901         if (abs(lambda1 - sign1) < epsilon$2) lambda1 -= sign1 * epsilon$2;
27902         phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
27903         stream.point(sign0, phi0);
27904         stream.lineEnd();
27905         stream.lineStart();
27906         stream.point(sign1, phi0);
27907         clean = 0;
27908       }
27909       stream.point(lambda0 = lambda1, phi0 = phi1);
27910       sign0 = sign1;
27911     },
27912     lineEnd: function() {
27913       stream.lineEnd();
27914       lambda0 = phi0 = NaN;
27915     },
27916     clean: function() {
27917       return 2 - clean; // if intersections, rejoin first and last segments
27918     }
27919   };
27920 }
27921
27922 function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
27923   var cosPhi0,
27924       cosPhi1,
27925       sinLambda0Lambda1 = sin$1(lambda0 - lambda1);
27926   return abs(sinLambda0Lambda1) > epsilon$2
27927       ? atan((sin$1(phi0) * (cosPhi1 = cos$1(phi1)) * sin$1(lambda1)
27928           - sin$1(phi1) * (cosPhi0 = cos$1(phi0)) * sin$1(lambda0))
27929           / (cosPhi0 * cosPhi1 * sinLambda0Lambda1))
27930       : (phi0 + phi1) / 2;
27931 }
27932
27933 function clipAntimeridianInterpolate(from, to, direction, stream) {
27934   var phi;
27935   if (from == null) {
27936     phi = direction * halfPi$2;
27937     stream.point(-pi$3, phi);
27938     stream.point(0, phi);
27939     stream.point(pi$3, phi);
27940     stream.point(pi$3, 0);
27941     stream.point(pi$3, -phi);
27942     stream.point(0, -phi);
27943     stream.point(-pi$3, -phi);
27944     stream.point(-pi$3, 0);
27945     stream.point(-pi$3, phi);
27946   } else if (abs(from[0] - to[0]) > epsilon$2) {
27947     var lambda = from[0] < to[0] ? pi$3 : -pi$3;
27948     phi = direction * lambda / 2;
27949     stream.point(-lambda, phi);
27950     stream.point(0, phi);
27951     stream.point(lambda, phi);
27952   } else {
27953     stream.point(to[0], to[1]);
27954   }
27955 }
27956
27957 var clipCircle = function(radius, delta) {
27958   var cr = cos$1(radius),
27959       smallRadius = cr > 0,
27960       notHemisphere = abs(cr) > epsilon$2; // TODO optimise for this common case
27961
27962   function interpolate(from, to, direction, stream) {
27963     circleStream(stream, radius, delta, direction, from, to);
27964   }
27965
27966   function visible(lambda, phi) {
27967     return cos$1(lambda) * cos$1(phi) > cr;
27968   }
27969
27970   // Takes a line and cuts into visible segments. Return values used for polygon
27971   // clipping: 0 - there were intersections or the line was empty; 1 - no
27972   // intersections 2 - there were intersections, and the first and last segments
27973   // should be rejoined.
27974   function clipLine(stream) {
27975     var point0, // previous point
27976         c0, // code for previous point
27977         v0, // visibility of previous point
27978         v00, // visibility of first point
27979         clean; // no intersections
27980     return {
27981       lineStart: function() {
27982         v00 = v0 = false;
27983         clean = 1;
27984       },
27985       point: function(lambda, phi) {
27986         var point1 = [lambda, phi],
27987             point2,
27988             v = visible(lambda, phi),
27989             c = smallRadius
27990               ? v ? 0 : code(lambda, phi)
27991               : v ? code(lambda + (lambda < 0 ? pi$3 : -pi$3), phi) : 0;
27992         if (!point0 && (v00 = v0 = v)) stream.lineStart();
27993         // Handle degeneracies.
27994         // TODO ignore if not clipping polygons.
27995         if (v !== v0) {
27996           point2 = intersect(point0, point1);
27997           if (pointEqual(point0, point2) || pointEqual(point1, point2)) {
27998             point1[0] += epsilon$2;
27999             point1[1] += epsilon$2;
28000             v = visible(point1[0], point1[1]);
28001           }
28002         }
28003         if (v !== v0) {
28004           clean = 0;
28005           if (v) {
28006             // outside going in
28007             stream.lineStart();
28008             point2 = intersect(point1, point0);
28009             stream.point(point2[0], point2[1]);
28010           } else {
28011             // inside going out
28012             point2 = intersect(point0, point1);
28013             stream.point(point2[0], point2[1]);
28014             stream.lineEnd();
28015           }
28016           point0 = point2;
28017         } else if (notHemisphere && point0 && smallRadius ^ v) {
28018           var t;
28019           // If the codes for two points are different, or are both zero,
28020           // and there this segment intersects with the small circle.
28021           if (!(c & c0) && (t = intersect(point1, point0, true))) {
28022             clean = 0;
28023             if (smallRadius) {
28024               stream.lineStart();
28025               stream.point(t[0][0], t[0][1]);
28026               stream.point(t[1][0], t[1][1]);
28027               stream.lineEnd();
28028             } else {
28029               stream.point(t[1][0], t[1][1]);
28030               stream.lineEnd();
28031               stream.lineStart();
28032               stream.point(t[0][0], t[0][1]);
28033             }
28034           }
28035         }
28036         if (v && (!point0 || !pointEqual(point0, point1))) {
28037           stream.point(point1[0], point1[1]);
28038         }
28039         point0 = point1, v0 = v, c0 = c;
28040       },
28041       lineEnd: function() {
28042         if (v0) stream.lineEnd();
28043         point0 = null;
28044       },
28045       // Rejoin first and last segments if there were intersections and the first
28046       // and last points were visible.
28047       clean: function() {
28048         return clean | ((v00 && v0) << 1);
28049       }
28050     };
28051   }
28052
28053   // Intersects the great circle between a and b with the clip circle.
28054   function intersect(a, b, two) {
28055     var pa = cartesian(a),
28056         pb = cartesian(b);
28057
28058     // We have two planes, n1.p = d1 and n2.p = d2.
28059     // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
28060     var n1 = [1, 0, 0], // normal
28061         n2 = cartesianCross(pa, pb),
28062         n2n2 = cartesianDot(n2, n2),
28063         n1n2 = n2[0], // cartesianDot(n1, n2),
28064         determinant = n2n2 - n1n2 * n1n2;
28065
28066     // Two polar points.
28067     if (!determinant) return !two && a;
28068
28069     var c1 =  cr * n2n2 / determinant,
28070         c2 = -cr * n1n2 / determinant,
28071         n1xn2 = cartesianCross(n1, n2),
28072         A = cartesianScale(n1, c1),
28073         B = cartesianScale(n2, c2);
28074     cartesianAddInPlace(A, B);
28075
28076     // Solve |p(t)|^2 = 1.
28077     var u = n1xn2,
28078         w = cartesianDot(A, u),
28079         uu = cartesianDot(u, u),
28080         t2 = w * w - uu * (cartesianDot(A, A) - 1);
28081
28082     if (t2 < 0) return;
28083
28084     var t = sqrt(t2),
28085         q = cartesianScale(u, (-w - t) / uu);
28086     cartesianAddInPlace(q, A);
28087     q = spherical(q);
28088
28089     if (!two) return q;
28090
28091     // Two intersection points.
28092     var lambda0 = a[0],
28093         lambda1 = b[0],
28094         phi0 = a[1],
28095         phi1 = b[1],
28096         z;
28097
28098     if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
28099
28100     var delta = lambda1 - lambda0,
28101         polar = abs(delta - pi$3) < epsilon$2,
28102         meridian = polar || delta < epsilon$2;
28103
28104     if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z;
28105
28106     // Check that the first point is between a and b.
28107     if (meridian
28108         ? polar
28109           ? phi0 + phi1 > 0 ^ q[1] < (abs(q[0] - lambda0) < epsilon$2 ? phi0 : phi1)
28110           : phi0 <= q[1] && q[1] <= phi1
28111         : delta > pi$3 ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
28112       var q1 = cartesianScale(u, (-w + t) / uu);
28113       cartesianAddInPlace(q1, A);
28114       return [q, spherical(q1)];
28115     }
28116   }
28117
28118   // Generates a 4-bit vector representing the location of a point relative to
28119   // the small circle's bounding box.
28120   function code(lambda, phi) {
28121     var r = smallRadius ? radius : pi$3 - radius,
28122         code = 0;
28123     if (lambda < -r) code |= 1; // left
28124     else if (lambda > r) code |= 2; // right
28125     if (phi < -r) code |= 4; // below
28126     else if (phi > r) code |= 8; // above
28127     return code;
28128   }
28129
28130   return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi$3, radius - pi$3]);
28131 };
28132
28133 var transform = function(methods) {
28134   return {
28135     stream: transformer(methods)
28136   };
28137 };
28138
28139 function transformer(methods) {
28140   return function(stream) {
28141     var s = new TransformStream;
28142     for (var key in methods) s[key] = methods[key];
28143     s.stream = stream;
28144     return s;
28145   };
28146 }
28147
28148 function TransformStream() {}
28149
28150 TransformStream.prototype = {
28151   constructor: TransformStream,
28152   point: function(x, y) { this.stream.point(x, y); },
28153   sphere: function() { this.stream.sphere(); },
28154   lineStart: function() { this.stream.lineStart(); },
28155   lineEnd: function() { this.stream.lineEnd(); },
28156   polygonStart: function() { this.stream.polygonStart(); },
28157   polygonEnd: function() { this.stream.polygonEnd(); }
28158 };
28159
28160 function fitExtent(projection, extent, object) {
28161   var w = extent[1][0] - extent[0][0],
28162       h = extent[1][1] - extent[0][1],
28163       clip = projection.clipExtent && projection.clipExtent();
28164
28165   projection
28166       .scale(150)
28167       .translate([0, 0]);
28168
28169   if (clip != null) projection.clipExtent(null);
28170
28171   geoStream(object, projection.stream(boundsStream$1));
28172
28173   var b = boundsStream$1.result(),
28174       k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
28175       x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
28176       y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
28177
28178   if (clip != null) projection.clipExtent(clip);
28179
28180   return projection
28181       .scale(k * 150)
28182       .translate([x, y]);
28183 }
28184
28185 function fitSize(projection, size, object) {
28186   return fitExtent(projection, [[0, 0], size], object);
28187 }
28188
28189 var maxDepth = 16;
28190 var cosMinDistance = cos$1(30 * radians); // cos(minimum angular distance)
28191
28192 var resample = function(project, delta2) {
28193   return +delta2 ? resample$1(project, delta2) : resampleNone(project);
28194 };
28195
28196 function resampleNone(project) {
28197   return transformer({
28198     point: function(x, y) {
28199       x = project(x, y);
28200       this.stream.point(x[0], x[1]);
28201     }
28202   });
28203 }
28204
28205 function resample$1(project, delta2) {
28206
28207   function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
28208     var dx = x1 - x0,
28209         dy = y1 - y0,
28210         d2 = dx * dx + dy * dy;
28211     if (d2 > 4 * delta2 && depth--) {
28212       var a = a0 + a1,
28213           b = b0 + b1,
28214           c = c0 + c1,
28215           m = sqrt(a * a + b * b + c * c),
28216           phi2 = asin(c /= m),
28217           lambda2 = abs(abs(c) - 1) < epsilon$2 || abs(lambda0 - lambda1) < epsilon$2 ? (lambda0 + lambda1) / 2 : atan2(b, a),
28218           p = project(lambda2, phi2),
28219           x2 = p[0],
28220           y2 = p[1],
28221           dx2 = x2 - x0,
28222           dy2 = y2 - y0,
28223           dz = dy * dx2 - dx * dy2;
28224       if (dz * dz / d2 > delta2 // perpendicular projected distance
28225           || abs((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
28226           || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
28227         resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
28228         stream.point(x2, y2);
28229         resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
28230       }
28231     }
28232   }
28233   return function(stream) {
28234     var lambda00, x00, y00, a00, b00, c00, // first point
28235         lambda0, x0, y0, a0, b0, c0; // previous point
28236
28237     var resampleStream = {
28238       point: point,
28239       lineStart: lineStart,
28240       lineEnd: lineEnd,
28241       polygonStart: function() { stream.polygonStart(); resampleStream.lineStart = ringStart; },
28242       polygonEnd: function() { stream.polygonEnd(); resampleStream.lineStart = lineStart; }
28243     };
28244
28245     function point(x, y) {
28246       x = project(x, y);
28247       stream.point(x[0], x[1]);
28248     }
28249
28250     function lineStart() {
28251       x0 = NaN;
28252       resampleStream.point = linePoint;
28253       stream.lineStart();
28254     }
28255
28256     function linePoint(lambda, phi) {
28257       var c = cartesian([lambda, phi]), p = project(lambda, phi);
28258       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);
28259       stream.point(x0, y0);
28260     }
28261
28262     function lineEnd() {
28263       resampleStream.point = point;
28264       stream.lineEnd();
28265     }
28266
28267     function ringStart() {
28268       lineStart();
28269       resampleStream.point = ringPoint;
28270       resampleStream.lineEnd = ringEnd;
28271     }
28272
28273     function ringPoint(lambda, phi) {
28274       linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
28275       resampleStream.point = linePoint;
28276     }
28277
28278     function ringEnd() {
28279       resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
28280       resampleStream.lineEnd = lineEnd;
28281       lineEnd();
28282     }
28283
28284     return resampleStream;
28285   };
28286 }
28287
28288 var transformRadians = transformer({
28289   point: function(x, y) {
28290     this.stream.point(x * radians, y * radians);
28291   }
28292 });
28293
28294 function projection(project) {
28295   return projectionMutator(function() { return project; })();
28296 }
28297
28298 function projectionMutator(projectAt) {
28299   var project,
28300       k = 150, // scale
28301       x = 480, y = 250, // translate
28302       dx, dy, lambda = 0, phi = 0, // center
28303       deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, projectRotate, // rotate
28304       theta = null, preclip = clipAntimeridian, // clip angle
28305       x0 = null, y0, x1, y1, postclip = identity$4, // clip extent
28306       delta2 = 0.5, projectResample = resample(projectTransform, delta2), // precision
28307       cache,
28308       cacheStream;
28309
28310   function projection(point) {
28311     point = projectRotate(point[0] * radians, point[1] * radians);
28312     return [point[0] * k + dx, dy - point[1] * k];
28313   }
28314
28315   function invert(point) {
28316     point = projectRotate.invert((point[0] - dx) / k, (dy - point[1]) / k);
28317     return point && [point[0] * degrees$1, point[1] * degrees$1];
28318   }
28319
28320   function projectTransform(x, y) {
28321     return x = project(x, y), [x[0] * k + dx, dy - x[1] * k];
28322   }
28323
28324   projection.stream = function(stream) {
28325     return cache && cacheStream === stream ? cache : cache = transformRadians(preclip(rotate, projectResample(postclip(cacheStream = stream))));
28326   };
28327
28328   projection.clipAngle = function(_) {
28329     return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians, 6 * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees$1;
28330   };
28331
28332   projection.clipExtent = function(_) {
28333     return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$4) : clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
28334   };
28335
28336   projection.scale = function(_) {
28337     return arguments.length ? (k = +_, recenter()) : k;
28338   };
28339
28340   projection.translate = function(_) {
28341     return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
28342   };
28343
28344   projection.center = function(_) {
28345     return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees$1, phi * degrees$1];
28346   };
28347
28348   projection.rotate = function(_) {
28349     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];
28350   };
28351
28352   projection.precision = function(_) {
28353     return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
28354   };
28355
28356   projection.fitExtent = function(extent, object) {
28357     return fitExtent(projection, extent, object);
28358   };
28359
28360   projection.fitSize = function(size, object) {
28361     return fitSize(projection, size, object);
28362   };
28363
28364   function recenter() {
28365     projectRotate = compose(rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma), project);
28366     var center = project(lambda, phi);
28367     dx = x - center[0] * k;
28368     dy = y + center[1] * k;
28369     return reset();
28370   }
28371
28372   function reset() {
28373     cache = cacheStream = null;
28374     return projection;
28375   }
28376
28377   return function() {
28378     project = projectAt.apply(this, arguments);
28379     projection.invert = project.invert && invert;
28380     return recenter();
28381   };
28382 }
28383
28384 function conicProjection(projectAt) {
28385   var phi0 = 0,
28386       phi1 = pi$3 / 3,
28387       m = projectionMutator(projectAt),
28388       p = m(phi0, phi1);
28389
28390   p.parallels = function(_) {
28391     return arguments.length ? m(phi0 = _[0] * radians, phi1 = _[1] * radians) : [phi0 * degrees$1, phi1 * degrees$1];
28392   };
28393
28394   return p;
28395 }
28396
28397 function cylindricalEqualAreaRaw(phi0) {
28398   var cosPhi0 = cos$1(phi0);
28399
28400   function forward(lambda, phi) {
28401     return [lambda * cosPhi0, sin$1(phi) / cosPhi0];
28402   }
28403
28404   forward.invert = function(x, y) {
28405     return [x / cosPhi0, asin(y * cosPhi0)];
28406   };
28407
28408   return forward;
28409 }
28410
28411 function conicEqualAreaRaw(y0, y1) {
28412   var sy0 = sin$1(y0), n = (sy0 + sin$1(y1)) / 2;
28413
28414   // Are the parallels symmetrical around the Equator?
28415   if (abs(n) < epsilon$2) return cylindricalEqualAreaRaw(y0);
28416
28417   var c = 1 + sy0 * (2 * n - sy0), r0 = sqrt(c) / n;
28418
28419   function project(x, y) {
28420     var r = sqrt(c - 2 * n * sin$1(y)) / n;
28421     return [r * sin$1(x *= n), r0 - r * cos$1(x)];
28422   }
28423
28424   project.invert = function(x, y) {
28425     var r0y = r0 - y;
28426     return [atan2(x, abs(r0y)) / n * sign(r0y), asin((c - (x * x + r0y * r0y) * n * n) / (2 * n))];
28427   };
28428
28429   return project;
28430 }
28431
28432 var conicEqualArea = function() {
28433   return conicProjection(conicEqualAreaRaw)
28434       .scale(155.424)
28435       .center([0, 33.6442]);
28436 };
28437
28438 var albers = function() {
28439   return conicEqualArea()
28440       .parallels([29.5, 45.5])
28441       .scale(1070)
28442       .translate([480, 250])
28443       .rotate([96, 0])
28444       .center([-0.6, 38.7]);
28445 };
28446
28447 // The projections must have mutually exclusive clip regions on the sphere,
28448 // as this will avoid emitting interleaving lines and polygons.
28449 function multiplex(streams) {
28450   var n = streams.length;
28451   return {
28452     point: function(x, y) { var i = -1; while (++i < n) streams[i].point(x, y); },
28453     sphere: function() { var i = -1; while (++i < n) streams[i].sphere(); },
28454     lineStart: function() { var i = -1; while (++i < n) streams[i].lineStart(); },
28455     lineEnd: function() { var i = -1; while (++i < n) streams[i].lineEnd(); },
28456     polygonStart: function() { var i = -1; while (++i < n) streams[i].polygonStart(); },
28457     polygonEnd: function() { var i = -1; while (++i < n) streams[i].polygonEnd(); }
28458   };
28459 }
28460
28461 // A composite projection for the United States, configured by default for
28462 // 960×500. The projection also works quite well at 960×600 if you change the
28463 // scale to 1285 and adjust the translate accordingly. The set of standard
28464 // parallels for each region comes from USGS, which is published here:
28465 // http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers
28466 var albersUsa = function() {
28467   var cache,
28468       cacheStream,
28469       lower48 = albers(), lower48Point,
28470       alaska = conicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]), alaskaPoint, // EPSG:3338
28471       hawaii = conicEqualArea().rotate([157, 0]).center([-3, 19.9]).parallels([8, 18]), hawaiiPoint, // ESRI:102007
28472       point, pointStream = {point: function(x, y) { point = [x, y]; }};
28473
28474   function albersUsa(coordinates) {
28475     var x = coordinates[0], y = coordinates[1];
28476     return point = null,
28477         (lower48Point.point(x, y), point)
28478         || (alaskaPoint.point(x, y), point)
28479         || (hawaiiPoint.point(x, y), point);
28480   }
28481
28482   albersUsa.invert = function(coordinates) {
28483     var k = lower48.scale(),
28484         t = lower48.translate(),
28485         x = (coordinates[0] - t[0]) / k,
28486         y = (coordinates[1] - t[1]) / k;
28487     return (y >= 0.120 && y < 0.234 && x >= -0.425 && x < -0.214 ? alaska
28488         : y >= 0.166 && y < 0.234 && x >= -0.214 && x < -0.115 ? hawaii
28489         : lower48).invert(coordinates);
28490   };
28491
28492   albersUsa.stream = function(stream) {
28493     return cache && cacheStream === stream ? cache : cache = multiplex([lower48.stream(cacheStream = stream), alaska.stream(stream), hawaii.stream(stream)]);
28494   };
28495
28496   albersUsa.precision = function(_) {
28497     if (!arguments.length) return lower48.precision();
28498     lower48.precision(_), alaska.precision(_), hawaii.precision(_);
28499     return reset();
28500   };
28501
28502   albersUsa.scale = function(_) {
28503     if (!arguments.length) return lower48.scale();
28504     lower48.scale(_), alaska.scale(_ * 0.35), hawaii.scale(_);
28505     return albersUsa.translate(lower48.translate());
28506   };
28507
28508   albersUsa.translate = function(_) {
28509     if (!arguments.length) return lower48.translate();
28510     var k = lower48.scale(), x = +_[0], y = +_[1];
28511
28512     lower48Point = lower48
28513         .translate(_)
28514         .clipExtent([[x - 0.455 * k, y - 0.238 * k], [x + 0.455 * k, y + 0.238 * k]])
28515         .stream(pointStream);
28516
28517     alaskaPoint = alaska
28518         .translate([x - 0.307 * k, y + 0.201 * k])
28519         .clipExtent([[x - 0.425 * k + epsilon$2, y + 0.120 * k + epsilon$2], [x - 0.214 * k - epsilon$2, y + 0.234 * k - epsilon$2]])
28520         .stream(pointStream);
28521
28522     hawaiiPoint = hawaii
28523         .translate([x - 0.205 * k, y + 0.212 * k])
28524         .clipExtent([[x - 0.214 * k + epsilon$2, y + 0.166 * k + epsilon$2], [x - 0.115 * k - epsilon$2, y + 0.234 * k - epsilon$2]])
28525         .stream(pointStream);
28526
28527     return reset();
28528   };
28529
28530   albersUsa.fitExtent = function(extent, object) {
28531     return fitExtent(albersUsa, extent, object);
28532   };
28533
28534   albersUsa.fitSize = function(size, object) {
28535     return fitSize(albersUsa, size, object);
28536   };
28537
28538   function reset() {
28539     cache = cacheStream = null;
28540     return albersUsa;
28541   }
28542
28543   return albersUsa.scale(1070);
28544 };
28545
28546 function azimuthalRaw(scale) {
28547   return function(x, y) {
28548     var cx = cos$1(x),
28549         cy = cos$1(y),
28550         k = scale(cx * cy);
28551     return [
28552       k * cy * sin$1(x),
28553       k * sin$1(y)
28554     ];
28555   }
28556 }
28557
28558 function azimuthalInvert(angle) {
28559   return function(x, y) {
28560     var z = sqrt(x * x + y * y),
28561         c = angle(z),
28562         sc = sin$1(c),
28563         cc = cos$1(c);
28564     return [
28565       atan2(x * sc, z * cc),
28566       asin(z && y * sc / z)
28567     ];
28568   }
28569 }
28570
28571 var azimuthalEqualAreaRaw = azimuthalRaw(function(cxcy) {
28572   return sqrt(2 / (1 + cxcy));
28573 });
28574
28575 azimuthalEqualAreaRaw.invert = azimuthalInvert(function(z) {
28576   return 2 * asin(z / 2);
28577 });
28578
28579 var azimuthalEqualArea = function() {
28580   return projection(azimuthalEqualAreaRaw)
28581       .scale(124.75)
28582       .clipAngle(180 - 1e-3);
28583 };
28584
28585 var azimuthalEquidistantRaw = azimuthalRaw(function(c) {
28586   return (c = acos(c)) && c / sin$1(c);
28587 });
28588
28589 azimuthalEquidistantRaw.invert = azimuthalInvert(function(z) {
28590   return z;
28591 });
28592
28593 var azimuthalEquidistant = function() {
28594   return projection(azimuthalEquidistantRaw)
28595       .scale(79.4188)
28596       .clipAngle(180 - 1e-3);
28597 };
28598
28599 function mercatorRaw(lambda, phi) {
28600   return [lambda, log(tan((halfPi$2 + phi) / 2))];
28601 }
28602
28603 mercatorRaw.invert = function(x, y) {
28604   return [x, 2 * atan(exp(y)) - halfPi$2];
28605 };
28606
28607 var mercator = function() {
28608   return mercatorProjection(mercatorRaw)
28609       .scale(961 / tau$3);
28610 };
28611
28612 function mercatorProjection(project) {
28613   var m = projection(project),
28614       center = m.center,
28615       scale = m.scale,
28616       translate = m.translate,
28617       clipExtent = m.clipExtent,
28618       x0 = null, y0, x1, y1; // clip extent
28619
28620   m.scale = function(_) {
28621     return arguments.length ? (scale(_), reclip()) : scale();
28622   };
28623
28624   m.translate = function(_) {
28625     return arguments.length ? (translate(_), reclip()) : translate();
28626   };
28627
28628   m.center = function(_) {
28629     return arguments.length ? (center(_), reclip()) : center();
28630   };
28631
28632   m.clipExtent = function(_) {
28633     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]];
28634   };
28635
28636   function reclip() {
28637     var k = pi$3 * scale(),
28638         t = m(rotation(m.rotate()).invert([0, 0]));
28639     return clipExtent(x0 == null
28640         ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw
28641         ? [[Math.max(t[0] - k, x0), y0], [Math.min(t[0] + k, x1), y1]]
28642         : [[x0, Math.max(t[1] - k, y0)], [x1, Math.min(t[1] + k, y1)]]);
28643   }
28644
28645   return reclip();
28646 }
28647
28648 function tany(y) {
28649   return tan((halfPi$2 + y) / 2);
28650 }
28651
28652 function conicConformalRaw(y0, y1) {
28653   var cy0 = cos$1(y0),
28654       n = y0 === y1 ? sin$1(y0) : log(cy0 / cos$1(y1)) / log(tany(y1) / tany(y0)),
28655       f = cy0 * pow(tany(y0), n) / n;
28656
28657   if (!n) return mercatorRaw;
28658
28659   function project(x, y) {
28660     if (f > 0) { if (y < -halfPi$2 + epsilon$2) y = -halfPi$2 + epsilon$2; }
28661     else { if (y > halfPi$2 - epsilon$2) y = halfPi$2 - epsilon$2; }
28662     var r = f / pow(tany(y), n);
28663     return [r * sin$1(n * x), f - r * cos$1(n * x)];
28664   }
28665
28666   project.invert = function(x, y) {
28667     var fy = f - y, r = sign(n) * sqrt(x * x + fy * fy);
28668     return [atan2(x, abs(fy)) / n * sign(fy), 2 * atan(pow(f / r, 1 / n)) - halfPi$2];
28669   };
28670
28671   return project;
28672 }
28673
28674 var conicConformal = function() {
28675   return conicProjection(conicConformalRaw)
28676       .scale(109.5)
28677       .parallels([30, 30]);
28678 };
28679
28680 function equirectangularRaw(lambda, phi) {
28681   return [lambda, phi];
28682 }
28683
28684 equirectangularRaw.invert = equirectangularRaw;
28685
28686 var equirectangular = function() {
28687   return projection(equirectangularRaw)
28688       .scale(152.63);
28689 };
28690
28691 function conicEquidistantRaw(y0, y1) {
28692   var cy0 = cos$1(y0),
28693       n = y0 === y1 ? sin$1(y0) : (cy0 - cos$1(y1)) / (y1 - y0),
28694       g = cy0 / n + y0;
28695
28696   if (abs(n) < epsilon$2) return equirectangularRaw;
28697
28698   function project(x, y) {
28699     var gy = g - y, nx = n * x;
28700     return [gy * sin$1(nx), g - gy * cos$1(nx)];
28701   }
28702
28703   project.invert = function(x, y) {
28704     var gy = g - y;
28705     return [atan2(x, abs(gy)) / n * sign(gy), g - sign(n) * sqrt(x * x + gy * gy)];
28706   };
28707
28708   return project;
28709 }
28710
28711 var conicEquidistant = function() {
28712   return conicProjection(conicEquidistantRaw)
28713       .scale(131.154)
28714       .center([0, 13.9389]);
28715 };
28716
28717 function gnomonicRaw(x, y) {
28718   var cy = cos$1(y), k = cos$1(x) * cy;
28719   return [cy * sin$1(x) / k, sin$1(y) / k];
28720 }
28721
28722 gnomonicRaw.invert = azimuthalInvert(atan);
28723
28724 var gnomonic = function() {
28725   return projection(gnomonicRaw)
28726       .scale(144.049)
28727       .clipAngle(60);
28728 };
28729
28730 function scaleTranslate(kx, ky, tx, ty) {
28731   return kx === 1 && ky === 1 && tx === 0 && ty === 0 ? identity$4 : transformer({
28732     point: function(x, y) {
28733       this.stream.point(x * kx + tx, y * ky + ty);
28734     }
28735   });
28736 }
28737
28738 var identity$5 = function() {
28739   var k = 1, tx = 0, ty = 0, sx = 1, sy = 1, transform = identity$4, // scale, translate and reflect
28740       x0 = null, y0, x1, y1, clip = identity$4, // clip extent
28741       cache,
28742       cacheStream,
28743       projection;
28744
28745   function reset() {
28746     cache = cacheStream = null;
28747     return projection;
28748   }
28749
28750   return projection = {
28751     stream: function(stream) {
28752       return cache && cacheStream === stream ? cache : cache = transform(clip(cacheStream = stream));
28753     },
28754     clipExtent: function(_) {
28755       return arguments.length ? (clip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$4) : clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
28756     },
28757     scale: function(_) {
28758       return arguments.length ? (transform = scaleTranslate((k = +_) * sx, k * sy, tx, ty), reset()) : k;
28759     },
28760     translate: function(_) {
28761       return arguments.length ? (transform = scaleTranslate(k * sx, k * sy, tx = +_[0], ty = +_[1]), reset()) : [tx, ty];
28762     },
28763     reflectX: function(_) {
28764       return arguments.length ? (transform = scaleTranslate(k * (sx = _ ? -1 : 1), k * sy, tx, ty), reset()) : sx < 0;
28765     },
28766     reflectY: function(_) {
28767       return arguments.length ? (transform = scaleTranslate(k * sx, k * (sy = _ ? -1 : 1), tx, ty), reset()) : sy < 0;
28768     },
28769     fitExtent: function(extent, object) {
28770       return fitExtent(projection, extent, object);
28771     },
28772     fitSize: function(size, object) {
28773       return fitSize(projection, size, object);
28774     }
28775   };
28776 };
28777
28778 function orthographicRaw(x, y) {
28779   return [cos$1(y) * sin$1(x), sin$1(y)];
28780 }
28781
28782 orthographicRaw.invert = azimuthalInvert(asin);
28783
28784 var orthographic = function() {
28785   return projection(orthographicRaw)
28786       .scale(249.5)
28787       .clipAngle(90 + epsilon$2);
28788 };
28789
28790 function stereographicRaw(x, y) {
28791   var cy = cos$1(y), k = 1 + cos$1(x) * cy;
28792   return [cy * sin$1(x) / k, sin$1(y) / k];
28793 }
28794
28795 stereographicRaw.invert = azimuthalInvert(function(z) {
28796   return 2 * atan(z);
28797 });
28798
28799 var stereographic = function() {
28800   return projection(stereographicRaw)
28801       .scale(250)
28802       .clipAngle(142);
28803 };
28804
28805 function transverseMercatorRaw(lambda, phi) {
28806   return [log(tan((halfPi$2 + phi) / 2)), -lambda];
28807 }
28808
28809 transverseMercatorRaw.invert = function(x, y) {
28810   return [-y, 2 * atan(exp(x)) - halfPi$2];
28811 };
28812
28813 var transverseMercator = function() {
28814   var m = mercatorProjection(transverseMercatorRaw),
28815       center = m.center,
28816       rotate = m.rotate;
28817
28818   m.center = function(_) {
28819     return arguments.length ? center([-_[1], _[0]]) : (_ = center(), [_[1], -_[0]]);
28820   };
28821
28822   m.rotate = function(_) {
28823     return arguments.length ? rotate([_[0], _[1], _.length > 2 ? _[2] + 90 : 90]) : (_ = rotate(), [_[0], _[1], _[2] - 90]);
28824   };
28825
28826   return rotate([0, 0, 90])
28827       .scale(159.155);
28828 };
28829
28830 function defaultSeparation(a, b) {
28831   return a.parent === b.parent ? 1 : 2;
28832 }
28833
28834 function meanX(children) {
28835   return children.reduce(meanXReduce, 0) / children.length;
28836 }
28837
28838 function meanXReduce(x, c) {
28839   return x + c.x;
28840 }
28841
28842 function maxY(children) {
28843   return 1 + children.reduce(maxYReduce, 0);
28844 }
28845
28846 function maxYReduce(y, c) {
28847   return Math.max(y, c.y);
28848 }
28849
28850 function leafLeft(node) {
28851   var children;
28852   while (children = node.children) node = children[0];
28853   return node;
28854 }
28855
28856 function leafRight(node) {
28857   var children;
28858   while (children = node.children) node = children[children.length - 1];
28859   return node;
28860 }
28861
28862 var cluster = function() {
28863   var separation = defaultSeparation,
28864       dx = 1,
28865       dy = 1,
28866       nodeSize = false;
28867
28868   function cluster(root) {
28869     var previousNode,
28870         x = 0;
28871
28872     // First walk, computing the initial x & y values.
28873     root.eachAfter(function(node) {
28874       var children = node.children;
28875       if (children) {
28876         node.x = meanX(children);
28877         node.y = maxY(children);
28878       } else {
28879         node.x = previousNode ? x += separation(node, previousNode) : 0;
28880         node.y = 0;
28881         previousNode = node;
28882       }
28883     });
28884
28885     var left = leafLeft(root),
28886         right = leafRight(root),
28887         x0 = left.x - separation(left, right) / 2,
28888         x1 = right.x + separation(right, left) / 2;
28889
28890     // Second walk, normalizing x & y to the desired size.
28891     return root.eachAfter(nodeSize ? function(node) {
28892       node.x = (node.x - root.x) * dx;
28893       node.y = (root.y - node.y) * dy;
28894     } : function(node) {
28895       node.x = (node.x - x0) / (x1 - x0) * dx;
28896       node.y = (1 - (root.y ? node.y / root.y : 1)) * dy;
28897     });
28898   }
28899
28900   cluster.separation = function(x) {
28901     return arguments.length ? (separation = x, cluster) : separation;
28902   };
28903
28904   cluster.size = function(x) {
28905     return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? null : [dx, dy]);
28906   };
28907
28908   cluster.nodeSize = function(x) {
28909     return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? [dx, dy] : null);
28910   };
28911
28912   return cluster;
28913 };
28914
28915 function count(node) {
28916   var sum = 0,
28917       children = node.children,
28918       i = children && children.length;
28919   if (!i) sum = 1;
28920   else while (--i >= 0) sum += children[i].value;
28921   node.value = sum;
28922 }
28923
28924 var node_count = function() {
28925   return this.eachAfter(count);
28926 };
28927
28928 var node_each = function(callback) {
28929   var node = this, current, next = [node], children, i, n;
28930   do {
28931     current = next.reverse(), next = [];
28932     while (node = current.pop()) {
28933       callback(node), children = node.children;
28934       if (children) for (i = 0, n = children.length; i < n; ++i) {
28935         next.push(children[i]);
28936       }
28937     }
28938   } while (next.length);
28939   return this;
28940 };
28941
28942 var node_eachBefore = function(callback) {
28943   var node = this, nodes = [node], children, i;
28944   while (node = nodes.pop()) {
28945     callback(node), children = node.children;
28946     if (children) for (i = children.length - 1; i >= 0; --i) {
28947       nodes.push(children[i]);
28948     }
28949   }
28950   return this;
28951 };
28952
28953 var node_eachAfter = function(callback) {
28954   var node = this, nodes = [node], next = [], children, i, n;
28955   while (node = nodes.pop()) {
28956     next.push(node), children = node.children;
28957     if (children) for (i = 0, n = children.length; i < n; ++i) {
28958       nodes.push(children[i]);
28959     }
28960   }
28961   while (node = next.pop()) {
28962     callback(node);
28963   }
28964   return this;
28965 };
28966
28967 var node_sum = function(value) {
28968   return this.eachAfter(function(node) {
28969     var sum = +value(node.data) || 0,
28970         children = node.children,
28971         i = children && children.length;
28972     while (--i >= 0) sum += children[i].value;
28973     node.value = sum;
28974   });
28975 };
28976
28977 var node_sort = function(compare) {
28978   return this.eachBefore(function(node) {
28979     if (node.children) {
28980       node.children.sort(compare);
28981     }
28982   });
28983 };
28984
28985 var node_path = function(end) {
28986   var start = this,
28987       ancestor = leastCommonAncestor(start, end),
28988       nodes = [start];
28989   while (start !== ancestor) {
28990     start = start.parent;
28991     nodes.push(start);
28992   }
28993   var k = nodes.length;
28994   while (end !== ancestor) {
28995     nodes.splice(k, 0, end);
28996     end = end.parent;
28997   }
28998   return nodes;
28999 };
29000
29001 function leastCommonAncestor(a, b) {
29002   if (a === b) return a;
29003   var aNodes = a.ancestors(),
29004       bNodes = b.ancestors(),
29005       c = null;
29006   a = aNodes.pop();
29007   b = bNodes.pop();
29008   while (a === b) {
29009     c = a;
29010     a = aNodes.pop();
29011     b = bNodes.pop();
29012   }
29013   return c;
29014 }
29015
29016 var node_ancestors = function() {
29017   var node = this, nodes = [node];
29018   while (node = node.parent) {
29019     nodes.push(node);
29020   }
29021   return nodes;
29022 };
29023
29024 var node_descendants = function() {
29025   var nodes = [];
29026   this.each(function(node) {
29027     nodes.push(node);
29028   });
29029   return nodes;
29030 };
29031
29032 var node_leaves = function() {
29033   var leaves = [];
29034   this.eachBefore(function(node) {
29035     if (!node.children) {
29036       leaves.push(node);
29037     }
29038   });
29039   return leaves;
29040 };
29041
29042 var node_links = function() {
29043   var root = this, links = [];
29044   root.each(function(node) {
29045     if (node !== root) { // Don’t include the root’s parent, if any.
29046       links.push({source: node.parent, target: node});
29047     }
29048   });
29049   return links;
29050 };
29051
29052 function hierarchy(data, children) {
29053   var root = new Node(data),
29054       valued = +data.value && (root.value = data.value),
29055       node,
29056       nodes = [root],
29057       child,
29058       childs,
29059       i,
29060       n;
29061
29062   if (children == null) children = defaultChildren;
29063
29064   while (node = nodes.pop()) {
29065     if (valued) node.value = +node.data.value;
29066     if ((childs = children(node.data)) && (n = childs.length)) {
29067       node.children = new Array(n);
29068       for (i = n - 1; i >= 0; --i) {
29069         nodes.push(child = node.children[i] = new Node(childs[i]));
29070         child.parent = node;
29071         child.depth = node.depth + 1;
29072       }
29073     }
29074   }
29075
29076   return root.eachBefore(computeHeight);
29077 }
29078
29079 function node_copy() {
29080   return hierarchy(this).eachBefore(copyData);
29081 }
29082
29083 function defaultChildren(d) {
29084   return d.children;
29085 }
29086
29087 function copyData(node) {
29088   node.data = node.data.data;
29089 }
29090
29091 function computeHeight(node) {
29092   var height = 0;
29093   do node.height = height;
29094   while ((node = node.parent) && (node.height < ++height));
29095 }
29096
29097 function Node(data) {
29098   this.data = data;
29099   this.depth =
29100   this.height = 0;
29101   this.parent = null;
29102 }
29103
29104 Node.prototype = hierarchy.prototype = {
29105   constructor: Node,
29106   count: node_count,
29107   each: node_each,
29108   eachAfter: node_eachAfter,
29109   eachBefore: node_eachBefore,
29110   sum: node_sum,
29111   sort: node_sort,
29112   path: node_path,
29113   ancestors: node_ancestors,
29114   descendants: node_descendants,
29115   leaves: node_leaves,
29116   links: node_links,
29117   copy: node_copy
29118 };
29119
29120 function Node$2(value) {
29121   this._ = value;
29122   this.next = null;
29123 }
29124
29125 var shuffle$1 = function(array) {
29126   var i,
29127       n = (array = array.slice()).length,
29128       head = null,
29129       node = head;
29130
29131   while (n) {
29132     var next = new Node$2(array[n - 1]);
29133     if (node) node = node.next = next;
29134     else node = head = next;
29135     array[i] = array[--n];
29136   }
29137
29138   return {
29139     head: head,
29140     tail: node
29141   };
29142 };
29143
29144 var enclose = function(circles) {
29145   return encloseN(shuffle$1(circles), []);
29146 };
29147
29148 function encloses(a, b) {
29149   var dx = b.x - a.x,
29150       dy = b.y - a.y,
29151       dr = a.r - b.r;
29152   return dr * dr + 1e-6 > dx * dx + dy * dy;
29153 }
29154
29155 // Returns the smallest circle that contains circles L and intersects circles B.
29156 function encloseN(L, B) {
29157   var circle,
29158       l0 = null,
29159       l1 = L.head,
29160       l2,
29161       p1;
29162
29163   switch (B.length) {
29164     case 1: circle = enclose1(B[0]); break;
29165     case 2: circle = enclose2(B[0], B[1]); break;
29166     case 3: circle = enclose3(B[0], B[1], B[2]); break;
29167   }
29168
29169   while (l1) {
29170     p1 = l1._, l2 = l1.next;
29171     if (!circle || !encloses(circle, p1)) {
29172
29173       // Temporarily truncate L before l1.
29174       if (l0) L.tail = l0, l0.next = null;
29175       else L.head = L.tail = null;
29176
29177       B.push(p1);
29178       circle = encloseN(L, B); // Note: reorders L!
29179       B.pop();
29180
29181       // Move l1 to the front of L and reconnect the truncated list L.
29182       if (L.head) l1.next = L.head, L.head = l1;
29183       else l1.next = null, L.head = L.tail = l1;
29184       l0 = L.tail, l0.next = l2;
29185
29186     } else {
29187       l0 = l1;
29188     }
29189     l1 = l2;
29190   }
29191
29192   L.tail = l0;
29193   return circle;
29194 }
29195
29196 function enclose1(a) {
29197   return {
29198     x: a.x,
29199     y: a.y,
29200     r: a.r
29201   };
29202 }
29203
29204 function enclose2(a, b) {
29205   var x1 = a.x, y1 = a.y, r1 = a.r,
29206       x2 = b.x, y2 = b.y, r2 = b.r,
29207       x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1,
29208       l = Math.sqrt(x21 * x21 + y21 * y21);
29209   return {
29210     x: (x1 + x2 + x21 / l * r21) / 2,
29211     y: (y1 + y2 + y21 / l * r21) / 2,
29212     r: (l + r1 + r2) / 2
29213   };
29214 }
29215
29216 function enclose3(a, b, c) {
29217   var x1 = a.x, y1 = a.y, r1 = a.r,
29218       x2 = b.x, y2 = b.y, r2 = b.r,
29219       x3 = c.x, y3 = c.y, r3 = c.r,
29220       a2 = 2 * (x1 - x2),
29221       b2 = 2 * (y1 - y2),
29222       c2 = 2 * (r2 - r1),
29223       d2 = x1 * x1 + y1 * y1 - r1 * r1 - x2 * x2 - y2 * y2 + r2 * r2,
29224       a3 = 2 * (x1 - x3),
29225       b3 = 2 * (y1 - y3),
29226       c3 = 2 * (r3 - r1),
29227       d3 = x1 * x1 + y1 * y1 - r1 * r1 - x3 * x3 - y3 * y3 + r3 * r3,
29228       ab = a3 * b2 - a2 * b3,
29229       xa = (b2 * d3 - b3 * d2) / ab - x1,
29230       xb = (b3 * c2 - b2 * c3) / ab,
29231       ya = (a3 * d2 - a2 * d3) / ab - y1,
29232       yb = (a2 * c3 - a3 * c2) / ab,
29233       A = xb * xb + yb * yb - 1,
29234       B = 2 * (xa * xb + ya * yb + r1),
29235       C = xa * xa + ya * ya - r1 * r1,
29236       r = (-B - Math.sqrt(B * B - 4 * A * C)) / (2 * A);
29237   return {
29238     x: xa + xb * r + x1,
29239     y: ya + yb * r + y1,
29240     r: r
29241   };
29242 }
29243
29244 function place(a, b, c) {
29245   var ax = a.x,
29246       ay = a.y,
29247       da = b.r + c.r,
29248       db = a.r + c.r,
29249       dx = b.x - ax,
29250       dy = b.y - ay,
29251       dc = dx * dx + dy * dy;
29252   if (dc) {
29253     var x = 0.5 + ((db *= db) - (da *= da)) / (2 * dc),
29254         y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
29255     c.x = ax + x * dx + y * dy;
29256     c.y = ay + x * dy - y * dx;
29257   } else {
29258     c.x = ax + db;
29259     c.y = ay;
29260   }
29261 }
29262
29263 function intersects(a, b) {
29264   var dx = b.x - a.x,
29265       dy = b.y - a.y,
29266       dr = a.r + b.r;
29267   return dr * dr - 1e-6 > dx * dx + dy * dy;
29268 }
29269
29270 function distance2(node, x, y) {
29271   var a = node._,
29272       b = node.next._,
29273       ab = a.r + b.r,
29274       dx = (a.x * b.r + b.x * a.r) / ab - x,
29275       dy = (a.y * b.r + b.y * a.r) / ab - y;
29276   return dx * dx + dy * dy;
29277 }
29278
29279 function Node$1(circle) {
29280   this._ = circle;
29281   this.next = null;
29282   this.previous = null;
29283 }
29284
29285 function packEnclose(circles) {
29286   if (!(n = circles.length)) return 0;
29287
29288   var a, b, c, n;
29289
29290   // Place the first circle.
29291   a = circles[0], a.x = 0, a.y = 0;
29292   if (!(n > 1)) return a.r;
29293
29294   // Place the second circle.
29295   b = circles[1], a.x = -b.r, b.x = a.r, b.y = 0;
29296   if (!(n > 2)) return a.r + b.r;
29297
29298   // Place the third circle.
29299   place(b, a, c = circles[2]);
29300
29301   // Initialize the weighted centroid.
29302   var aa = a.r * a.r,
29303       ba = b.r * b.r,
29304       ca = c.r * c.r,
29305       oa = aa + ba + ca,
29306       ox = aa * a.x + ba * b.x + ca * c.x,
29307       oy = aa * a.y + ba * b.y + ca * c.y,
29308       cx, cy, i, j, k, sj, sk;
29309
29310   // Initialize the front-chain using the first three circles a, b and c.
29311   a = new Node$1(a), b = new Node$1(b), c = new Node$1(c);
29312   a.next = c.previous = b;
29313   b.next = a.previous = c;
29314   c.next = b.previous = a;
29315
29316   // Attempt to place each remaining circle…
29317   pack: for (i = 3; i < n; ++i) {
29318     place(a._, b._, c = circles[i]), c = new Node$1(c);
29319
29320     // Find the closest intersecting circle on the front-chain, if any.
29321     // “Closeness” is determined by linear distance along the front-chain.
29322     // “Ahead” or “behind” is likewise determined by linear distance.
29323     j = b.next, k = a.previous, sj = b._.r, sk = a._.r;
29324     do {
29325       if (sj <= sk) {
29326         if (intersects(j._, c._)) {
29327           b = j, a.next = b, b.previous = a, --i;
29328           continue pack;
29329         }
29330         sj += j._.r, j = j.next;
29331       } else {
29332         if (intersects(k._, c._)) {
29333           a = k, a.next = b, b.previous = a, --i;
29334           continue pack;
29335         }
29336         sk += k._.r, k = k.previous;
29337       }
29338     } while (j !== k.next);
29339
29340     // Success! Insert the new circle c between a and b.
29341     c.previous = a, c.next = b, a.next = b.previous = b = c;
29342
29343     // Update the weighted centroid.
29344     oa += ca = c._.r * c._.r;
29345     ox += ca * c._.x;
29346     oy += ca * c._.y;
29347
29348     // Compute the new closest circle pair to the centroid.
29349     aa = distance2(a, cx = ox / oa, cy = oy / oa);
29350     while ((c = c.next) !== b) {
29351       if ((ca = distance2(c, cx, cy)) < aa) {
29352         a = c, aa = ca;
29353       }
29354     }
29355     b = a.next;
29356   }
29357
29358   // Compute the enclosing circle of the front chain.
29359   a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = enclose(a);
29360
29361   // Translate the circles to put the enclosing circle around the origin.
29362   for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y;
29363
29364   return c.r;
29365 }
29366
29367 var siblings = function(circles) {
29368   packEnclose(circles);
29369   return circles;
29370 };
29371
29372 function optional(f) {
29373   return f == null ? null : required(f);
29374 }
29375
29376 function required(f) {
29377   if (typeof f !== "function") throw new Error;
29378   return f;
29379 }
29380
29381 function constantZero() {
29382   return 0;
29383 }
29384
29385 var constant$8 = function(x) {
29386   return function() {
29387     return x;
29388   };
29389 };
29390
29391 function defaultRadius$1(d) {
29392   return Math.sqrt(d.value);
29393 }
29394
29395 var index$5 = function() {
29396   var radius = null,
29397       dx = 1,
29398       dy = 1,
29399       padding = constantZero;
29400
29401   function pack(root) {
29402     root.x = dx / 2, root.y = dy / 2;
29403     if (radius) {
29404       root.eachBefore(radiusLeaf(radius))
29405           .eachAfter(packChildren(padding, 0.5))
29406           .eachBefore(translateChild(1));
29407     } else {
29408       root.eachBefore(radiusLeaf(defaultRadius$1))
29409           .eachAfter(packChildren(constantZero, 1))
29410           .eachAfter(packChildren(padding, root.r / Math.min(dx, dy)))
29411           .eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r)));
29412     }
29413     return root;
29414   }
29415
29416   pack.radius = function(x) {
29417     return arguments.length ? (radius = optional(x), pack) : radius;
29418   };
29419
29420   pack.size = function(x) {
29421     return arguments.length ? (dx = +x[0], dy = +x[1], pack) : [dx, dy];
29422   };
29423
29424   pack.padding = function(x) {
29425     return arguments.length ? (padding = typeof x === "function" ? x : constant$8(+x), pack) : padding;
29426   };
29427
29428   return pack;
29429 };
29430
29431 function radiusLeaf(radius) {
29432   return function(node) {
29433     if (!node.children) {
29434       node.r = Math.max(0, +radius(node) || 0);
29435     }
29436   };
29437 }
29438
29439 function packChildren(padding, k) {
29440   return function(node) {
29441     if (children = node.children) {
29442       var children,
29443           i,
29444           n = children.length,
29445           r = padding(node) * k || 0,
29446           e;
29447
29448       if (r) for (i = 0; i < n; ++i) children[i].r += r;
29449       e = packEnclose(children);
29450       if (r) for (i = 0; i < n; ++i) children[i].r -= r;
29451       node.r = e + r;
29452     }
29453   };
29454 }
29455
29456 function translateChild(k) {
29457   return function(node) {
29458     var parent = node.parent;
29459     node.r *= k;
29460     if (parent) {
29461       node.x = parent.x + k * node.x;
29462       node.y = parent.y + k * node.y;
29463     }
29464   };
29465 }
29466
29467 var roundNode = function(node) {
29468   node.x0 = Math.round(node.x0);
29469   node.y0 = Math.round(node.y0);
29470   node.x1 = Math.round(node.x1);
29471   node.y1 = Math.round(node.y1);
29472 };
29473
29474 var treemapDice = function(parent, x0, y0, x1, y1) {
29475   var nodes = parent.children,
29476       node,
29477       i = -1,
29478       n = nodes.length,
29479       k = parent.value && (x1 - x0) / parent.value;
29480
29481   while (++i < n) {
29482     node = nodes[i], node.y0 = y0, node.y1 = y1;
29483     node.x0 = x0, node.x1 = x0 += node.value * k;
29484   }
29485 };
29486
29487 var partition = function() {
29488   var dx = 1,
29489       dy = 1,
29490       padding = 0,
29491       round = false;
29492
29493   function partition(root) {
29494     var n = root.height + 1;
29495     root.x0 =
29496     root.y0 = padding;
29497     root.x1 = dx;
29498     root.y1 = dy / n;
29499     root.eachBefore(positionNode(dy, n));
29500     if (round) root.eachBefore(roundNode);
29501     return root;
29502   }
29503
29504   function positionNode(dy, n) {
29505     return function(node) {
29506       if (node.children) {
29507         treemapDice(node, node.x0, dy * (node.depth + 1) / n, node.x1, dy * (node.depth + 2) / n);
29508       }
29509       var x0 = node.x0,
29510           y0 = node.y0,
29511           x1 = node.x1 - padding,
29512           y1 = node.y1 - padding;
29513       if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29514       if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29515       node.x0 = x0;
29516       node.y0 = y0;
29517       node.x1 = x1;
29518       node.y1 = y1;
29519     };
29520   }
29521
29522   partition.round = function(x) {
29523     return arguments.length ? (round = !!x, partition) : round;
29524   };
29525
29526   partition.size = function(x) {
29527     return arguments.length ? (dx = +x[0], dy = +x[1], partition) : [dx, dy];
29528   };
29529
29530   partition.padding = function(x) {
29531     return arguments.length ? (padding = +x, partition) : padding;
29532   };
29533
29534   return partition;
29535 };
29536
29537 var keyPrefix$1 = "$";
29538 var preroot = {depth: -1};
29539 var ambiguous = {};
29540
29541 function defaultId(d) {
29542   return d.id;
29543 }
29544
29545 function defaultParentId(d) {
29546   return d.parentId;
29547 }
29548
29549 var stratify = function() {
29550   var id = defaultId,
29551       parentId = defaultParentId;
29552
29553   function stratify(data) {
29554     var d,
29555         i,
29556         n = data.length,
29557         root,
29558         parent,
29559         node,
29560         nodes = new Array(n),
29561         nodeId,
29562         nodeKey,
29563         nodeByKey = {};
29564
29565     for (i = 0; i < n; ++i) {
29566       d = data[i], node = nodes[i] = new Node(d);
29567       if ((nodeId = id(d, i, data)) != null && (nodeId += "")) {
29568         nodeKey = keyPrefix$1 + (node.id = nodeId);
29569         nodeByKey[nodeKey] = nodeKey in nodeByKey ? ambiguous : node;
29570       }
29571     }
29572
29573     for (i = 0; i < n; ++i) {
29574       node = nodes[i], nodeId = parentId(data[i], i, data);
29575       if (nodeId == null || !(nodeId += "")) {
29576         if (root) throw new Error("multiple roots");
29577         root = node;
29578       } else {
29579         parent = nodeByKey[keyPrefix$1 + nodeId];
29580         if (!parent) throw new Error("missing: " + nodeId);
29581         if (parent === ambiguous) throw new Error("ambiguous: " + nodeId);
29582         if (parent.children) parent.children.push(node);
29583         else parent.children = [node];
29584         node.parent = parent;
29585       }
29586     }
29587
29588     if (!root) throw new Error("no root");
29589     root.parent = preroot;
29590     root.eachBefore(function(node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight);
29591     root.parent = null;
29592     if (n > 0) throw new Error("cycle");
29593
29594     return root;
29595   }
29596
29597   stratify.id = function(x) {
29598     return arguments.length ? (id = required(x), stratify) : id;
29599   };
29600
29601   stratify.parentId = function(x) {
29602     return arguments.length ? (parentId = required(x), stratify) : parentId;
29603   };
29604
29605   return stratify;
29606 };
29607
29608 function defaultSeparation$1(a, b) {
29609   return a.parent === b.parent ? 1 : 2;
29610 }
29611
29612 // function radialSeparation(a, b) {
29613 //   return (a.parent === b.parent ? 1 : 2) / a.depth;
29614 // }
29615
29616 // This function is used to traverse the left contour of a subtree (or
29617 // subforest). It returns the successor of v on this contour. This successor is
29618 // either given by the leftmost child of v or by the thread of v. The function
29619 // returns null if and only if v is on the highest level of its subtree.
29620 function nextLeft(v) {
29621   var children = v.children;
29622   return children ? children[0] : v.t;
29623 }
29624
29625 // This function works analogously to nextLeft.
29626 function nextRight(v) {
29627   var children = v.children;
29628   return children ? children[children.length - 1] : v.t;
29629 }
29630
29631 // Shifts the current subtree rooted at w+. This is done by increasing
29632 // prelim(w+) and mod(w+) by shift.
29633 function moveSubtree(wm, wp, shift) {
29634   var change = shift / (wp.i - wm.i);
29635   wp.c -= change;
29636   wp.s += shift;
29637   wm.c += change;
29638   wp.z += shift;
29639   wp.m += shift;
29640 }
29641
29642 // All other shifts, applied to the smaller subtrees between w- and w+, are
29643 // performed by this function. To prepare the shifts, we have to adjust
29644 // change(w+), shift(w+), and change(w-).
29645 function executeShifts(v) {
29646   var shift = 0,
29647       change = 0,
29648       children = v.children,
29649       i = children.length,
29650       w;
29651   while (--i >= 0) {
29652     w = children[i];
29653     w.z += shift;
29654     w.m += shift;
29655     shift += w.s + (change += w.c);
29656   }
29657 }
29658
29659 // If vi-’s ancestor is a sibling of v, returns vi-’s ancestor. Otherwise,
29660 // returns the specified (default) ancestor.
29661 function nextAncestor(vim, v, ancestor) {
29662   return vim.a.parent === v.parent ? vim.a : ancestor;
29663 }
29664
29665 function TreeNode(node, i) {
29666   this._ = node;
29667   this.parent = null;
29668   this.children = null;
29669   this.A = null; // default ancestor
29670   this.a = this; // ancestor
29671   this.z = 0; // prelim
29672   this.m = 0; // mod
29673   this.c = 0; // change
29674   this.s = 0; // shift
29675   this.t = null; // thread
29676   this.i = i; // number
29677 }
29678
29679 TreeNode.prototype = Object.create(Node.prototype);
29680
29681 function treeRoot(root) {
29682   var tree = new TreeNode(root, 0),
29683       node,
29684       nodes = [tree],
29685       child,
29686       children,
29687       i,
29688       n;
29689
29690   while (node = nodes.pop()) {
29691     if (children = node._.children) {
29692       node.children = new Array(n = children.length);
29693       for (i = n - 1; i >= 0; --i) {
29694         nodes.push(child = node.children[i] = new TreeNode(children[i], i));
29695         child.parent = node;
29696       }
29697     }
29698   }
29699
29700   (tree.parent = new TreeNode(null, 0)).children = [tree];
29701   return tree;
29702 }
29703
29704 // Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
29705 var tree = function() {
29706   var separation = defaultSeparation$1,
29707       dx = 1,
29708       dy = 1,
29709       nodeSize = null;
29710
29711   function tree(root) {
29712     var t = treeRoot(root);
29713
29714     // Compute the layout using Buchheim et al.’s algorithm.
29715     t.eachAfter(firstWalk), t.parent.m = -t.z;
29716     t.eachBefore(secondWalk);
29717
29718     // If a fixed node size is specified, scale x and y.
29719     if (nodeSize) root.eachBefore(sizeNode);
29720
29721     // If a fixed tree size is specified, scale x and y based on the extent.
29722     // Compute the left-most, right-most, and depth-most nodes for extents.
29723     else {
29724       var left = root,
29725           right = root,
29726           bottom = root;
29727       root.eachBefore(function(node) {
29728         if (node.x < left.x) left = node;
29729         if (node.x > right.x) right = node;
29730         if (node.depth > bottom.depth) bottom = node;
29731       });
29732       var s = left === right ? 1 : separation(left, right) / 2,
29733           tx = s - left.x,
29734           kx = dx / (right.x + s + tx),
29735           ky = dy / (bottom.depth || 1);
29736       root.eachBefore(function(node) {
29737         node.x = (node.x + tx) * kx;
29738         node.y = node.depth * ky;
29739       });
29740     }
29741
29742     return root;
29743   }
29744
29745   // Computes a preliminary x-coordinate for v. Before that, FIRST WALK is
29746   // applied recursively to the children of v, as well as the function
29747   // APPORTION. After spacing out the children by calling EXECUTE SHIFTS, the
29748   // node v is placed to the midpoint of its outermost children.
29749   function firstWalk(v) {
29750     var children = v.children,
29751         siblings = v.parent.children,
29752         w = v.i ? siblings[v.i - 1] : null;
29753     if (children) {
29754       executeShifts(v);
29755       var midpoint = (children[0].z + children[children.length - 1].z) / 2;
29756       if (w) {
29757         v.z = w.z + separation(v._, w._);
29758         v.m = v.z - midpoint;
29759       } else {
29760         v.z = midpoint;
29761       }
29762     } else if (w) {
29763       v.z = w.z + separation(v._, w._);
29764     }
29765     v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
29766   }
29767
29768   // Computes all real x-coordinates by summing up the modifiers recursively.
29769   function secondWalk(v) {
29770     v._.x = v.z + v.parent.m;
29771     v.m += v.parent.m;
29772   }
29773
29774   // The core of the algorithm. Here, a new subtree is combined with the
29775   // previous subtrees. Threads are used to traverse the inside and outside
29776   // contours of the left and right subtree up to the highest common level. The
29777   // vertices used for the traversals are vi+, vi-, vo-, and vo+, where the
29778   // superscript o means outside and i means inside, the subscript - means left
29779   // subtree and + means right subtree. For summing up the modifiers along the
29780   // contour, we use respective variables si+, si-, so-, and so+. Whenever two
29781   // nodes of the inside contours conflict, we compute the left one of the
29782   // greatest uncommon ancestors using the function ANCESTOR and call MOVE
29783   // SUBTREE to shift the subtree and prepare the shifts of smaller subtrees.
29784   // Finally, we add a new thread (if necessary).
29785   function apportion(v, w, ancestor) {
29786     if (w) {
29787       var vip = v,
29788           vop = v,
29789           vim = w,
29790           vom = vip.parent.children[0],
29791           sip = vip.m,
29792           sop = vop.m,
29793           sim = vim.m,
29794           som = vom.m,
29795           shift;
29796       while (vim = nextRight(vim), vip = nextLeft(vip), vim && vip) {
29797         vom = nextLeft(vom);
29798         vop = nextRight(vop);
29799         vop.a = v;
29800         shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
29801         if (shift > 0) {
29802           moveSubtree(nextAncestor(vim, v, ancestor), v, shift);
29803           sip += shift;
29804           sop += shift;
29805         }
29806         sim += vim.m;
29807         sip += vip.m;
29808         som += vom.m;
29809         sop += vop.m;
29810       }
29811       if (vim && !nextRight(vop)) {
29812         vop.t = vim;
29813         vop.m += sim - sop;
29814       }
29815       if (vip && !nextLeft(vom)) {
29816         vom.t = vip;
29817         vom.m += sip - som;
29818         ancestor = v;
29819       }
29820     }
29821     return ancestor;
29822   }
29823
29824   function sizeNode(node) {
29825     node.x *= dx;
29826     node.y = node.depth * dy;
29827   }
29828
29829   tree.separation = function(x) {
29830     return arguments.length ? (separation = x, tree) : separation;
29831   };
29832
29833   tree.size = function(x) {
29834     return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], tree) : (nodeSize ? null : [dx, dy]);
29835   };
29836
29837   tree.nodeSize = function(x) {
29838     return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], tree) : (nodeSize ? [dx, dy] : null);
29839   };
29840
29841   return tree;
29842 };
29843
29844 var treemapSlice = function(parent, x0, y0, x1, y1) {
29845   var nodes = parent.children,
29846       node,
29847       i = -1,
29848       n = nodes.length,
29849       k = parent.value && (y1 - y0) / parent.value;
29850
29851   while (++i < n) {
29852     node = nodes[i], node.x0 = x0, node.x1 = x1;
29853     node.y0 = y0, node.y1 = y0 += node.value * k;
29854   }
29855 };
29856
29857 var phi = (1 + Math.sqrt(5)) / 2;
29858
29859 function squarifyRatio(ratio, parent, x0, y0, x1, y1) {
29860   var rows = [],
29861       nodes = parent.children,
29862       row,
29863       nodeValue,
29864       i0 = 0,
29865       i1 = 0,
29866       n = nodes.length,
29867       dx, dy,
29868       value = parent.value,
29869       sumValue,
29870       minValue,
29871       maxValue,
29872       newRatio,
29873       minRatio,
29874       alpha,
29875       beta;
29876
29877   while (i0 < n) {
29878     dx = x1 - x0, dy = y1 - y0;
29879
29880     // Find the next non-empty node.
29881     do sumValue = nodes[i1++].value; while (!sumValue && i1 < n);
29882     minValue = maxValue = sumValue;
29883     alpha = Math.max(dy / dx, dx / dy) / (value * ratio);
29884     beta = sumValue * sumValue * alpha;
29885     minRatio = Math.max(maxValue / beta, beta / minValue);
29886
29887     // Keep adding nodes while the aspect ratio maintains or improves.
29888     for (; i1 < n; ++i1) {
29889       sumValue += nodeValue = nodes[i1].value;
29890       if (nodeValue < minValue) minValue = nodeValue;
29891       if (nodeValue > maxValue) maxValue = nodeValue;
29892       beta = sumValue * sumValue * alpha;
29893       newRatio = Math.max(maxValue / beta, beta / minValue);
29894       if (newRatio > minRatio) { sumValue -= nodeValue; break; }
29895       minRatio = newRatio;
29896     }
29897
29898     // Position and record the row orientation.
29899     rows.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)});
29900     if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += dy * sumValue / value : y1);
29901     else treemapSlice(row, x0, y0, value ? x0 += dx * sumValue / value : x1, y1);
29902     value -= sumValue, i0 = i1;
29903   }
29904
29905   return rows;
29906 }
29907
29908 var squarify = ((function custom(ratio) {
29909
29910   function squarify(parent, x0, y0, x1, y1) {
29911     squarifyRatio(ratio, parent, x0, y0, x1, y1);
29912   }
29913
29914   squarify.ratio = function(x) {
29915     return custom((x = +x) > 1 ? x : 1);
29916   };
29917
29918   return squarify;
29919 }))(phi);
29920
29921 var index$6 = function() {
29922   var tile = squarify,
29923       round = false,
29924       dx = 1,
29925       dy = 1,
29926       paddingStack = [0],
29927       paddingInner = constantZero,
29928       paddingTop = constantZero,
29929       paddingRight = constantZero,
29930       paddingBottom = constantZero,
29931       paddingLeft = constantZero;
29932
29933   function treemap(root) {
29934     root.x0 =
29935     root.y0 = 0;
29936     root.x1 = dx;
29937     root.y1 = dy;
29938     root.eachBefore(positionNode);
29939     paddingStack = [0];
29940     if (round) root.eachBefore(roundNode);
29941     return root;
29942   }
29943
29944   function positionNode(node) {
29945     var p = paddingStack[node.depth],
29946         x0 = node.x0 + p,
29947         y0 = node.y0 + p,
29948         x1 = node.x1 - p,
29949         y1 = node.y1 - p;
29950     if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29951     if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29952     node.x0 = x0;
29953     node.y0 = y0;
29954     node.x1 = x1;
29955     node.y1 = y1;
29956     if (node.children) {
29957       p = paddingStack[node.depth + 1] = paddingInner(node) / 2;
29958       x0 += paddingLeft(node) - p;
29959       y0 += paddingTop(node) - p;
29960       x1 -= paddingRight(node) - p;
29961       y1 -= paddingBottom(node) - p;
29962       if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29963       if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29964       tile(node, x0, y0, x1, y1);
29965     }
29966   }
29967
29968   treemap.round = function(x) {
29969     return arguments.length ? (round = !!x, treemap) : round;
29970   };
29971
29972   treemap.size = function(x) {
29973     return arguments.length ? (dx = +x[0], dy = +x[1], treemap) : [dx, dy];
29974   };
29975
29976   treemap.tile = function(x) {
29977     return arguments.length ? (tile = required(x), treemap) : tile;
29978   };
29979
29980   treemap.padding = function(x) {
29981     return arguments.length ? treemap.paddingInner(x).paddingOuter(x) : treemap.paddingInner();
29982   };
29983
29984   treemap.paddingInner = function(x) {
29985     return arguments.length ? (paddingInner = typeof x === "function" ? x : constant$8(+x), treemap) : paddingInner;
29986   };
29987
29988   treemap.paddingOuter = function(x) {
29989     return arguments.length ? treemap.paddingTop(x).paddingRight(x).paddingBottom(x).paddingLeft(x) : treemap.paddingTop();
29990   };
29991
29992   treemap.paddingTop = function(x) {
29993     return arguments.length ? (paddingTop = typeof x === "function" ? x : constant$8(+x), treemap) : paddingTop;
29994   };
29995
29996   treemap.paddingRight = function(x) {
29997     return arguments.length ? (paddingRight = typeof x === "function" ? x : constant$8(+x), treemap) : paddingRight;
29998   };
29999
30000   treemap.paddingBottom = function(x) {
30001     return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant$8(+x), treemap) : paddingBottom;
30002   };
30003
30004   treemap.paddingLeft = function(x) {
30005     return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant$8(+x), treemap) : paddingLeft;
30006   };
30007
30008   return treemap;
30009 };
30010
30011 var binary = function(parent, x0, y0, x1, y1) {
30012   var nodes = parent.children,
30013       i, n = nodes.length,
30014       sum, sums = new Array(n + 1);
30015
30016   for (sums[0] = sum = i = 0; i < n; ++i) {
30017     sums[i + 1] = sum += nodes[i].value;
30018   }
30019
30020   partition(0, n, parent.value, x0, y0, x1, y1);
30021
30022   function partition(i, j, value, x0, y0, x1, y1) {
30023     if (i >= j - 1) {
30024       var node = nodes[i];
30025       node.x0 = x0, node.y0 = y0;
30026       node.x1 = x1, node.y1 = y1;
30027       return;
30028     }
30029
30030     var valueOffset = sums[i],
30031         valueTarget = (value / 2) + valueOffset,
30032         k = i + 1,
30033         hi = j - 1;
30034
30035     while (k < hi) {
30036       var mid = k + hi >>> 1;
30037       if (sums[mid] < valueTarget) k = mid + 1;
30038       else hi = mid;
30039     }
30040
30041     if ((valueTarget - sums[k - 1]) < (sums[k] - valueTarget) && i + 1 < k) --k;
30042
30043     var valueLeft = sums[k] - valueOffset,
30044         valueRight = value - valueLeft;
30045
30046     if ((x1 - x0) > (y1 - y0)) {
30047       var xk = (x0 * valueRight + x1 * valueLeft) / value;
30048       partition(i, k, valueLeft, x0, y0, xk, y1);
30049       partition(k, j, valueRight, xk, y0, x1, y1);
30050     } else {
30051       var yk = (y0 * valueRight + y1 * valueLeft) / value;
30052       partition(i, k, valueLeft, x0, y0, x1, yk);
30053       partition(k, j, valueRight, x0, yk, x1, y1);
30054     }
30055   }
30056 };
30057
30058 var sliceDice = function(parent, x0, y0, x1, y1) {
30059   (parent.depth & 1 ? treemapSlice : treemapDice)(parent, x0, y0, x1, y1);
30060 };
30061
30062 var resquarify = ((function custom(ratio) {
30063
30064   function resquarify(parent, x0, y0, x1, y1) {
30065     if ((rows = parent._squarify) && (rows.ratio === ratio)) {
30066       var rows,
30067           row,
30068           nodes,
30069           i,
30070           j = -1,
30071           n,
30072           m = rows.length,
30073           value = parent.value;
30074
30075       while (++j < m) {
30076         row = rows[j], nodes = row.children;
30077         for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value;
30078         if (row.dice) treemapDice(row, x0, y0, x1, y0 += (y1 - y0) * row.value / value);
30079         else treemapSlice(row, x0, y0, x0 += (x1 - x0) * row.value / value, y1);
30080         value -= row.value;
30081       }
30082     } else {
30083       parent._squarify = rows = squarifyRatio(ratio, parent, x0, y0, x1, y1);
30084       rows.ratio = ratio;
30085     }
30086   }
30087
30088   resquarify.ratio = function(x) {
30089     return custom((x = +x) > 1 ? x : 1);
30090   };
30091
30092   return resquarify;
30093 }))(phi);
30094
30095 var d3polygonArea = function(polygon) {
30096   var i = -1,
30097       n = polygon.length,
30098       a,
30099       b = polygon[n - 1],
30100       area = 0;
30101
30102   while (++i < n) {
30103     a = b;
30104     b = polygon[i];
30105     area += a[1] * b[0] - a[0] * b[1];
30106   }
30107
30108   return area / 2;
30109 };
30110
30111 var d3polygonCentroid = function(polygon) {
30112   var i = -1,
30113       n = polygon.length,
30114       x = 0,
30115       y = 0,
30116       a,
30117       b = polygon[n - 1],
30118       c,
30119       k = 0;
30120
30121   while (++i < n) {
30122     a = b;
30123     b = polygon[i];
30124     k += c = a[0] * b[1] - b[0] * a[1];
30125     x += (a[0] + b[0]) * c;
30126     y += (a[1] + b[1]) * c;
30127   }
30128
30129   return k *= 3, [x / k, y / k];
30130 };
30131
30132 // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
30133 // the 3D cross product in a quadrant I Cartesian coordinate system (+x is
30134 // right, +y is up). Returns a positive value if ABC is counter-clockwise,
30135 // negative if clockwise, and zero if the points are collinear.
30136 var cross$1 = function(a, b, c) {
30137   return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
30138 };
30139
30140 function lexicographicOrder(a, b) {
30141   return a[0] - b[0] || a[1] - b[1];
30142 }
30143
30144 // Computes the upper convex hull per the monotone chain algorithm.
30145 // Assumes points.length >= 3, is sorted by x, unique in y.
30146 // Returns an array of indices into points in left-to-right order.
30147 function computeUpperHullIndexes(points) {
30148   var n = points.length,
30149       indexes = [0, 1],
30150       size = 2;
30151
30152   for (var i = 2; i < n; ++i) {
30153     while (size > 1 && cross$1(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size;
30154     indexes[size++] = i;
30155   }
30156
30157   return indexes.slice(0, size); // remove popped points
30158 }
30159
30160 var d3polygonHull = function(points) {
30161   if ((n = points.length) < 3) return null;
30162
30163   var i,
30164       n,
30165       sortedPoints = new Array(n),
30166       flippedPoints = new Array(n);
30167
30168   for (i = 0; i < n; ++i) sortedPoints[i] = [+points[i][0], +points[i][1], i];
30169   sortedPoints.sort(lexicographicOrder);
30170   for (i = 0; i < n; ++i) flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
30171
30172   var upperIndexes = computeUpperHullIndexes(sortedPoints),
30173       lowerIndexes = computeUpperHullIndexes(flippedPoints);
30174
30175   // Construct the hull polygon, removing possible duplicate endpoints.
30176   var skipLeft = lowerIndexes[0] === upperIndexes[0],
30177       skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
30178       hull = [];
30179
30180   // Add upper hull in right-to-l order.
30181   // Then add lower hull in left-to-right order.
30182   for (i = upperIndexes.length - 1; i >= 0; --i) hull.push(points[sortedPoints[upperIndexes[i]][2]]);
30183   for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
30184
30185   return hull;
30186 };
30187
30188 var contains$1 = function(polygon, point) {
30189   var n = polygon.length,
30190       p = polygon[n - 1],
30191       x = point[0], y = point[1],
30192       x0 = p[0], y0 = p[1],
30193       x1, y1,
30194       inside = false;
30195
30196   for (var i = 0; i < n; ++i) {
30197     p = polygon[i], x1 = p[0], y1 = p[1];
30198     if (((y1 > y) !== (y0 > y)) && (x < (x0 - x1) * (y - y1) / (y0 - y1) + x1)) inside = !inside;
30199     x0 = x1, y0 = y1;
30200   }
30201
30202   return inside;
30203 };
30204
30205 var length$1 = function(polygon) {
30206   var i = -1,
30207       n = polygon.length,
30208       b = polygon[n - 1],
30209       xa,
30210       ya,
30211       xb = b[0],
30212       yb = b[1],
30213       perimeter = 0;
30214
30215   while (++i < n) {
30216     xa = xb;
30217     ya = yb;
30218     b = polygon[i];
30219     xb = b[0];
30220     yb = b[1];
30221     xa -= xb;
30222     ya -= yb;
30223     perimeter += Math.sqrt(xa * xa + ya * ya);
30224   }
30225
30226   return perimeter;
30227 };
30228
30229 var slice$3 = [].slice;
30230
30231 var noabort = {};
30232
30233 function Queue(size) {
30234   if (!(size >= 1)) throw new Error;
30235   this._size = size;
30236   this._call =
30237   this._error = null;
30238   this._tasks = [];
30239   this._data = [];
30240   this._waiting =
30241   this._active =
30242   this._ended =
30243   this._start = 0; // inside a synchronous task callback?
30244 }
30245
30246 Queue.prototype = queue.prototype = {
30247   constructor: Queue,
30248   defer: function(callback) {
30249     if (typeof callback !== "function" || this._call) throw new Error;
30250     if (this._error != null) return this;
30251     var t = slice$3.call(arguments, 1);
30252     t.push(callback);
30253     ++this._waiting, this._tasks.push(t);
30254     poke$1(this);
30255     return this;
30256   },
30257   abort: function() {
30258     if (this._error == null) abort(this, new Error("abort"));
30259     return this;
30260   },
30261   await: function(callback) {
30262     if (typeof callback !== "function" || this._call) throw new Error;
30263     this._call = function(error, results) { callback.apply(null, [error].concat(results)); };
30264     maybeNotify(this);
30265     return this;
30266   },
30267   awaitAll: function(callback) {
30268     if (typeof callback !== "function" || this._call) throw new Error;
30269     this._call = callback;
30270     maybeNotify(this);
30271     return this;
30272   }
30273 };
30274
30275 function poke$1(q) {
30276   if (!q._start) {
30277     try { start$1(q); } // let the current task complete
30278     catch (e) {
30279       if (q._tasks[q._ended + q._active - 1]) abort(q, e); // task errored synchronously
30280       else if (!q._data) throw e; // await callback errored synchronously
30281     }
30282   }
30283 }
30284
30285 function start$1(q) {
30286   while (q._start = q._waiting && q._active < q._size) {
30287     var i = q._ended + q._active,
30288         t = q._tasks[i],
30289         j = t.length - 1,
30290         c = t[j];
30291     t[j] = end(q, i);
30292     --q._waiting, ++q._active;
30293     t = c.apply(null, t);
30294     if (!q._tasks[i]) continue; // task finished synchronously
30295     q._tasks[i] = t || noabort;
30296   }
30297 }
30298
30299 function end(q, i) {
30300   return function(e, r) {
30301     if (!q._tasks[i]) return; // ignore multiple callbacks
30302     --q._active, ++q._ended;
30303     q._tasks[i] = null;
30304     if (q._error != null) return; // ignore secondary errors
30305     if (e != null) {
30306       abort(q, e);
30307     } else {
30308       q._data[i] = r;
30309       if (q._waiting) poke$1(q);
30310       else maybeNotify(q);
30311     }
30312   };
30313 }
30314
30315 function abort(q, e) {
30316   var i = q._tasks.length, t;
30317   q._error = e; // ignore active callbacks
30318   q._data = undefined; // allow gc
30319   q._waiting = NaN; // prevent starting
30320
30321   while (--i >= 0) {
30322     if (t = q._tasks[i]) {
30323       q._tasks[i] = null;
30324       if (t.abort) {
30325         try { t.abort(); }
30326         catch (e) { /* ignore */ }
30327       }
30328     }
30329   }
30330
30331   q._active = NaN; // allow notification
30332   maybeNotify(q);
30333 }
30334
30335 function maybeNotify(q) {
30336   if (!q._active && q._call) {
30337     var d = q._data;
30338     q._data = undefined; // allow gc
30339     q._call(q._error, d);
30340   }
30341 }
30342
30343 function queue(concurrency) {
30344   return new Queue(arguments.length ? +concurrency : Infinity);
30345 }
30346
30347 var uniform = function(min, max) {
30348   min = min == null ? 0 : +min;
30349   max = max == null ? 1 : +max;
30350   if (arguments.length === 1) max = min, min = 0;
30351   else max -= min;
30352   return function() {
30353     return Math.random() * max + min;
30354   };
30355 };
30356
30357 var normal = function(mu, sigma) {
30358   var x, r;
30359   mu = mu == null ? 0 : +mu;
30360   sigma = sigma == null ? 1 : +sigma;
30361   return function() {
30362     var y;
30363
30364     // If available, use the second previously-generated uniform random.
30365     if (x != null) y = x, x = null;
30366
30367     // Otherwise, generate a new x and y.
30368     else do {
30369       x = Math.random() * 2 - 1;
30370       y = Math.random() * 2 - 1;
30371       r = x * x + y * y;
30372     } while (!r || r > 1);
30373
30374     return mu + sigma * y * Math.sqrt(-2 * Math.log(r) / r);
30375   };
30376 };
30377
30378 var logNormal = function() {
30379   var randomNormal = normal.apply(this, arguments);
30380   return function() {
30381     return Math.exp(randomNormal());
30382   };
30383 };
30384
30385 var irwinHall = function(n) {
30386   return function() {
30387     for (var sum = 0, i = 0; i < n; ++i) sum += Math.random();
30388     return sum;
30389   };
30390 };
30391
30392 var bates = function(n) {
30393   var randomIrwinHall = irwinHall(n);
30394   return function() {
30395     return randomIrwinHall() / n;
30396   };
30397 };
30398
30399 var exponential$1 = function(lambda) {
30400   return function() {
30401     return -Math.log(1 - Math.random()) / lambda;
30402   };
30403 };
30404
30405 var request = function(url, callback) {
30406   var request,
30407       event = dispatch("beforesend", "progress", "load", "error"),
30408       mimeType,
30409       headers = map$1(),
30410       xhr = new XMLHttpRequest,
30411       user = null,
30412       password = null,
30413       response,
30414       responseType,
30415       timeout = 0;
30416
30417   // If IE does not support CORS, use XDomainRequest.
30418   if (typeof XDomainRequest !== "undefined"
30419       && !("withCredentials" in xhr)
30420       && /^(http(s)?:)?\/\//.test(url)) xhr = new XDomainRequest;
30421
30422   "onload" in xhr
30423       ? xhr.onload = xhr.onerror = xhr.ontimeout = respond
30424       : xhr.onreadystatechange = function(o) { xhr.readyState > 3 && respond(o); };
30425
30426   function respond(o) {
30427     var status = xhr.status, result;
30428     if (!status && hasResponse(xhr)
30429         || status >= 200 && status < 300
30430         || status === 304) {
30431       if (response) {
30432         try {
30433           result = response.call(request, xhr);
30434         } catch (e) {
30435           event.call("error", request, e);
30436           return;
30437         }
30438       } else {
30439         result = xhr;
30440       }
30441       event.call("load", request, result);
30442     } else {
30443       event.call("error", request, o);
30444     }
30445   }
30446
30447   xhr.onprogress = function(e) {
30448     event.call("progress", request, e);
30449   };
30450
30451   request = {
30452     header: function(name, value) {
30453       name = (name + "").toLowerCase();
30454       if (arguments.length < 2) return headers.get(name);
30455       if (value == null) headers.remove(name);
30456       else headers.set(name, value + "");
30457       return request;
30458     },
30459
30460     // If mimeType is non-null and no Accept header is set, a default is used.
30461     mimeType: function(value) {
30462       if (!arguments.length) return mimeType;
30463       mimeType = value == null ? null : value + "";
30464       return request;
30465     },
30466
30467     // Specifies what type the response value should take;
30468     // for instance, arraybuffer, blob, document, or text.
30469     responseType: function(value) {
30470       if (!arguments.length) return responseType;
30471       responseType = value;
30472       return request;
30473     },
30474
30475     timeout: function(value) {
30476       if (!arguments.length) return timeout;
30477       timeout = +value;
30478       return request;
30479     },
30480
30481     user: function(value) {
30482       return arguments.length < 1 ? user : (user = value == null ? null : value + "", request);
30483     },
30484
30485     password: function(value) {
30486       return arguments.length < 1 ? password : (password = value == null ? null : value + "", request);
30487     },
30488
30489     // Specify how to convert the response content to a specific type;
30490     // changes the callback value on "load" events.
30491     response: function(value) {
30492       response = value;
30493       return request;
30494     },
30495
30496     // Alias for send("GET", …).
30497     get: function(data, callback) {
30498       return request.send("GET", data, callback);
30499     },
30500
30501     // Alias for send("POST", …).
30502     post: function(data, callback) {
30503       return request.send("POST", data, callback);
30504     },
30505
30506     // If callback is non-null, it will be used for error and load events.
30507     send: function(method, data, callback) {
30508       xhr.open(method, url, true, user, password);
30509       if (mimeType != null && !headers.has("accept")) headers.set("accept", mimeType + ",*/*");
30510       if (xhr.setRequestHeader) headers.each(function(value, name) { xhr.setRequestHeader(name, value); });
30511       if (mimeType != null && xhr.overrideMimeType) xhr.overrideMimeType(mimeType);
30512       if (responseType != null) xhr.responseType = responseType;
30513       if (timeout > 0) xhr.timeout = timeout;
30514       if (callback == null && typeof data === "function") callback = data, data = null;
30515       if (callback != null && callback.length === 1) callback = fixCallback(callback);
30516       if (callback != null) request.on("error", callback).on("load", function(xhr) { callback(null, xhr); });
30517       event.call("beforesend", request, xhr);
30518       xhr.send(data == null ? null : data);
30519       return request;
30520     },
30521
30522     abort: function() {
30523       xhr.abort();
30524       return request;
30525     },
30526
30527     on: function() {
30528       var value = event.on.apply(event, arguments);
30529       return value === event ? request : value;
30530     }
30531   };
30532
30533   if (callback != null) {
30534     if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
30535     return request.get(callback);
30536   }
30537
30538   return request;
30539 };
30540
30541 function fixCallback(callback) {
30542   return function(error, xhr) {
30543     callback(error == null ? xhr : null);
30544   };
30545 }
30546
30547 function hasResponse(xhr) {
30548   var type = xhr.responseType;
30549   return type && type !== "text"
30550       ? xhr.response // null on error
30551       : xhr.responseText; // "" on error
30552 }
30553
30554 var type$3 = function(defaultMimeType, response) {
30555   return function(url, callback) {
30556     var r = request(url).mimeType(defaultMimeType).response(response);
30557     if (callback != null) {
30558       if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
30559       return r.get(callback);
30560     }
30561     return r;
30562   };
30563 };
30564
30565 var html = type$3("text/html", function(xhr) {
30566   return document.createRange().createContextualFragment(xhr.responseText);
30567 });
30568
30569 var json = type$3("application/json", function(xhr) {
30570   return JSON.parse(xhr.responseText);
30571 });
30572
30573 var text = type$3("text/plain", function(xhr) {
30574   return xhr.responseText;
30575 });
30576
30577 var xml = type$3("application/xml", function(xhr) {
30578   var xml = xhr.responseXML;
30579   if (!xml) throw new Error("parse error");
30580   return xml;
30581 });
30582
30583 var dsv$1 = function(defaultMimeType, parse) {
30584   return function(url, row, callback) {
30585     if (arguments.length < 3) callback = row, row = null;
30586     var r = request(url).mimeType(defaultMimeType);
30587     r.row = function(_) { return arguments.length ? r.response(responseOf(parse, row = _)) : row; };
30588     r.row(row);
30589     return callback ? r.get(callback) : r;
30590   };
30591 };
30592
30593 function responseOf(parse, row) {
30594   return function(request$$1) {
30595     return parse(request$$1.responseText, row);
30596   };
30597 }
30598
30599 var csv$1 = dsv$1("text/csv", csvParse);
30600
30601 var tsv$1 = dsv$1("text/tab-separated-values", tsvParse);
30602
30603 var array$2 = Array.prototype;
30604
30605 var map$3 = array$2.map;
30606 var slice$4 = array$2.slice;
30607
30608 var implicit = {name: "implicit"};
30609
30610 function ordinal(range) {
30611   var index = map$1(),
30612       domain = [],
30613       unknown = implicit;
30614
30615   range = range == null ? [] : slice$4.call(range);
30616
30617   function scale(d) {
30618     var key = d + "", i = index.get(key);
30619     if (!i) {
30620       if (unknown !== implicit) return unknown;
30621       index.set(key, i = domain.push(d));
30622     }
30623     return range[(i - 1) % range.length];
30624   }
30625
30626   scale.domain = function(_) {
30627     if (!arguments.length) return domain.slice();
30628     domain = [], index = map$1();
30629     var i = -1, n = _.length, d, key;
30630     while (++i < n) if (!index.has(key = (d = _[i]) + "")) index.set(key, domain.push(d));
30631     return scale;
30632   };
30633
30634   scale.range = function(_) {
30635     return arguments.length ? (range = slice$4.call(_), scale) : range.slice();
30636   };
30637
30638   scale.unknown = function(_) {
30639     return arguments.length ? (unknown = _, scale) : unknown;
30640   };
30641
30642   scale.copy = function() {
30643     return ordinal()
30644         .domain(domain)
30645         .range(range)
30646         .unknown(unknown);
30647   };
30648
30649   return scale;
30650 }
30651
30652 function band() {
30653   var scale = ordinal().unknown(undefined),
30654       domain = scale.domain,
30655       ordinalRange = scale.range,
30656       range$$1 = [0, 1],
30657       step,
30658       bandwidth,
30659       round = false,
30660       paddingInner = 0,
30661       paddingOuter = 0,
30662       align = 0.5;
30663
30664   delete scale.unknown;
30665
30666   function rescale() {
30667     var n = domain().length,
30668         reverse = range$$1[1] < range$$1[0],
30669         start = range$$1[reverse - 0],
30670         stop = range$$1[1 - reverse];
30671     step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2);
30672     if (round) step = Math.floor(step);
30673     start += (stop - start - step * (n - paddingInner)) * align;
30674     bandwidth = step * (1 - paddingInner);
30675     if (round) start = Math.round(start), bandwidth = Math.round(bandwidth);
30676     var values = sequence(n).map(function(i) { return start + step * i; });
30677     return ordinalRange(reverse ? values.reverse() : values);
30678   }
30679
30680   scale.domain = function(_) {
30681     return arguments.length ? (domain(_), rescale()) : domain();
30682   };
30683
30684   scale.range = function(_) {
30685     return arguments.length ? (range$$1 = [+_[0], +_[1]], rescale()) : range$$1.slice();
30686   };
30687
30688   scale.rangeRound = function(_) {
30689     return range$$1 = [+_[0], +_[1]], round = true, rescale();
30690   };
30691
30692   scale.bandwidth = function() {
30693     return bandwidth;
30694   };
30695
30696   scale.step = function() {
30697     return step;
30698   };
30699
30700   scale.round = function(_) {
30701     return arguments.length ? (round = !!_, rescale()) : round;
30702   };
30703
30704   scale.padding = function(_) {
30705     return arguments.length ? (paddingInner = paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
30706   };
30707
30708   scale.paddingInner = function(_) {
30709     return arguments.length ? (paddingInner = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
30710   };
30711
30712   scale.paddingOuter = function(_) {
30713     return arguments.length ? (paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingOuter;
30714   };
30715
30716   scale.align = function(_) {
30717     return arguments.length ? (align = Math.max(0, Math.min(1, _)), rescale()) : align;
30718   };
30719
30720   scale.copy = function() {
30721     return band()
30722         .domain(domain())
30723         .range(range$$1)
30724         .round(round)
30725         .paddingInner(paddingInner)
30726         .paddingOuter(paddingOuter)
30727         .align(align);
30728   };
30729
30730   return rescale();
30731 }
30732
30733 function pointish(scale) {
30734   var copy = scale.copy;
30735
30736   scale.padding = scale.paddingOuter;
30737   delete scale.paddingInner;
30738   delete scale.paddingOuter;
30739
30740   scale.copy = function() {
30741     return pointish(copy());
30742   };
30743
30744   return scale;
30745 }
30746
30747 function point$1() {
30748   return pointish(band().paddingInner(1));
30749 }
30750
30751 var constant$9 = function(x) {
30752   return function() {
30753     return x;
30754   };
30755 };
30756
30757 var number$1 = function(x) {
30758   return +x;
30759 };
30760
30761 var unit = [0, 1];
30762
30763 function deinterpolateLinear(a, b) {
30764   return (b -= (a = +a))
30765       ? function(x) { return (x - a) / b; }
30766       : constant$9(b);
30767 }
30768
30769 function deinterpolateClamp(deinterpolate) {
30770   return function(a, b) {
30771     var d = deinterpolate(a = +a, b = +b);
30772     return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); };
30773   };
30774 }
30775
30776 function reinterpolateClamp(reinterpolate) {
30777   return function(a, b) {
30778     var r = reinterpolate(a = +a, b = +b);
30779     return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); };
30780   };
30781 }
30782
30783 function bimap(domain, range$$1, deinterpolate, reinterpolate) {
30784   var d0 = domain[0], d1 = domain[1], r0 = range$$1[0], r1 = range$$1[1];
30785   if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate(r1, r0);
30786   else d0 = deinterpolate(d0, d1), r0 = reinterpolate(r0, r1);
30787   return function(x) { return r0(d0(x)); };
30788 }
30789
30790 function polymap(domain, range$$1, deinterpolate, reinterpolate) {
30791   var j = Math.min(domain.length, range$$1.length) - 1,
30792       d = new Array(j),
30793       r = new Array(j),
30794       i = -1;
30795
30796   // Reverse descending domains.
30797   if (domain[j] < domain[0]) {
30798     domain = domain.slice().reverse();
30799     range$$1 = range$$1.slice().reverse();
30800   }
30801
30802   while (++i < j) {
30803     d[i] = deinterpolate(domain[i], domain[i + 1]);
30804     r[i] = reinterpolate(range$$1[i], range$$1[i + 1]);
30805   }
30806
30807   return function(x) {
30808     var i = bisectRight(domain, x, 1, j) - 1;
30809     return r[i](d[i](x));
30810   };
30811 }
30812
30813 function copy(source, target) {
30814   return target
30815       .domain(source.domain())
30816       .range(source.range())
30817       .interpolate(source.interpolate())
30818       .clamp(source.clamp());
30819 }
30820
30821 // deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
30822 // reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].
30823 function continuous(deinterpolate, reinterpolate) {
30824   var domain = unit,
30825       range$$1 = unit,
30826       interpolate$$1 = interpolateValue,
30827       clamp = false,
30828       piecewise,
30829       output,
30830       input;
30831
30832   function rescale() {
30833     piecewise = Math.min(domain.length, range$$1.length) > 2 ? polymap : bimap;
30834     output = input = null;
30835     return scale;
30836   }
30837
30838   function scale(x) {
30839     return (output || (output = piecewise(domain, range$$1, clamp ? deinterpolateClamp(deinterpolate) : deinterpolate, interpolate$$1)))(+x);
30840   }
30841
30842   scale.invert = function(y) {
30843     return (input || (input = piecewise(range$$1, domain, deinterpolateLinear, clamp ? reinterpolateClamp(reinterpolate) : reinterpolate)))(+y);
30844   };
30845
30846   scale.domain = function(_) {
30847     return arguments.length ? (domain = map$3.call(_, number$1), rescale()) : domain.slice();
30848   };
30849
30850   scale.range = function(_) {
30851     return arguments.length ? (range$$1 = slice$4.call(_), rescale()) : range$$1.slice();
30852   };
30853
30854   scale.rangeRound = function(_) {
30855     return range$$1 = slice$4.call(_), interpolate$$1 = interpolateRound, rescale();
30856   };
30857
30858   scale.clamp = function(_) {
30859     return arguments.length ? (clamp = !!_, rescale()) : clamp;
30860   };
30861
30862   scale.interpolate = function(_) {
30863     return arguments.length ? (interpolate$$1 = _, rescale()) : interpolate$$1;
30864   };
30865
30866   return rescale();
30867 }
30868
30869 var tickFormat = function(domain, count, specifier) {
30870   var start = domain[0],
30871       stop = domain[domain.length - 1],
30872       step = tickStep(start, stop, count == null ? 10 : count),
30873       precision;
30874   specifier = formatSpecifier(specifier == null ? ",f" : specifier);
30875   switch (specifier.type) {
30876     case "s": {
30877       var value = Math.max(Math.abs(start), Math.abs(stop));
30878       if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
30879       return formatPrefix(specifier, value);
30880     }
30881     case "":
30882     case "e":
30883     case "g":
30884     case "p":
30885     case "r": {
30886       if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
30887       break;
30888     }
30889     case "f":
30890     case "%": {
30891       if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
30892       break;
30893     }
30894   }
30895   return format(specifier);
30896 };
30897
30898 function linearish(scale) {
30899   var domain = scale.domain;
30900
30901   scale.ticks = function(count) {
30902     var d = domain();
30903     return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
30904   };
30905
30906   scale.tickFormat = function(count, specifier) {
30907     return tickFormat(domain(), count, specifier);
30908   };
30909
30910   scale.nice = function(count) {
30911     var d = domain(),
30912         i = d.length - 1,
30913         n = count == null ? 10 : count,
30914         start = d[0],
30915         stop = d[i],
30916         step = tickStep(start, stop, n);
30917
30918     if (step) {
30919       step = tickStep(Math.floor(start / step) * step, Math.ceil(stop / step) * step, n);
30920       d[0] = Math.floor(start / step) * step;
30921       d[i] = Math.ceil(stop / step) * step;
30922       domain(d);
30923     }
30924
30925     return scale;
30926   };
30927
30928   return scale;
30929 }
30930
30931 function linear$2() {
30932   var scale = continuous(deinterpolateLinear, reinterpolate);
30933
30934   scale.copy = function() {
30935     return copy(scale, linear$2());
30936   };
30937
30938   return linearish(scale);
30939 }
30940
30941 function identity$6() {
30942   var domain = [0, 1];
30943
30944   function scale(x) {
30945     return +x;
30946   }
30947
30948   scale.invert = scale;
30949
30950   scale.domain = scale.range = function(_) {
30951     return arguments.length ? (domain = map$3.call(_, number$1), scale) : domain.slice();
30952   };
30953
30954   scale.copy = function() {
30955     return identity$6().domain(domain);
30956   };
30957
30958   return linearish(scale);
30959 }
30960
30961 var nice = function(domain, interval) {
30962   domain = domain.slice();
30963
30964   var i0 = 0,
30965       i1 = domain.length - 1,
30966       x0 = domain[i0],
30967       x1 = domain[i1],
30968       t;
30969
30970   if (x1 < x0) {
30971     t = i0, i0 = i1, i1 = t;
30972     t = x0, x0 = x1, x1 = t;
30973   }
30974
30975   domain[i0] = interval.floor(x0);
30976   domain[i1] = interval.ceil(x1);
30977   return domain;
30978 };
30979
30980 function deinterpolate(a, b) {
30981   return (b = Math.log(b / a))
30982       ? function(x) { return Math.log(x / a) / b; }
30983       : constant$9(b);
30984 }
30985
30986 function reinterpolate$1(a, b) {
30987   return a < 0
30988       ? function(t) { return -Math.pow(-b, t) * Math.pow(-a, 1 - t); }
30989       : function(t) { return Math.pow(b, t) * Math.pow(a, 1 - t); };
30990 }
30991
30992 function pow10(x) {
30993   return isFinite(x) ? +("1e" + x) : x < 0 ? 0 : x;
30994 }
30995
30996 function powp(base) {
30997   return base === 10 ? pow10
30998       : base === Math.E ? Math.exp
30999       : function(x) { return Math.pow(base, x); };
31000 }
31001
31002 function logp(base) {
31003   return base === Math.E ? Math.log
31004       : base === 10 && Math.log10
31005       || base === 2 && Math.log2
31006       || (base = Math.log(base), function(x) { return Math.log(x) / base; });
31007 }
31008
31009 function reflect(f) {
31010   return function(x) {
31011     return -f(-x);
31012   };
31013 }
31014
31015 function log$1() {
31016   var scale = continuous(deinterpolate, reinterpolate$1).domain([1, 10]),
31017       domain = scale.domain,
31018       base = 10,
31019       logs = logp(10),
31020       pows = powp(10);
31021
31022   function rescale() {
31023     logs = logp(base), pows = powp(base);
31024     if (domain()[0] < 0) logs = reflect(logs), pows = reflect(pows);
31025     return scale;
31026   }
31027
31028   scale.base = function(_) {
31029     return arguments.length ? (base = +_, rescale()) : base;
31030   };
31031
31032   scale.domain = function(_) {
31033     return arguments.length ? (domain(_), rescale()) : domain();
31034   };
31035
31036   scale.ticks = function(count) {
31037     var d = domain(),
31038         u = d[0],
31039         v = d[d.length - 1],
31040         r;
31041
31042     if (r = v < u) i = u, u = v, v = i;
31043
31044     var i = logs(u),
31045         j = logs(v),
31046         p,
31047         k,
31048         t,
31049         n = count == null ? 10 : +count,
31050         z = [];
31051
31052     if (!(base % 1) && j - i < n) {
31053       i = Math.round(i) - 1, j = Math.round(j) + 1;
31054       if (u > 0) for (; i < j; ++i) {
31055         for (k = 1, p = pows(i); k < base; ++k) {
31056           t = p * k;
31057           if (t < u) continue;
31058           if (t > v) break;
31059           z.push(t);
31060         }
31061       } else for (; i < j; ++i) {
31062         for (k = base - 1, p = pows(i); k >= 1; --k) {
31063           t = p * k;
31064           if (t < u) continue;
31065           if (t > v) break;
31066           z.push(t);
31067         }
31068       }
31069     } else {
31070       z = ticks(i, j, Math.min(j - i, n)).map(pows);
31071     }
31072
31073     return r ? z.reverse() : z;
31074   };
31075
31076   scale.tickFormat = function(count, specifier) {
31077     if (specifier == null) specifier = base === 10 ? ".0e" : ",";
31078     if (typeof specifier !== "function") specifier = format(specifier);
31079     if (count === Infinity) return specifier;
31080     if (count == null) count = 10;
31081     var k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate?
31082     return function(d) {
31083       var i = d / pows(Math.round(logs(d)));
31084       if (i * base < base - 0.5) i *= base;
31085       return i <= k ? specifier(d) : "";
31086     };
31087   };
31088
31089   scale.nice = function() {
31090     return domain(nice(domain(), {
31091       floor: function(x) { return pows(Math.floor(logs(x))); },
31092       ceil: function(x) { return pows(Math.ceil(logs(x))); }
31093     }));
31094   };
31095
31096   scale.copy = function() {
31097     return copy(scale, log$1().base(base));
31098   };
31099
31100   return scale;
31101 }
31102
31103 function raise$1(x, exponent) {
31104   return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent);
31105 }
31106
31107 function pow$1() {
31108   var exponent = 1,
31109       scale = continuous(deinterpolate, reinterpolate),
31110       domain = scale.domain;
31111
31112   function deinterpolate(a, b) {
31113     return (b = raise$1(b, exponent) - (a = raise$1(a, exponent)))
31114         ? function(x) { return (raise$1(x, exponent) - a) / b; }
31115         : constant$9(b);
31116   }
31117
31118   function reinterpolate(a, b) {
31119     b = raise$1(b, exponent) - (a = raise$1(a, exponent));
31120     return function(t) { return raise$1(a + b * t, 1 / exponent); };
31121   }
31122
31123   scale.exponent = function(_) {
31124     return arguments.length ? (exponent = +_, domain(domain())) : exponent;
31125   };
31126
31127   scale.copy = function() {
31128     return copy(scale, pow$1().exponent(exponent));
31129   };
31130
31131   return linearish(scale);
31132 }
31133
31134 function sqrt$1() {
31135   return pow$1().exponent(0.5);
31136 }
31137
31138 function quantile$$1() {
31139   var domain = [],
31140       range$$1 = [],
31141       thresholds = [];
31142
31143   function rescale() {
31144     var i = 0, n = Math.max(1, range$$1.length);
31145     thresholds = new Array(n - 1);
31146     while (++i < n) thresholds[i - 1] = threshold(domain, i / n);
31147     return scale;
31148   }
31149
31150   function scale(x) {
31151     if (!isNaN(x = +x)) return range$$1[bisectRight(thresholds, x)];
31152   }
31153
31154   scale.invertExtent = function(y) {
31155     var i = range$$1.indexOf(y);
31156     return i < 0 ? [NaN, NaN] : [
31157       i > 0 ? thresholds[i - 1] : domain[0],
31158       i < thresholds.length ? thresholds[i] : domain[domain.length - 1]
31159     ];
31160   };
31161
31162   scale.domain = function(_) {
31163     if (!arguments.length) return domain.slice();
31164     domain = [];
31165     for (var i = 0, n = _.length, d; i < n; ++i) if (d = _[i], d != null && !isNaN(d = +d)) domain.push(d);
31166     domain.sort(ascending);
31167     return rescale();
31168   };
31169
31170   scale.range = function(_) {
31171     return arguments.length ? (range$$1 = slice$4.call(_), rescale()) : range$$1.slice();
31172   };
31173
31174   scale.quantiles = function() {
31175     return thresholds.slice();
31176   };
31177
31178   scale.copy = function() {
31179     return quantile$$1()
31180         .domain(domain)
31181         .range(range$$1);
31182   };
31183
31184   return scale;
31185 }
31186
31187 function quantize$1() {
31188   var x0 = 0,
31189       x1 = 1,
31190       n = 1,
31191       domain = [0.5],
31192       range$$1 = [0, 1];
31193
31194   function scale(x) {
31195     if (x <= x) return range$$1[bisectRight(domain, x, 0, n)];
31196   }
31197
31198   function rescale() {
31199     var i = -1;
31200     domain = new Array(n);
31201     while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
31202     return scale;
31203   }
31204
31205   scale.domain = function(_) {
31206     return arguments.length ? (x0 = +_[0], x1 = +_[1], rescale()) : [x0, x1];
31207   };
31208
31209   scale.range = function(_) {
31210     return arguments.length ? (n = (range$$1 = slice$4.call(_)).length - 1, rescale()) : range$$1.slice();
31211   };
31212
31213   scale.invertExtent = function(y) {
31214     var i = range$$1.indexOf(y);
31215     return i < 0 ? [NaN, NaN]
31216         : i < 1 ? [x0, domain[0]]
31217         : i >= n ? [domain[n - 1], x1]
31218         : [domain[i - 1], domain[i]];
31219   };
31220
31221   scale.copy = function() {
31222     return quantize$1()
31223         .domain([x0, x1])
31224         .range(range$$1);
31225   };
31226
31227   return linearish(scale);
31228 }
31229
31230 function threshold$1() {
31231   var domain = [0.5],
31232       range$$1 = [0, 1],
31233       n = 1;
31234
31235   function scale(x) {
31236     if (x <= x) return range$$1[bisectRight(domain, x, 0, n)];
31237   }
31238
31239   scale.domain = function(_) {
31240     return arguments.length ? (domain = slice$4.call(_), n = Math.min(domain.length, range$$1.length - 1), scale) : domain.slice();
31241   };
31242
31243   scale.range = function(_) {
31244     return arguments.length ? (range$$1 = slice$4.call(_), n = Math.min(domain.length, range$$1.length - 1), scale) : range$$1.slice();
31245   };
31246
31247   scale.invertExtent = function(y) {
31248     var i = range$$1.indexOf(y);
31249     return [domain[i - 1], domain[i]];
31250   };
31251
31252   scale.copy = function() {
31253     return threshold$1()
31254         .domain(domain)
31255         .range(range$$1);
31256   };
31257
31258   return scale;
31259 }
31260
31261 var t0$1 = new Date;
31262 var t1$1 = new Date;
31263
31264 function newInterval(floori, offseti, count, field) {
31265
31266   function interval(date) {
31267     return floori(date = new Date(+date)), date;
31268   }
31269
31270   interval.floor = interval;
31271
31272   interval.ceil = function(date) {
31273     return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;
31274   };
31275
31276   interval.round = function(date) {
31277     var d0 = interval(date),
31278         d1 = interval.ceil(date);
31279     return date - d0 < d1 - date ? d0 : d1;
31280   };
31281
31282   interval.offset = function(date, step) {
31283     return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;
31284   };
31285
31286   interval.range = function(start, stop, step) {
31287     var range = [];
31288     start = interval.ceil(start);
31289     step = step == null ? 1 : Math.floor(step);
31290     if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date
31291     do range.push(new Date(+start)); while (offseti(start, step), floori(start), start < stop)
31292     return range;
31293   };
31294
31295   interval.filter = function(test) {
31296     return newInterval(function(date) {
31297       if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1);
31298     }, function(date, step) {
31299       if (date >= date) while (--step >= 0) while (offseti(date, 1), !test(date)) {} // eslint-disable-line no-empty
31300     });
31301   };
31302
31303   if (count) {
31304     interval.count = function(start, end) {
31305       t0$1.setTime(+start), t1$1.setTime(+end);
31306       floori(t0$1), floori(t1$1);
31307       return Math.floor(count(t0$1, t1$1));
31308     };
31309
31310     interval.every = function(step) {
31311       step = Math.floor(step);
31312       return !isFinite(step) || !(step > 0) ? null
31313           : !(step > 1) ? interval
31314           : interval.filter(field
31315               ? function(d) { return field(d) % step === 0; }
31316               : function(d) { return interval.count(0, d) % step === 0; });
31317     };
31318   }
31319
31320   return interval;
31321 }
31322
31323 var millisecond = newInterval(function() {
31324   // noop
31325 }, function(date, step) {
31326   date.setTime(+date + step);
31327 }, function(start, end) {
31328   return end - start;
31329 });
31330
31331 // An optimized implementation for this simple case.
31332 millisecond.every = function(k) {
31333   k = Math.floor(k);
31334   if (!isFinite(k) || !(k > 0)) return null;
31335   if (!(k > 1)) return millisecond;
31336   return newInterval(function(date) {
31337     date.setTime(Math.floor(date / k) * k);
31338   }, function(date, step) {
31339     date.setTime(+date + step * k);
31340   }, function(start, end) {
31341     return (end - start) / k;
31342   });
31343 };
31344
31345 var milliseconds = millisecond.range;
31346
31347 var durationSecond$1 = 1e3;
31348 var durationMinute$1 = 6e4;
31349 var durationHour$1 = 36e5;
31350 var durationDay$1 = 864e5;
31351 var durationWeek$1 = 6048e5;
31352
31353 var second = newInterval(function(date) {
31354   date.setTime(Math.floor(date / durationSecond$1) * durationSecond$1);
31355 }, function(date, step) {
31356   date.setTime(+date + step * durationSecond$1);
31357 }, function(start, end) {
31358   return (end - start) / durationSecond$1;
31359 }, function(date) {
31360   return date.getUTCSeconds();
31361 });
31362
31363 var seconds = second.range;
31364
31365 var minute = newInterval(function(date) {
31366   date.setTime(Math.floor(date / durationMinute$1) * durationMinute$1);
31367 }, function(date, step) {
31368   date.setTime(+date + step * durationMinute$1);
31369 }, function(start, end) {
31370   return (end - start) / durationMinute$1;
31371 }, function(date) {
31372   return date.getMinutes();
31373 });
31374
31375 var minutes = minute.range;
31376
31377 var hour = newInterval(function(date) {
31378   var offset = date.getTimezoneOffset() * durationMinute$1 % durationHour$1;
31379   if (offset < 0) offset += durationHour$1;
31380   date.setTime(Math.floor((+date - offset) / durationHour$1) * durationHour$1 + offset);
31381 }, function(date, step) {
31382   date.setTime(+date + step * durationHour$1);
31383 }, function(start, end) {
31384   return (end - start) / durationHour$1;
31385 }, function(date) {
31386   return date.getHours();
31387 });
31388
31389 var hours = hour.range;
31390
31391 var day = newInterval(function(date) {
31392   date.setHours(0, 0, 0, 0);
31393 }, function(date, step) {
31394   date.setDate(date.getDate() + step);
31395 }, function(start, end) {
31396   return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute$1) / durationDay$1;
31397 }, function(date) {
31398   return date.getDate() - 1;
31399 });
31400
31401 var days = day.range;
31402
31403 function weekday(i) {
31404   return newInterval(function(date) {
31405     date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
31406     date.setHours(0, 0, 0, 0);
31407   }, function(date, step) {
31408     date.setDate(date.getDate() + step * 7);
31409   }, function(start, end) {
31410     return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute$1) / durationWeek$1;
31411   });
31412 }
31413
31414 var sunday = weekday(0);
31415 var monday = weekday(1);
31416 var tuesday = weekday(2);
31417 var wednesday = weekday(3);
31418 var thursday = weekday(4);
31419 var friday = weekday(5);
31420 var saturday = weekday(6);
31421
31422 var sundays = sunday.range;
31423 var mondays = monday.range;
31424 var tuesdays = tuesday.range;
31425 var wednesdays = wednesday.range;
31426 var thursdays = thursday.range;
31427 var fridays = friday.range;
31428 var saturdays = saturday.range;
31429
31430 var month = newInterval(function(date) {
31431   date.setDate(1);
31432   date.setHours(0, 0, 0, 0);
31433 }, function(date, step) {
31434   date.setMonth(date.getMonth() + step);
31435 }, function(start, end) {
31436   return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
31437 }, function(date) {
31438   return date.getMonth();
31439 });
31440
31441 var months = month.range;
31442
31443 var year = newInterval(function(date) {
31444   date.setMonth(0, 1);
31445   date.setHours(0, 0, 0, 0);
31446 }, function(date, step) {
31447   date.setFullYear(date.getFullYear() + step);
31448 }, function(start, end) {
31449   return end.getFullYear() - start.getFullYear();
31450 }, function(date) {
31451   return date.getFullYear();
31452 });
31453
31454 // An optimized implementation for this simple case.
31455 year.every = function(k) {
31456   return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
31457     date.setFullYear(Math.floor(date.getFullYear() / k) * k);
31458     date.setMonth(0, 1);
31459     date.setHours(0, 0, 0, 0);
31460   }, function(date, step) {
31461     date.setFullYear(date.getFullYear() + step * k);
31462   });
31463 };
31464
31465 var years = year.range;
31466
31467 var utcMinute = newInterval(function(date) {
31468   date.setUTCSeconds(0, 0);
31469 }, function(date, step) {
31470   date.setTime(+date + step * durationMinute$1);
31471 }, function(start, end) {
31472   return (end - start) / durationMinute$1;
31473 }, function(date) {
31474   return date.getUTCMinutes();
31475 });
31476
31477 var utcMinutes = utcMinute.range;
31478
31479 var utcHour = newInterval(function(date) {
31480   date.setUTCMinutes(0, 0, 0);
31481 }, function(date, step) {
31482   date.setTime(+date + step * durationHour$1);
31483 }, function(start, end) {
31484   return (end - start) / durationHour$1;
31485 }, function(date) {
31486   return date.getUTCHours();
31487 });
31488
31489 var utcHours = utcHour.range;
31490
31491 var utcDay = newInterval(function(date) {
31492   date.setUTCHours(0, 0, 0, 0);
31493 }, function(date, step) {
31494   date.setUTCDate(date.getUTCDate() + step);
31495 }, function(start, end) {
31496   return (end - start) / durationDay$1;
31497 }, function(date) {
31498   return date.getUTCDate() - 1;
31499 });
31500
31501 var utcDays = utcDay.range;
31502
31503 function utcWeekday(i) {
31504   return newInterval(function(date) {
31505     date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
31506     date.setUTCHours(0, 0, 0, 0);
31507   }, function(date, step) {
31508     date.setUTCDate(date.getUTCDate() + step * 7);
31509   }, function(start, end) {
31510     return (end - start) / durationWeek$1;
31511   });
31512 }
31513
31514 var utcSunday = utcWeekday(0);
31515 var utcMonday = utcWeekday(1);
31516 var utcTuesday = utcWeekday(2);
31517 var utcWednesday = utcWeekday(3);
31518 var utcThursday = utcWeekday(4);
31519 var utcFriday = utcWeekday(5);
31520 var utcSaturday = utcWeekday(6);
31521
31522 var utcSundays = utcSunday.range;
31523 var utcMondays = utcMonday.range;
31524 var utcTuesdays = utcTuesday.range;
31525 var utcWednesdays = utcWednesday.range;
31526 var utcThursdays = utcThursday.range;
31527 var utcFridays = utcFriday.range;
31528 var utcSaturdays = utcSaturday.range;
31529
31530 var utcMonth = newInterval(function(date) {
31531   date.setUTCDate(1);
31532   date.setUTCHours(0, 0, 0, 0);
31533 }, function(date, step) {
31534   date.setUTCMonth(date.getUTCMonth() + step);
31535 }, function(start, end) {
31536   return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;
31537 }, function(date) {
31538   return date.getUTCMonth();
31539 });
31540
31541 var utcMonths = utcMonth.range;
31542
31543 var utcYear = newInterval(function(date) {
31544   date.setUTCMonth(0, 1);
31545   date.setUTCHours(0, 0, 0, 0);
31546 }, function(date, step) {
31547   date.setUTCFullYear(date.getUTCFullYear() + step);
31548 }, function(start, end) {
31549   return end.getUTCFullYear() - start.getUTCFullYear();
31550 }, function(date) {
31551   return date.getUTCFullYear();
31552 });
31553
31554 // An optimized implementation for this simple case.
31555 utcYear.every = function(k) {
31556   return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
31557     date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);
31558     date.setUTCMonth(0, 1);
31559     date.setUTCHours(0, 0, 0, 0);
31560   }, function(date, step) {
31561     date.setUTCFullYear(date.getUTCFullYear() + step * k);
31562   });
31563 };
31564
31565 var utcYears = utcYear.range;
31566
31567 function localDate(d) {
31568   if (0 <= d.y && d.y < 100) {
31569     var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L);
31570     date.setFullYear(d.y);
31571     return date;
31572   }
31573   return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L);
31574 }
31575
31576 function utcDate(d) {
31577   if (0 <= d.y && d.y < 100) {
31578     var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L));
31579     date.setUTCFullYear(d.y);
31580     return date;
31581   }
31582   return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));
31583 }
31584
31585 function newYear(y) {
31586   return {y: y, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0};
31587 }
31588
31589 function formatLocale$1(locale) {
31590   var locale_dateTime = locale.dateTime,
31591       locale_date = locale.date,
31592       locale_time = locale.time,
31593       locale_periods = locale.periods,
31594       locale_weekdays = locale.days,
31595       locale_shortWeekdays = locale.shortDays,
31596       locale_months = locale.months,
31597       locale_shortMonths = locale.shortMonths;
31598
31599   var periodRe = formatRe(locale_periods),
31600       periodLookup = formatLookup(locale_periods),
31601       weekdayRe = formatRe(locale_weekdays),
31602       weekdayLookup = formatLookup(locale_weekdays),
31603       shortWeekdayRe = formatRe(locale_shortWeekdays),
31604       shortWeekdayLookup = formatLookup(locale_shortWeekdays),
31605       monthRe = formatRe(locale_months),
31606       monthLookup = formatLookup(locale_months),
31607       shortMonthRe = formatRe(locale_shortMonths),
31608       shortMonthLookup = formatLookup(locale_shortMonths);
31609
31610   var formats = {
31611     "a": formatShortWeekday,
31612     "A": formatWeekday,
31613     "b": formatShortMonth,
31614     "B": formatMonth,
31615     "c": null,
31616     "d": formatDayOfMonth,
31617     "e": formatDayOfMonth,
31618     "H": formatHour24,
31619     "I": formatHour12,
31620     "j": formatDayOfYear,
31621     "L": formatMilliseconds,
31622     "m": formatMonthNumber,
31623     "M": formatMinutes,
31624     "p": formatPeriod,
31625     "S": formatSeconds,
31626     "U": formatWeekNumberSunday,
31627     "w": formatWeekdayNumber,
31628     "W": formatWeekNumberMonday,
31629     "x": null,
31630     "X": null,
31631     "y": formatYear,
31632     "Y": formatFullYear,
31633     "Z": formatZone,
31634     "%": formatLiteralPercent
31635   };
31636
31637   var utcFormats = {
31638     "a": formatUTCShortWeekday,
31639     "A": formatUTCWeekday,
31640     "b": formatUTCShortMonth,
31641     "B": formatUTCMonth,
31642     "c": null,
31643     "d": formatUTCDayOfMonth,
31644     "e": formatUTCDayOfMonth,
31645     "H": formatUTCHour24,
31646     "I": formatUTCHour12,
31647     "j": formatUTCDayOfYear,
31648     "L": formatUTCMilliseconds,
31649     "m": formatUTCMonthNumber,
31650     "M": formatUTCMinutes,
31651     "p": formatUTCPeriod,
31652     "S": formatUTCSeconds,
31653     "U": formatUTCWeekNumberSunday,
31654     "w": formatUTCWeekdayNumber,
31655     "W": formatUTCWeekNumberMonday,
31656     "x": null,
31657     "X": null,
31658     "y": formatUTCYear,
31659     "Y": formatUTCFullYear,
31660     "Z": formatUTCZone,
31661     "%": formatLiteralPercent
31662   };
31663
31664   var parses = {
31665     "a": parseShortWeekday,
31666     "A": parseWeekday,
31667     "b": parseShortMonth,
31668     "B": parseMonth,
31669     "c": parseLocaleDateTime,
31670     "d": parseDayOfMonth,
31671     "e": parseDayOfMonth,
31672     "H": parseHour24,
31673     "I": parseHour24,
31674     "j": parseDayOfYear,
31675     "L": parseMilliseconds,
31676     "m": parseMonthNumber,
31677     "M": parseMinutes,
31678     "p": parsePeriod,
31679     "S": parseSeconds,
31680     "U": parseWeekNumberSunday,
31681     "w": parseWeekdayNumber,
31682     "W": parseWeekNumberMonday,
31683     "x": parseLocaleDate,
31684     "X": parseLocaleTime,
31685     "y": parseYear,
31686     "Y": parseFullYear,
31687     "Z": parseZone,
31688     "%": parseLiteralPercent
31689   };
31690
31691   // These recursive directive definitions must be deferred.
31692   formats.x = newFormat(locale_date, formats);
31693   formats.X = newFormat(locale_time, formats);
31694   formats.c = newFormat(locale_dateTime, formats);
31695   utcFormats.x = newFormat(locale_date, utcFormats);
31696   utcFormats.X = newFormat(locale_time, utcFormats);
31697   utcFormats.c = newFormat(locale_dateTime, utcFormats);
31698
31699   function newFormat(specifier, formats) {
31700     return function(date) {
31701       var string = [],
31702           i = -1,
31703           j = 0,
31704           n = specifier.length,
31705           c,
31706           pad,
31707           format;
31708
31709       if (!(date instanceof Date)) date = new Date(+date);
31710
31711       while (++i < n) {
31712         if (specifier.charCodeAt(i) === 37) {
31713           string.push(specifier.slice(j, i));
31714           if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);
31715           else pad = c === "e" ? " " : "0";
31716           if (format = formats[c]) c = format(date, pad);
31717           string.push(c);
31718           j = i + 1;
31719         }
31720       }
31721
31722       string.push(specifier.slice(j, i));
31723       return string.join("");
31724     };
31725   }
31726
31727   function newParse(specifier, newDate) {
31728     return function(string) {
31729       var d = newYear(1900),
31730           i = parseSpecifier(d, specifier, string += "", 0);
31731       if (i != string.length) return null;
31732
31733       // The am-pm flag is 0 for AM, and 1 for PM.
31734       if ("p" in d) d.H = d.H % 12 + d.p * 12;
31735
31736       // Convert day-of-week and week-of-year to day-of-year.
31737       if ("W" in d || "U" in d) {
31738         if (!("w" in d)) d.w = "W" in d ? 1 : 0;
31739         var day$$1 = "Z" in d ? utcDate(newYear(d.y)).getUTCDay() : newDate(newYear(d.y)).getDay();
31740         d.m = 0;
31741         d.d = "W" in d ? (d.w + 6) % 7 + d.W * 7 - (day$$1 + 5) % 7 : d.w + d.U * 7 - (day$$1 + 6) % 7;
31742       }
31743
31744       // If a time zone is specified, all fields are interpreted as UTC and then
31745       // offset according to the specified time zone.
31746       if ("Z" in d) {
31747         d.H += d.Z / 100 | 0;
31748         d.M += d.Z % 100;
31749         return utcDate(d);
31750       }
31751
31752       // Otherwise, all fields are in local time.
31753       return newDate(d);
31754     };
31755   }
31756
31757   function parseSpecifier(d, specifier, string, j) {
31758     var i = 0,
31759         n = specifier.length,
31760         m = string.length,
31761         c,
31762         parse;
31763
31764     while (i < n) {
31765       if (j >= m) return -1;
31766       c = specifier.charCodeAt(i++);
31767       if (c === 37) {
31768         c = specifier.charAt(i++);
31769         parse = parses[c in pads ? specifier.charAt(i++) : c];
31770         if (!parse || ((j = parse(d, string, j)) < 0)) return -1;
31771       } else if (c != string.charCodeAt(j++)) {
31772         return -1;
31773       }
31774     }
31775
31776     return j;
31777   }
31778
31779   function parsePeriod(d, string, i) {
31780     var n = periodRe.exec(string.slice(i));
31781     return n ? (d.p = periodLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31782   }
31783
31784   function parseShortWeekday(d, string, i) {
31785     var n = shortWeekdayRe.exec(string.slice(i));
31786     return n ? (d.w = shortWeekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31787   }
31788
31789   function parseWeekday(d, string, i) {
31790     var n = weekdayRe.exec(string.slice(i));
31791     return n ? (d.w = weekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31792   }
31793
31794   function parseShortMonth(d, string, i) {
31795     var n = shortMonthRe.exec(string.slice(i));
31796     return n ? (d.m = shortMonthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31797   }
31798
31799   function parseMonth(d, string, i) {
31800     var n = monthRe.exec(string.slice(i));
31801     return n ? (d.m = monthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31802   }
31803
31804   function parseLocaleDateTime(d, string, i) {
31805     return parseSpecifier(d, locale_dateTime, string, i);
31806   }
31807
31808   function parseLocaleDate(d, string, i) {
31809     return parseSpecifier(d, locale_date, string, i);
31810   }
31811
31812   function parseLocaleTime(d, string, i) {
31813     return parseSpecifier(d, locale_time, string, i);
31814   }
31815
31816   function formatShortWeekday(d) {
31817     return locale_shortWeekdays[d.getDay()];
31818   }
31819
31820   function formatWeekday(d) {
31821     return locale_weekdays[d.getDay()];
31822   }
31823
31824   function formatShortMonth(d) {
31825     return locale_shortMonths[d.getMonth()];
31826   }
31827
31828   function formatMonth(d) {
31829     return locale_months[d.getMonth()];
31830   }
31831
31832   function formatPeriod(d) {
31833     return locale_periods[+(d.getHours() >= 12)];
31834   }
31835
31836   function formatUTCShortWeekday(d) {
31837     return locale_shortWeekdays[d.getUTCDay()];
31838   }
31839
31840   function formatUTCWeekday(d) {
31841     return locale_weekdays[d.getUTCDay()];
31842   }
31843
31844   function formatUTCShortMonth(d) {
31845     return locale_shortMonths[d.getUTCMonth()];
31846   }
31847
31848   function formatUTCMonth(d) {
31849     return locale_months[d.getUTCMonth()];
31850   }
31851
31852   function formatUTCPeriod(d) {
31853     return locale_periods[+(d.getUTCHours() >= 12)];
31854   }
31855
31856   return {
31857     format: function(specifier) {
31858       var f = newFormat(specifier += "", formats);
31859       f.toString = function() { return specifier; };
31860       return f;
31861     },
31862     parse: function(specifier) {
31863       var p = newParse(specifier += "", localDate);
31864       p.toString = function() { return specifier; };
31865       return p;
31866     },
31867     utcFormat: function(specifier) {
31868       var f = newFormat(specifier += "", utcFormats);
31869       f.toString = function() { return specifier; };
31870       return f;
31871     },
31872     utcParse: function(specifier) {
31873       var p = newParse(specifier, utcDate);
31874       p.toString = function() { return specifier; };
31875       return p;
31876     }
31877   };
31878 }
31879
31880 var pads = {"-": "", "_": " ", "0": "0"};
31881 var numberRe = /^\s*\d+/;
31882 var percentRe = /^%/;
31883 var requoteRe = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
31884
31885 function pad(value, fill, width) {
31886   var sign = value < 0 ? "-" : "",
31887       string = (sign ? -value : value) + "",
31888       length = string.length;
31889   return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
31890 }
31891
31892 function requote(s) {
31893   return s.replace(requoteRe, "\\$&");
31894 }
31895
31896 function formatRe(names) {
31897   return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i");
31898 }
31899
31900 function formatLookup(names) {
31901   var map = {}, i = -1, n = names.length;
31902   while (++i < n) map[names[i].toLowerCase()] = i;
31903   return map;
31904 }
31905
31906 function parseWeekdayNumber(d, string, i) {
31907   var n = numberRe.exec(string.slice(i, i + 1));
31908   return n ? (d.w = +n[0], i + n[0].length) : -1;
31909 }
31910
31911 function parseWeekNumberSunday(d, string, i) {
31912   var n = numberRe.exec(string.slice(i));
31913   return n ? (d.U = +n[0], i + n[0].length) : -1;
31914 }
31915
31916 function parseWeekNumberMonday(d, string, i) {
31917   var n = numberRe.exec(string.slice(i));
31918   return n ? (d.W = +n[0], i + n[0].length) : -1;
31919 }
31920
31921 function parseFullYear(d, string, i) {
31922   var n = numberRe.exec(string.slice(i, i + 4));
31923   return n ? (d.y = +n[0], i + n[0].length) : -1;
31924 }
31925
31926 function parseYear(d, string, i) {
31927   var n = numberRe.exec(string.slice(i, i + 2));
31928   return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;
31929 }
31930
31931 function parseZone(d, string, i) {
31932   var n = /^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(string.slice(i, i + 6));
31933   return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || "00")), i + n[0].length) : -1;
31934 }
31935
31936 function parseMonthNumber(d, string, i) {
31937   var n = numberRe.exec(string.slice(i, i + 2));
31938   return n ? (d.m = n[0] - 1, i + n[0].length) : -1;
31939 }
31940
31941 function parseDayOfMonth(d, string, i) {
31942   var n = numberRe.exec(string.slice(i, i + 2));
31943   return n ? (d.d = +n[0], i + n[0].length) : -1;
31944 }
31945
31946 function parseDayOfYear(d, string, i) {
31947   var n = numberRe.exec(string.slice(i, i + 3));
31948   return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1;
31949 }
31950
31951 function parseHour24(d, string, i) {
31952   var n = numberRe.exec(string.slice(i, i + 2));
31953   return n ? (d.H = +n[0], i + n[0].length) : -1;
31954 }
31955
31956 function parseMinutes(d, string, i) {
31957   var n = numberRe.exec(string.slice(i, i + 2));
31958   return n ? (d.M = +n[0], i + n[0].length) : -1;
31959 }
31960
31961 function parseSeconds(d, string, i) {
31962   var n = numberRe.exec(string.slice(i, i + 2));
31963   return n ? (d.S = +n[0], i + n[0].length) : -1;
31964 }
31965
31966 function parseMilliseconds(d, string, i) {
31967   var n = numberRe.exec(string.slice(i, i + 3));
31968   return n ? (d.L = +n[0], i + n[0].length) : -1;
31969 }
31970
31971 function parseLiteralPercent(d, string, i) {
31972   var n = percentRe.exec(string.slice(i, i + 1));
31973   return n ? i + n[0].length : -1;
31974 }
31975
31976 function formatDayOfMonth(d, p) {
31977   return pad(d.getDate(), p, 2);
31978 }
31979
31980 function formatHour24(d, p) {
31981   return pad(d.getHours(), p, 2);
31982 }
31983
31984 function formatHour12(d, p) {
31985   return pad(d.getHours() % 12 || 12, p, 2);
31986 }
31987
31988 function formatDayOfYear(d, p) {
31989   return pad(1 + day.count(year(d), d), p, 3);
31990 }
31991
31992 function formatMilliseconds(d, p) {
31993   return pad(d.getMilliseconds(), p, 3);
31994 }
31995
31996 function formatMonthNumber(d, p) {
31997   return pad(d.getMonth() + 1, p, 2);
31998 }
31999
32000 function formatMinutes(d, p) {
32001   return pad(d.getMinutes(), p, 2);
32002 }
32003
32004 function formatSeconds(d, p) {
32005   return pad(d.getSeconds(), p, 2);
32006 }
32007
32008 function formatWeekNumberSunday(d, p) {
32009   return pad(sunday.count(year(d), d), p, 2);
32010 }
32011
32012 function formatWeekdayNumber(d) {
32013   return d.getDay();
32014 }
32015
32016 function formatWeekNumberMonday(d, p) {
32017   return pad(monday.count(year(d), d), p, 2);
32018 }
32019
32020 function formatYear(d, p) {
32021   return pad(d.getFullYear() % 100, p, 2);
32022 }
32023
32024 function formatFullYear(d, p) {
32025   return pad(d.getFullYear() % 10000, p, 4);
32026 }
32027
32028 function formatZone(d) {
32029   var z = d.getTimezoneOffset();
32030   return (z > 0 ? "-" : (z *= -1, "+"))
32031       + pad(z / 60 | 0, "0", 2)
32032       + pad(z % 60, "0", 2);
32033 }
32034
32035 function formatUTCDayOfMonth(d, p) {
32036   return pad(d.getUTCDate(), p, 2);
32037 }
32038
32039 function formatUTCHour24(d, p) {
32040   return pad(d.getUTCHours(), p, 2);
32041 }
32042
32043 function formatUTCHour12(d, p) {
32044   return pad(d.getUTCHours() % 12 || 12, p, 2);
32045 }
32046
32047 function formatUTCDayOfYear(d, p) {
32048   return pad(1 + utcDay.count(utcYear(d), d), p, 3);
32049 }
32050
32051 function formatUTCMilliseconds(d, p) {
32052   return pad(d.getUTCMilliseconds(), p, 3);
32053 }
32054
32055 function formatUTCMonthNumber(d, p) {
32056   return pad(d.getUTCMonth() + 1, p, 2);
32057 }
32058
32059 function formatUTCMinutes(d, p) {
32060   return pad(d.getUTCMinutes(), p, 2);
32061 }
32062
32063 function formatUTCSeconds(d, p) {
32064   return pad(d.getUTCSeconds(), p, 2);
32065 }
32066
32067 function formatUTCWeekNumberSunday(d, p) {
32068   return pad(utcSunday.count(utcYear(d), d), p, 2);
32069 }
32070
32071 function formatUTCWeekdayNumber(d) {
32072   return d.getUTCDay();
32073 }
32074
32075 function formatUTCWeekNumberMonday(d, p) {
32076   return pad(utcMonday.count(utcYear(d), d), p, 2);
32077 }
32078
32079 function formatUTCYear(d, p) {
32080   return pad(d.getUTCFullYear() % 100, p, 2);
32081 }
32082
32083 function formatUTCFullYear(d, p) {
32084   return pad(d.getUTCFullYear() % 10000, p, 4);
32085 }
32086
32087 function formatUTCZone() {
32088   return "+0000";
32089 }
32090
32091 function formatLiteralPercent() {
32092   return "%";
32093 }
32094
32095 var locale$2;
32096 var timeFormat;
32097 var timeParse;
32098 var utcFormat;
32099 var utcParse;
32100
32101 defaultLocale$1({
32102   dateTime: "%x, %X",
32103   date: "%-m/%-d/%Y",
32104   time: "%-I:%M:%S %p",
32105   periods: ["AM", "PM"],
32106   days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
32107   shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
32108   months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
32109   shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
32110 });
32111
32112 function defaultLocale$1(definition) {
32113   locale$2 = formatLocale$1(definition);
32114   timeFormat = locale$2.format;
32115   timeParse = locale$2.parse;
32116   utcFormat = locale$2.utcFormat;
32117   utcParse = locale$2.utcParse;
32118   return locale$2;
32119 }
32120
32121 var isoSpecifier = "%Y-%m-%dT%H:%M:%S.%LZ";
32122
32123 function formatIsoNative(date) {
32124   return date.toISOString();
32125 }
32126
32127 var formatIso = Date.prototype.toISOString
32128     ? formatIsoNative
32129     : utcFormat(isoSpecifier);
32130
32131 function parseIsoNative(string) {
32132   var date = new Date(string);
32133   return isNaN(date) ? null : date;
32134 }
32135
32136 var parseIso = +new Date("2000-01-01T00:00:00.000Z")
32137     ? parseIsoNative
32138     : utcParse(isoSpecifier);
32139
32140 var durationSecond = 1000;
32141 var durationMinute = durationSecond * 60;
32142 var durationHour = durationMinute * 60;
32143 var durationDay = durationHour * 24;
32144 var durationWeek = durationDay * 7;
32145 var durationMonth = durationDay * 30;
32146 var durationYear = durationDay * 365;
32147
32148 function date$1(t) {
32149   return new Date(t);
32150 }
32151
32152 function number$2(t) {
32153   return t instanceof Date ? +t : +new Date(+t);
32154 }
32155
32156 function calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format) {
32157   var scale = continuous(deinterpolateLinear, reinterpolate),
32158       invert = scale.invert,
32159       domain = scale.domain;
32160
32161   var formatMillisecond = format(".%L"),
32162       formatSecond = format(":%S"),
32163       formatMinute = format("%I:%M"),
32164       formatHour = format("%I %p"),
32165       formatDay = format("%a %d"),
32166       formatWeek = format("%b %d"),
32167       formatMonth = format("%B"),
32168       formatYear = format("%Y");
32169
32170   var tickIntervals = [
32171     [second$$1,  1,      durationSecond],
32172     [second$$1,  5,  5 * durationSecond],
32173     [second$$1, 15, 15 * durationSecond],
32174     [second$$1, 30, 30 * durationSecond],
32175     [minute$$1,  1,      durationMinute],
32176     [minute$$1,  5,  5 * durationMinute],
32177     [minute$$1, 15, 15 * durationMinute],
32178     [minute$$1, 30, 30 * durationMinute],
32179     [  hour$$1,  1,      durationHour  ],
32180     [  hour$$1,  3,  3 * durationHour  ],
32181     [  hour$$1,  6,  6 * durationHour  ],
32182     [  hour$$1, 12, 12 * durationHour  ],
32183     [   day$$1,  1,      durationDay   ],
32184     [   day$$1,  2,  2 * durationDay   ],
32185     [  week,  1,      durationWeek  ],
32186     [ month$$1,  1,      durationMonth ],
32187     [ month$$1,  3,  3 * durationMonth ],
32188     [  year$$1,  1,      durationYear  ]
32189   ];
32190
32191   function tickFormat(date) {
32192     return (second$$1(date) < date ? formatMillisecond
32193         : minute$$1(date) < date ? formatSecond
32194         : hour$$1(date) < date ? formatMinute
32195         : day$$1(date) < date ? formatHour
32196         : month$$1(date) < date ? (week(date) < date ? formatDay : formatWeek)
32197         : year$$1(date) < date ? formatMonth
32198         : formatYear)(date);
32199   }
32200
32201   function tickInterval(interval, start, stop, step) {
32202     if (interval == null) interval = 10;
32203
32204     // If a desired tick count is specified, pick a reasonable tick interval
32205     // based on the extent of the domain and a rough estimate of tick size.
32206     // Otherwise, assume interval is already a time interval and use it.
32207     if (typeof interval === "number") {
32208       var target = Math.abs(stop - start) / interval,
32209           i = bisector(function(i) { return i[2]; }).right(tickIntervals, target);
32210       if (i === tickIntervals.length) {
32211         step = tickStep(start / durationYear, stop / durationYear, interval);
32212         interval = year$$1;
32213       } else if (i) {
32214         i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
32215         step = i[1];
32216         interval = i[0];
32217       } else {
32218         step = tickStep(start, stop, interval);
32219         interval = millisecond$$1;
32220       }
32221     }
32222
32223     return step == null ? interval : interval.every(step);
32224   }
32225
32226   scale.invert = function(y) {
32227     return new Date(invert(y));
32228   };
32229
32230   scale.domain = function(_) {
32231     return arguments.length ? domain(map$3.call(_, number$2)) : domain().map(date$1);
32232   };
32233
32234   scale.ticks = function(interval, step) {
32235     var d = domain(),
32236         t0 = d[0],
32237         t1 = d[d.length - 1],
32238         r = t1 < t0,
32239         t;
32240     if (r) t = t0, t0 = t1, t1 = t;
32241     t = tickInterval(interval, t0, t1, step);
32242     t = t ? t.range(t0, t1 + 1) : []; // inclusive stop
32243     return r ? t.reverse() : t;
32244   };
32245
32246   scale.tickFormat = function(count, specifier) {
32247     return specifier == null ? tickFormat : format(specifier);
32248   };
32249
32250   scale.nice = function(interval, step) {
32251     var d = domain();
32252     return (interval = tickInterval(interval, d[0], d[d.length - 1], step))
32253         ? domain(nice(d, interval))
32254         : scale;
32255   };
32256
32257   scale.copy = function() {
32258     return copy(scale, calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format));
32259   };
32260
32261   return scale;
32262 }
32263
32264 var time = function() {
32265   return calendar(year, month, sunday, day, hour, minute, second, millisecond, timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]);
32266 };
32267
32268 var utcTime = function() {
32269   return calendar(utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute, second, millisecond, utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]);
32270 };
32271
32272 var colors = function(s) {
32273   return s.match(/.{6}/g).map(function(x) {
32274     return "#" + x;
32275   });
32276 };
32277
32278 var category10 = colors("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf");
32279
32280 var category20b = colors("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6");
32281
32282 var category20c = colors("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9");
32283
32284 var category20 = colors("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5");
32285
32286 var cubehelix$3 = cubehelixLong(cubehelix(300, 0.5, 0.0), cubehelix(-240, 0.5, 1.0));
32287
32288 var warm = cubehelixLong(cubehelix(-100, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
32289
32290 var cool = cubehelixLong(cubehelix(260, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
32291
32292 var rainbow = cubehelix();
32293
32294 var rainbow$1 = function(t) {
32295   if (t < 0 || t > 1) t -= Math.floor(t);
32296   var ts = Math.abs(t - 0.5);
32297   rainbow.h = 360 * t - 100;
32298   rainbow.s = 1.5 - 1.5 * ts;
32299   rainbow.l = 0.8 - 0.9 * ts;
32300   return rainbow + "";
32301 };
32302
32303 function ramp(range) {
32304   var n = range.length;
32305   return function(t) {
32306     return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))];
32307   };
32308 }
32309
32310 var viridis = ramp(colors("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));
32311
32312 var magma = ramp(colors("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf"));
32313
32314 var inferno = ramp(colors("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4"));
32315
32316 var plasma = ramp(colors("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));
32317
32318 function sequential(interpolator) {
32319   var x0 = 0,
32320       x1 = 1,
32321       clamp = false;
32322
32323   function scale(x) {
32324     var t = (x - x0) / (x1 - x0);
32325     return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t);
32326   }
32327
32328   scale.domain = function(_) {
32329     return arguments.length ? (x0 = +_[0], x1 = +_[1], scale) : [x0, x1];
32330   };
32331
32332   scale.clamp = function(_) {
32333     return arguments.length ? (clamp = !!_, scale) : clamp;
32334   };
32335
32336   scale.interpolator = function(_) {
32337     return arguments.length ? (interpolator = _, scale) : interpolator;
32338   };
32339
32340   scale.copy = function() {
32341     return sequential(interpolator).domain([x0, x1]).clamp(clamp);
32342   };
32343
32344   return linearish(scale);
32345 }
32346
32347 var constant$10 = function(x) {
32348   return function constant() {
32349     return x;
32350   };
32351 };
32352
32353 var abs$1 = Math.abs;
32354 var atan2$1 = Math.atan2;
32355 var cos$2 = Math.cos;
32356 var max$2 = Math.max;
32357 var min$1 = Math.min;
32358 var sin$2 = Math.sin;
32359 var sqrt$2 = Math.sqrt;
32360
32361 var epsilon$3 = 1e-12;
32362 var pi$4 = Math.PI;
32363 var halfPi$3 = pi$4 / 2;
32364 var tau$4 = 2 * pi$4;
32365
32366 function acos$1(x) {
32367   return x > 1 ? 0 : x < -1 ? pi$4 : Math.acos(x);
32368 }
32369
32370 function asin$1(x) {
32371   return x >= 1 ? halfPi$3 : x <= -1 ? -halfPi$3 : Math.asin(x);
32372 }
32373
32374 function arcInnerRadius(d) {
32375   return d.innerRadius;
32376 }
32377
32378 function arcOuterRadius(d) {
32379   return d.outerRadius;
32380 }
32381
32382 function arcStartAngle(d) {
32383   return d.startAngle;
32384 }
32385
32386 function arcEndAngle(d) {
32387   return d.endAngle;
32388 }
32389
32390 function arcPadAngle(d) {
32391   return d && d.padAngle; // Note: optional!
32392 }
32393
32394 function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
32395   var x10 = x1 - x0, y10 = y1 - y0,
32396       x32 = x3 - x2, y32 = y3 - y2,
32397       t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / (y32 * x10 - x32 * y10);
32398   return [x0 + t * x10, y0 + t * y10];
32399 }
32400
32401 // Compute perpendicular offset line of length rc.
32402 // http://mathworld.wolfram.com/Circle-LineIntersection.html
32403 function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
32404   var x01 = x0 - x1,
32405       y01 = y0 - y1,
32406       lo = (cw ? rc : -rc) / sqrt$2(x01 * x01 + y01 * y01),
32407       ox = lo * y01,
32408       oy = -lo * x01,
32409       x11 = x0 + ox,
32410       y11 = y0 + oy,
32411       x10 = x1 + ox,
32412       y10 = y1 + oy,
32413       x00 = (x11 + x10) / 2,
32414       y00 = (y11 + y10) / 2,
32415       dx = x10 - x11,
32416       dy = y10 - y11,
32417       d2 = dx * dx + dy * dy,
32418       r = r1 - rc,
32419       D = x11 * y10 - x10 * y11,
32420       d = (dy < 0 ? -1 : 1) * sqrt$2(max$2(0, r * r * d2 - D * D)),
32421       cx0 = (D * dy - dx * d) / d2,
32422       cy0 = (-D * dx - dy * d) / d2,
32423       cx1 = (D * dy + dx * d) / d2,
32424       cy1 = (-D * dx + dy * d) / d2,
32425       dx0 = cx0 - x00,
32426       dy0 = cy0 - y00,
32427       dx1 = cx1 - x00,
32428       dy1 = cy1 - y00;
32429
32430   // Pick the closer of the two intersection points.
32431   // TODO Is there a faster way to determine which intersection to use?
32432   if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
32433
32434   return {
32435     cx: cx0,
32436     cy: cy0,
32437     x01: -ox,
32438     y01: -oy,
32439     x11: cx0 * (r1 / r - 1),
32440     y11: cy0 * (r1 / r - 1)
32441   };
32442 }
32443
32444 var arc = function() {
32445   var innerRadius = arcInnerRadius,
32446       outerRadius = arcOuterRadius,
32447       cornerRadius = constant$10(0),
32448       padRadius = null,
32449       startAngle = arcStartAngle,
32450       endAngle = arcEndAngle,
32451       padAngle = arcPadAngle,
32452       context = null;
32453
32454   function arc() {
32455     var buffer,
32456         r,
32457         r0 = +innerRadius.apply(this, arguments),
32458         r1 = +outerRadius.apply(this, arguments),
32459         a0 = startAngle.apply(this, arguments) - halfPi$3,
32460         a1 = endAngle.apply(this, arguments) - halfPi$3,
32461         da = abs$1(a1 - a0),
32462         cw = a1 > a0;
32463
32464     if (!context) context = buffer = path();
32465
32466     // Ensure that the outer radius is always larger than the inner radius.
32467     if (r1 < r0) r = r1, r1 = r0, r0 = r;
32468
32469     // Is it a point?
32470     if (!(r1 > epsilon$3)) context.moveTo(0, 0);
32471
32472     // Or is it a circle or annulus?
32473     else if (da > tau$4 - epsilon$3) {
32474       context.moveTo(r1 * cos$2(a0), r1 * sin$2(a0));
32475       context.arc(0, 0, r1, a0, a1, !cw);
32476       if (r0 > epsilon$3) {
32477         context.moveTo(r0 * cos$2(a1), r0 * sin$2(a1));
32478         context.arc(0, 0, r0, a1, a0, cw);
32479       }
32480     }
32481
32482     // Or is it a circular or annular sector?
32483     else {
32484       var a01 = a0,
32485           a11 = a1,
32486           a00 = a0,
32487           a10 = a1,
32488           da0 = da,
32489           da1 = da,
32490           ap = padAngle.apply(this, arguments) / 2,
32491           rp = (ap > epsilon$3) && (padRadius ? +padRadius.apply(this, arguments) : sqrt$2(r0 * r0 + r1 * r1)),
32492           rc = min$1(abs$1(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
32493           rc0 = rc,
32494           rc1 = rc,
32495           t0,
32496           t1;
32497
32498       // Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
32499       if (rp > epsilon$3) {
32500         var p0 = asin$1(rp / r0 * sin$2(ap)),
32501             p1 = asin$1(rp / r1 * sin$2(ap));
32502         if ((da0 -= p0 * 2) > epsilon$3) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
32503         else da0 = 0, a00 = a10 = (a0 + a1) / 2;
32504         if ((da1 -= p1 * 2) > epsilon$3) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
32505         else da1 = 0, a01 = a11 = (a0 + a1) / 2;
32506       }
32507
32508       var x01 = r1 * cos$2(a01),
32509           y01 = r1 * sin$2(a01),
32510           x10 = r0 * cos$2(a10),
32511           y10 = r0 * sin$2(a10);
32512
32513       // Apply rounded corners?
32514       if (rc > epsilon$3) {
32515         var x11 = r1 * cos$2(a11),
32516             y11 = r1 * sin$2(a11),
32517             x00 = r0 * cos$2(a00),
32518             y00 = r0 * sin$2(a00);
32519
32520         // Restrict the corner radius according to the sector angle.
32521         if (da < pi$4) {
32522           var oc = da0 > epsilon$3 ? intersect(x01, y01, x00, y00, x11, y11, x10, y10) : [x10, y10],
32523               ax = x01 - oc[0],
32524               ay = y01 - oc[1],
32525               bx = x11 - oc[0],
32526               by = y11 - oc[1],
32527               kc = 1 / sin$2(acos$1((ax * bx + ay * by) / (sqrt$2(ax * ax + ay * ay) * sqrt$2(bx * bx + by * by))) / 2),
32528               lc = sqrt$2(oc[0] * oc[0] + oc[1] * oc[1]);
32529           rc0 = min$1(rc, (r0 - lc) / (kc - 1));
32530           rc1 = min$1(rc, (r1 - lc) / (kc + 1));
32531         }
32532       }
32533
32534       // Is the sector collapsed to a line?
32535       if (!(da1 > epsilon$3)) context.moveTo(x01, y01);
32536
32537       // Does the sector’s outer ring have rounded corners?
32538       else if (rc1 > epsilon$3) {
32539         t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
32540         t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
32541
32542         context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
32543
32544         // Have the corners merged?
32545         if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2$1(t0.y01, t0.x01), atan2$1(t1.y01, t1.x01), !cw);
32546
32547         // Otherwise, draw the two corners and the ring.
32548         else {
32549           context.arc(t0.cx, t0.cy, rc1, atan2$1(t0.y01, t0.x01), atan2$1(t0.y11, t0.x11), !cw);
32550           context.arc(0, 0, r1, atan2$1(t0.cy + t0.y11, t0.cx + t0.x11), atan2$1(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
32551           context.arc(t1.cx, t1.cy, rc1, atan2$1(t1.y11, t1.x11), atan2$1(t1.y01, t1.x01), !cw);
32552         }
32553       }
32554
32555       // Or is the outer ring just a circular arc?
32556       else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
32557
32558       // Is there no inner ring, and it’s a circular sector?
32559       // Or perhaps it’s an annular sector collapsed due to padding?
32560       if (!(r0 > epsilon$3) || !(da0 > epsilon$3)) context.lineTo(x10, y10);
32561
32562       // Does the sector’s inner ring (or point) have rounded corners?
32563       else if (rc0 > epsilon$3) {
32564         t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
32565         t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
32566
32567         context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
32568
32569         // Have the corners merged?
32570         if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2$1(t0.y01, t0.x01), atan2$1(t1.y01, t1.x01), !cw);
32571
32572         // Otherwise, draw the two corners and the ring.
32573         else {
32574           context.arc(t0.cx, t0.cy, rc0, atan2$1(t0.y01, t0.x01), atan2$1(t0.y11, t0.x11), !cw);
32575           context.arc(0, 0, r0, atan2$1(t0.cy + t0.y11, t0.cx + t0.x11), atan2$1(t1.cy + t1.y11, t1.cx + t1.x11), cw);
32576           context.arc(t1.cx, t1.cy, rc0, atan2$1(t1.y11, t1.x11), atan2$1(t1.y01, t1.x01), !cw);
32577         }
32578       }
32579
32580       // Or is the inner ring just a circular arc?
32581       else context.arc(0, 0, r0, a10, a00, cw);
32582     }
32583
32584     context.closePath();
32585
32586     if (buffer) return context = null, buffer + "" || null;
32587   }
32588
32589   arc.centroid = function() {
32590     var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
32591         a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi$4 / 2;
32592     return [cos$2(a) * r, sin$2(a) * r];
32593   };
32594
32595   arc.innerRadius = function(_) {
32596     return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : innerRadius;
32597   };
32598
32599   arc.outerRadius = function(_) {
32600     return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : outerRadius;
32601   };
32602
32603   arc.cornerRadius = function(_) {
32604     return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : cornerRadius;
32605   };
32606
32607   arc.padRadius = function(_) {
32608     return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), arc) : padRadius;
32609   };
32610
32611   arc.startAngle = function(_) {
32612     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : startAngle;
32613   };
32614
32615   arc.endAngle = function(_) {
32616     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : endAngle;
32617   };
32618
32619   arc.padAngle = function(_) {
32620     return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : padAngle;
32621   };
32622
32623   arc.context = function(_) {
32624     return arguments.length ? ((context = _ == null ? null : _), arc) : context;
32625   };
32626
32627   return arc;
32628 };
32629
32630 function Linear(context) {
32631   this._context = context;
32632 }
32633
32634 Linear.prototype = {
32635   areaStart: function() {
32636     this._line = 0;
32637   },
32638   areaEnd: function() {
32639     this._line = NaN;
32640   },
32641   lineStart: function() {
32642     this._point = 0;
32643   },
32644   lineEnd: function() {
32645     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
32646     this._line = 1 - this._line;
32647   },
32648   point: function(x, y) {
32649     x = +x, y = +y;
32650     switch (this._point) {
32651       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
32652       case 1: this._point = 2; // proceed
32653       default: this._context.lineTo(x, y); break;
32654     }
32655   }
32656 };
32657
32658 var curveLinear = function(context) {
32659   return new Linear(context);
32660 };
32661
32662 function x$3(p) {
32663   return p[0];
32664 }
32665
32666 function y$3(p) {
32667   return p[1];
32668 }
32669
32670 var line = function() {
32671   var x$$1 = x$3,
32672       y$$1 = y$3,
32673       defined = constant$10(true),
32674       context = null,
32675       curve = curveLinear,
32676       output = null;
32677
32678   function line(data) {
32679     var i,
32680         n = data.length,
32681         d,
32682         defined0 = false,
32683         buffer;
32684
32685     if (context == null) output = curve(buffer = path());
32686
32687     for (i = 0; i <= n; ++i) {
32688       if (!(i < n && defined(d = data[i], i, data)) === defined0) {
32689         if (defined0 = !defined0) output.lineStart();
32690         else output.lineEnd();
32691       }
32692       if (defined0) output.point(+x$$1(d, i, data), +y$$1(d, i, data));
32693     }
32694
32695     if (buffer) return output = null, buffer + "" || null;
32696   }
32697
32698   line.x = function(_) {
32699     return arguments.length ? (x$$1 = typeof _ === "function" ? _ : constant$10(+_), line) : x$$1;
32700   };
32701
32702   line.y = function(_) {
32703     return arguments.length ? (y$$1 = typeof _ === "function" ? _ : constant$10(+_), line) : y$$1;
32704   };
32705
32706   line.defined = function(_) {
32707     return arguments.length ? (defined = typeof _ === "function" ? _ : constant$10(!!_), line) : defined;
32708   };
32709
32710   line.curve = function(_) {
32711     return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;
32712   };
32713
32714   line.context = function(_) {
32715     return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;
32716   };
32717
32718   return line;
32719 };
32720
32721 var area$1 = function() {
32722   var x0 = x$3,
32723       x1 = null,
32724       y0 = constant$10(0),
32725       y1 = y$3,
32726       defined = constant$10(true),
32727       context = null,
32728       curve = curveLinear,
32729       output = null;
32730
32731   function area(data) {
32732     var i,
32733         j,
32734         k,
32735         n = data.length,
32736         d,
32737         defined0 = false,
32738         buffer,
32739         x0z = new Array(n),
32740         y0z = new Array(n);
32741
32742     if (context == null) output = curve(buffer = path());
32743
32744     for (i = 0; i <= n; ++i) {
32745       if (!(i < n && defined(d = data[i], i, data)) === defined0) {
32746         if (defined0 = !defined0) {
32747           j = i;
32748           output.areaStart();
32749           output.lineStart();
32750         } else {
32751           output.lineEnd();
32752           output.lineStart();
32753           for (k = i - 1; k >= j; --k) {
32754             output.point(x0z[k], y0z[k]);
32755           }
32756           output.lineEnd();
32757           output.areaEnd();
32758         }
32759       }
32760       if (defined0) {
32761         x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);
32762         output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);
32763       }
32764     }
32765
32766     if (buffer) return output = null, buffer + "" || null;
32767   }
32768
32769   function arealine() {
32770     return line().defined(defined).curve(curve).context(context);
32771   }
32772
32773   area.x = function(_) {
32774     return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$10(+_), x1 = null, area) : x0;
32775   };
32776
32777   area.x0 = function(_) {
32778     return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$10(+_), area) : x0;
32779   };
32780
32781   area.x1 = function(_) {
32782     return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), area) : x1;
32783   };
32784
32785   area.y = function(_) {
32786     return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$10(+_), y1 = null, area) : y0;
32787   };
32788
32789   area.y0 = function(_) {
32790     return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$10(+_), area) : y0;
32791   };
32792
32793   area.y1 = function(_) {
32794     return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), area) : y1;
32795   };
32796
32797   area.lineX0 =
32798   area.lineY0 = function() {
32799     return arealine().x(x0).y(y0);
32800   };
32801
32802   area.lineY1 = function() {
32803     return arealine().x(x0).y(y1);
32804   };
32805
32806   area.lineX1 = function() {
32807     return arealine().x(x1).y(y0);
32808   };
32809
32810   area.defined = function(_) {
32811     return arguments.length ? (defined = typeof _ === "function" ? _ : constant$10(!!_), area) : defined;
32812   };
32813
32814   area.curve = function(_) {
32815     return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;
32816   };
32817
32818   area.context = function(_) {
32819     return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;
32820   };
32821
32822   return area;
32823 };
32824
32825 var descending$1 = function(a, b) {
32826   return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
32827 };
32828
32829 var identity$7 = function(d) {
32830   return d;
32831 };
32832
32833 var pie = function() {
32834   var value = identity$7,
32835       sortValues = descending$1,
32836       sort = null,
32837       startAngle = constant$10(0),
32838       endAngle = constant$10(tau$4),
32839       padAngle = constant$10(0);
32840
32841   function pie(data) {
32842     var i,
32843         n = data.length,
32844         j,
32845         k,
32846         sum = 0,
32847         index = new Array(n),
32848         arcs = new Array(n),
32849         a0 = +startAngle.apply(this, arguments),
32850         da = Math.min(tau$4, Math.max(-tau$4, endAngle.apply(this, arguments) - a0)),
32851         a1,
32852         p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)),
32853         pa = p * (da < 0 ? -1 : 1),
32854         v;
32855
32856     for (i = 0; i < n; ++i) {
32857       if ((v = arcs[index[i] = i] = +value(data[i], i, data)) > 0) {
32858         sum += v;
32859       }
32860     }
32861
32862     // Optionally sort the arcs by previously-computed values or by data.
32863     if (sortValues != null) index.sort(function(i, j) { return sortValues(arcs[i], arcs[j]); });
32864     else if (sort != null) index.sort(function(i, j) { return sort(data[i], data[j]); });
32865
32866     // Compute the arcs! They are stored in the original data's order.
32867     for (i = 0, k = sum ? (da - n * pa) / sum : 0; i < n; ++i, a0 = a1) {
32868       j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
32869         data: data[j],
32870         index: i,
32871         value: v,
32872         startAngle: a0,
32873         endAngle: a1,
32874         padAngle: p
32875       };
32876     }
32877
32878     return arcs;
32879   }
32880
32881   pie.value = function(_) {
32882     return arguments.length ? (value = typeof _ === "function" ? _ : constant$10(+_), pie) : value;
32883   };
32884
32885   pie.sortValues = function(_) {
32886     return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
32887   };
32888
32889   pie.sort = function(_) {
32890     return arguments.length ? (sort = _, sortValues = null, pie) : sort;
32891   };
32892
32893   pie.startAngle = function(_) {
32894     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : startAngle;
32895   };
32896
32897   pie.endAngle = function(_) {
32898     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : endAngle;
32899   };
32900
32901   pie.padAngle = function(_) {
32902     return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : padAngle;
32903   };
32904
32905   return pie;
32906 };
32907
32908 var curveRadialLinear = curveRadial(curveLinear);
32909
32910 function Radial(curve) {
32911   this._curve = curve;
32912 }
32913
32914 Radial.prototype = {
32915   areaStart: function() {
32916     this._curve.areaStart();
32917   },
32918   areaEnd: function() {
32919     this._curve.areaEnd();
32920   },
32921   lineStart: function() {
32922     this._curve.lineStart();
32923   },
32924   lineEnd: function() {
32925     this._curve.lineEnd();
32926   },
32927   point: function(a, r) {
32928     this._curve.point(r * Math.sin(a), r * -Math.cos(a));
32929   }
32930 };
32931
32932 function curveRadial(curve) {
32933
32934   function radial(context) {
32935     return new Radial(curve(context));
32936   }
32937
32938   radial._curve = curve;
32939
32940   return radial;
32941 }
32942
32943 function radialLine(l) {
32944   var c = l.curve;
32945
32946   l.angle = l.x, delete l.x;
32947   l.radius = l.y, delete l.y;
32948
32949   l.curve = function(_) {
32950     return arguments.length ? c(curveRadial(_)) : c()._curve;
32951   };
32952
32953   return l;
32954 }
32955
32956 var radialLine$1 = function() {
32957   return radialLine(line().curve(curveRadialLinear));
32958 };
32959
32960 var radialArea = function() {
32961   var a = area$1().curve(curveRadialLinear),
32962       c = a.curve,
32963       x0 = a.lineX0,
32964       x1 = a.lineX1,
32965       y0 = a.lineY0,
32966       y1 = a.lineY1;
32967
32968   a.angle = a.x, delete a.x;
32969   a.startAngle = a.x0, delete a.x0;
32970   a.endAngle = a.x1, delete a.x1;
32971   a.radius = a.y, delete a.y;
32972   a.innerRadius = a.y0, delete a.y0;
32973   a.outerRadius = a.y1, delete a.y1;
32974   a.lineStartAngle = function() { return radialLine(x0()); }, delete a.lineX0;
32975   a.lineEndAngle = function() { return radialLine(x1()); }, delete a.lineX1;
32976   a.lineInnerRadius = function() { return radialLine(y0()); }, delete a.lineY0;
32977   a.lineOuterRadius = function() { return radialLine(y1()); }, delete a.lineY1;
32978
32979   a.curve = function(_) {
32980     return arguments.length ? c(curveRadial(_)) : c()._curve;
32981   };
32982
32983   return a;
32984 };
32985
32986 var circle$2 = {
32987   draw: function(context, size) {
32988     var r = Math.sqrt(size / pi$4);
32989     context.moveTo(r, 0);
32990     context.arc(0, 0, r, 0, tau$4);
32991   }
32992 };
32993
32994 var cross$2 = {
32995   draw: function(context, size) {
32996     var r = Math.sqrt(size / 5) / 2;
32997     context.moveTo(-3 * r, -r);
32998     context.lineTo(-r, -r);
32999     context.lineTo(-r, -3 * r);
33000     context.lineTo(r, -3 * r);
33001     context.lineTo(r, -r);
33002     context.lineTo(3 * r, -r);
33003     context.lineTo(3 * r, r);
33004     context.lineTo(r, r);
33005     context.lineTo(r, 3 * r);
33006     context.lineTo(-r, 3 * r);
33007     context.lineTo(-r, r);
33008     context.lineTo(-3 * r, r);
33009     context.closePath();
33010   }
33011 };
33012
33013 var tan30 = Math.sqrt(1 / 3);
33014 var tan30_2 = tan30 * 2;
33015
33016 var diamond = {
33017   draw: function(context, size) {
33018     var y = Math.sqrt(size / tan30_2),
33019         x = y * tan30;
33020     context.moveTo(0, -y);
33021     context.lineTo(x, 0);
33022     context.lineTo(0, y);
33023     context.lineTo(-x, 0);
33024     context.closePath();
33025   }
33026 };
33027
33028 var ka = 0.89081309152928522810;
33029 var kr = Math.sin(pi$4 / 10) / Math.sin(7 * pi$4 / 10);
33030 var kx = Math.sin(tau$4 / 10) * kr;
33031 var ky = -Math.cos(tau$4 / 10) * kr;
33032
33033 var star = {
33034   draw: function(context, size) {
33035     var r = Math.sqrt(size * ka),
33036         x = kx * r,
33037         y = ky * r;
33038     context.moveTo(0, -r);
33039     context.lineTo(x, y);
33040     for (var i = 1; i < 5; ++i) {
33041       var a = tau$4 * i / 5,
33042           c = Math.cos(a),
33043           s = Math.sin(a);
33044       context.lineTo(s * r, -c * r);
33045       context.lineTo(c * x - s * y, s * x + c * y);
33046     }
33047     context.closePath();
33048   }
33049 };
33050
33051 var square = {
33052   draw: function(context, size) {
33053     var w = Math.sqrt(size),
33054         x = -w / 2;
33055     context.rect(x, x, w, w);
33056   }
33057 };
33058
33059 var sqrt3 = Math.sqrt(3);
33060
33061 var triangle = {
33062   draw: function(context, size) {
33063     var y = -Math.sqrt(size / (sqrt3 * 3));
33064     context.moveTo(0, y * 2);
33065     context.lineTo(-sqrt3 * y, -y);
33066     context.lineTo(sqrt3 * y, -y);
33067     context.closePath();
33068   }
33069 };
33070
33071 var c = -0.5;
33072 var s = Math.sqrt(3) / 2;
33073 var k = 1 / Math.sqrt(12);
33074 var a = (k / 2 + 1) * 3;
33075
33076 var wye = {
33077   draw: function(context, size) {
33078     var r = Math.sqrt(size / a),
33079         x0 = r / 2,
33080         y0 = r * k,
33081         x1 = x0,
33082         y1 = r * k + r,
33083         x2 = -x1,
33084         y2 = y1;
33085     context.moveTo(x0, y0);
33086     context.lineTo(x1, y1);
33087     context.lineTo(x2, y2);
33088     context.lineTo(c * x0 - s * y0, s * x0 + c * y0);
33089     context.lineTo(c * x1 - s * y1, s * x1 + c * y1);
33090     context.lineTo(c * x2 - s * y2, s * x2 + c * y2);
33091     context.lineTo(c * x0 + s * y0, c * y0 - s * x0);
33092     context.lineTo(c * x1 + s * y1, c * y1 - s * x1);
33093     context.lineTo(c * x2 + s * y2, c * y2 - s * x2);
33094     context.closePath();
33095   }
33096 };
33097
33098 var symbols = [
33099   circle$2,
33100   cross$2,
33101   diamond,
33102   square,
33103   star,
33104   triangle,
33105   wye
33106 ];
33107
33108 var symbol = function() {
33109   var type = constant$10(circle$2),
33110       size = constant$10(64),
33111       context = null;
33112
33113   function symbol() {
33114     var buffer;
33115     if (!context) context = buffer = path();
33116     type.apply(this, arguments).draw(context, +size.apply(this, arguments));
33117     if (buffer) return context = null, buffer + "" || null;
33118   }
33119
33120   symbol.type = function(_) {
33121     return arguments.length ? (type = typeof _ === "function" ? _ : constant$10(_), symbol) : type;
33122   };
33123
33124   symbol.size = function(_) {
33125     return arguments.length ? (size = typeof _ === "function" ? _ : constant$10(+_), symbol) : size;
33126   };
33127
33128   symbol.context = function(_) {
33129     return arguments.length ? (context = _ == null ? null : _, symbol) : context;
33130   };
33131
33132   return symbol;
33133 };
33134
33135 var noop$2 = function() {};
33136
33137 function point$2(that, x, y) {
33138   that._context.bezierCurveTo(
33139     (2 * that._x0 + that._x1) / 3,
33140     (2 * that._y0 + that._y1) / 3,
33141     (that._x0 + 2 * that._x1) / 3,
33142     (that._y0 + 2 * that._y1) / 3,
33143     (that._x0 + 4 * that._x1 + x) / 6,
33144     (that._y0 + 4 * that._y1 + y) / 6
33145   );
33146 }
33147
33148 function Basis(context) {
33149   this._context = context;
33150 }
33151
33152 Basis.prototype = {
33153   areaStart: function() {
33154     this._line = 0;
33155   },
33156   areaEnd: function() {
33157     this._line = NaN;
33158   },
33159   lineStart: function() {
33160     this._x0 = this._x1 =
33161     this._y0 = this._y1 = NaN;
33162     this._point = 0;
33163   },
33164   lineEnd: function() {
33165     switch (this._point) {
33166       case 3: point$2(this, this._x1, this._y1); // proceed
33167       case 2: this._context.lineTo(this._x1, this._y1); break;
33168     }
33169     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33170     this._line = 1 - this._line;
33171   },
33172   point: function(x, y) {
33173     x = +x, y = +y;
33174     switch (this._point) {
33175       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33176       case 1: this._point = 2; break;
33177       case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed
33178       default: point$2(this, x, y); break;
33179     }
33180     this._x0 = this._x1, this._x1 = x;
33181     this._y0 = this._y1, this._y1 = y;
33182   }
33183 };
33184
33185 var basis$2 = function(context) {
33186   return new Basis(context);
33187 };
33188
33189 function BasisClosed(context) {
33190   this._context = context;
33191 }
33192
33193 BasisClosed.prototype = {
33194   areaStart: noop$2,
33195   areaEnd: noop$2,
33196   lineStart: function() {
33197     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =
33198     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;
33199     this._point = 0;
33200   },
33201   lineEnd: function() {
33202     switch (this._point) {
33203       case 1: {
33204         this._context.moveTo(this._x2, this._y2);
33205         this._context.closePath();
33206         break;
33207       }
33208       case 2: {
33209         this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);
33210         this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);
33211         this._context.closePath();
33212         break;
33213       }
33214       case 3: {
33215         this.point(this._x2, this._y2);
33216         this.point(this._x3, this._y3);
33217         this.point(this._x4, this._y4);
33218         break;
33219       }
33220     }
33221   },
33222   point: function(x, y) {
33223     x = +x, y = +y;
33224     switch (this._point) {
33225       case 0: this._point = 1; this._x2 = x, this._y2 = y; break;
33226       case 1: this._point = 2; this._x3 = x, this._y3 = y; break;
33227       case 2: this._point = 3; this._x4 = x, this._y4 = y; this._context.moveTo((this._x0 + 4 * this._x1 + x) / 6, (this._y0 + 4 * this._y1 + y) / 6); break;
33228       default: point$2(this, x, y); break;
33229     }
33230     this._x0 = this._x1, this._x1 = x;
33231     this._y0 = this._y1, this._y1 = y;
33232   }
33233 };
33234
33235 var basisClosed$1 = function(context) {
33236   return new BasisClosed(context);
33237 };
33238
33239 function BasisOpen(context) {
33240   this._context = context;
33241 }
33242
33243 BasisOpen.prototype = {
33244   areaStart: function() {
33245     this._line = 0;
33246   },
33247   areaEnd: function() {
33248     this._line = NaN;
33249   },
33250   lineStart: function() {
33251     this._x0 = this._x1 =
33252     this._y0 = this._y1 = NaN;
33253     this._point = 0;
33254   },
33255   lineEnd: function() {
33256     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33257     this._line = 1 - this._line;
33258   },
33259   point: function(x, y) {
33260     x = +x, y = +y;
33261     switch (this._point) {
33262       case 0: this._point = 1; break;
33263       case 1: this._point = 2; break;
33264       case 2: this._point = 3; var x0 = (this._x0 + 4 * this._x1 + x) / 6, y0 = (this._y0 + 4 * this._y1 + y) / 6; this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); break;
33265       case 3: this._point = 4; // proceed
33266       default: point$2(this, x, y); break;
33267     }
33268     this._x0 = this._x1, this._x1 = x;
33269     this._y0 = this._y1, this._y1 = y;
33270   }
33271 };
33272
33273 var basisOpen = function(context) {
33274   return new BasisOpen(context);
33275 };
33276
33277 function Bundle(context, beta) {
33278   this._basis = new Basis(context);
33279   this._beta = beta;
33280 }
33281
33282 Bundle.prototype = {
33283   lineStart: function() {
33284     this._x = [];
33285     this._y = [];
33286     this._basis.lineStart();
33287   },
33288   lineEnd: function() {
33289     var x = this._x,
33290         y = this._y,
33291         j = x.length - 1;
33292
33293     if (j > 0) {
33294       var x0 = x[0],
33295           y0 = y[0],
33296           dx = x[j] - x0,
33297           dy = y[j] - y0,
33298           i = -1,
33299           t;
33300
33301       while (++i <= j) {
33302         t = i / j;
33303         this._basis.point(
33304           this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),
33305           this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)
33306         );
33307       }
33308     }
33309
33310     this._x = this._y = null;
33311     this._basis.lineEnd();
33312   },
33313   point: function(x, y) {
33314     this._x.push(+x);
33315     this._y.push(+y);
33316   }
33317 };
33318
33319 var bundle = ((function custom(beta) {
33320
33321   function bundle(context) {
33322     return beta === 1 ? new Basis(context) : new Bundle(context, beta);
33323   }
33324
33325   bundle.beta = function(beta) {
33326     return custom(+beta);
33327   };
33328
33329   return bundle;
33330 }))(0.85);
33331
33332 function point$3(that, x, y) {
33333   that._context.bezierCurveTo(
33334     that._x1 + that._k * (that._x2 - that._x0),
33335     that._y1 + that._k * (that._y2 - that._y0),
33336     that._x2 + that._k * (that._x1 - x),
33337     that._y2 + that._k * (that._y1 - y),
33338     that._x2,
33339     that._y2
33340   );
33341 }
33342
33343 function Cardinal(context, tension) {
33344   this._context = context;
33345   this._k = (1 - tension) / 6;
33346 }
33347
33348 Cardinal.prototype = {
33349   areaStart: function() {
33350     this._line = 0;
33351   },
33352   areaEnd: function() {
33353     this._line = NaN;
33354   },
33355   lineStart: function() {
33356     this._x0 = this._x1 = this._x2 =
33357     this._y0 = this._y1 = this._y2 = NaN;
33358     this._point = 0;
33359   },
33360   lineEnd: function() {
33361     switch (this._point) {
33362       case 2: this._context.lineTo(this._x2, this._y2); break;
33363       case 3: point$3(this, this._x1, this._y1); break;
33364     }
33365     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33366     this._line = 1 - this._line;
33367   },
33368   point: function(x, y) {
33369     x = +x, y = +y;
33370     switch (this._point) {
33371       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33372       case 1: this._point = 2; this._x1 = x, this._y1 = y; break;
33373       case 2: this._point = 3; // proceed
33374       default: point$3(this, x, y); break;
33375     }
33376     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33377     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33378   }
33379 };
33380
33381 var cardinal = ((function custom(tension) {
33382
33383   function cardinal(context) {
33384     return new Cardinal(context, tension);
33385   }
33386
33387   cardinal.tension = function(tension) {
33388     return custom(+tension);
33389   };
33390
33391   return cardinal;
33392 }))(0);
33393
33394 function CardinalClosed(context, tension) {
33395   this._context = context;
33396   this._k = (1 - tension) / 6;
33397 }
33398
33399 CardinalClosed.prototype = {
33400   areaStart: noop$2,
33401   areaEnd: noop$2,
33402   lineStart: function() {
33403     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
33404     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
33405     this._point = 0;
33406   },
33407   lineEnd: function() {
33408     switch (this._point) {
33409       case 1: {
33410         this._context.moveTo(this._x3, this._y3);
33411         this._context.closePath();
33412         break;
33413       }
33414       case 2: {
33415         this._context.lineTo(this._x3, this._y3);
33416         this._context.closePath();
33417         break;
33418       }
33419       case 3: {
33420         this.point(this._x3, this._y3);
33421         this.point(this._x4, this._y4);
33422         this.point(this._x5, this._y5);
33423         break;
33424       }
33425     }
33426   },
33427   point: function(x, y) {
33428     x = +x, y = +y;
33429     switch (this._point) {
33430       case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
33431       case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
33432       case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
33433       default: point$3(this, x, y); break;
33434     }
33435     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33436     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33437   }
33438 };
33439
33440 var cardinalClosed = ((function custom(tension) {
33441
33442   function cardinal(context) {
33443     return new CardinalClosed(context, tension);
33444   }
33445
33446   cardinal.tension = function(tension) {
33447     return custom(+tension);
33448   };
33449
33450   return cardinal;
33451 }))(0);
33452
33453 function CardinalOpen(context, tension) {
33454   this._context = context;
33455   this._k = (1 - tension) / 6;
33456 }
33457
33458 CardinalOpen.prototype = {
33459   areaStart: function() {
33460     this._line = 0;
33461   },
33462   areaEnd: function() {
33463     this._line = NaN;
33464   },
33465   lineStart: function() {
33466     this._x0 = this._x1 = this._x2 =
33467     this._y0 = this._y1 = this._y2 = NaN;
33468     this._point = 0;
33469   },
33470   lineEnd: function() {
33471     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33472     this._line = 1 - this._line;
33473   },
33474   point: function(x, y) {
33475     x = +x, y = +y;
33476     switch (this._point) {
33477       case 0: this._point = 1; break;
33478       case 1: this._point = 2; break;
33479       case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
33480       case 3: this._point = 4; // proceed
33481       default: point$3(this, x, y); break;
33482     }
33483     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33484     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33485   }
33486 };
33487
33488 var cardinalOpen = ((function custom(tension) {
33489
33490   function cardinal(context) {
33491     return new CardinalOpen(context, tension);
33492   }
33493
33494   cardinal.tension = function(tension) {
33495     return custom(+tension);
33496   };
33497
33498   return cardinal;
33499 }))(0);
33500
33501 function point$4(that, x, y) {
33502   var x1 = that._x1,
33503       y1 = that._y1,
33504       x2 = that._x2,
33505       y2 = that._y2;
33506
33507   if (that._l01_a > epsilon$3) {
33508     var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,
33509         n = 3 * that._l01_a * (that._l01_a + that._l12_a);
33510     x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;
33511     y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;
33512   }
33513
33514   if (that._l23_a > epsilon$3) {
33515     var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,
33516         m = 3 * that._l23_a * (that._l23_a + that._l12_a);
33517     x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;
33518     y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;
33519   }
33520
33521   that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);
33522 }
33523
33524 function CatmullRom(context, alpha) {
33525   this._context = context;
33526   this._alpha = alpha;
33527 }
33528
33529 CatmullRom.prototype = {
33530   areaStart: function() {
33531     this._line = 0;
33532   },
33533   areaEnd: function() {
33534     this._line = NaN;
33535   },
33536   lineStart: function() {
33537     this._x0 = this._x1 = this._x2 =
33538     this._y0 = this._y1 = this._y2 = NaN;
33539     this._l01_a = this._l12_a = this._l23_a =
33540     this._l01_2a = this._l12_2a = this._l23_2a =
33541     this._point = 0;
33542   },
33543   lineEnd: function() {
33544     switch (this._point) {
33545       case 2: this._context.lineTo(this._x2, this._y2); break;
33546       case 3: this.point(this._x2, this._y2); break;
33547     }
33548     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33549     this._line = 1 - this._line;
33550   },
33551   point: function(x, y) {
33552     x = +x, y = +y;
33553
33554     if (this._point) {
33555       var x23 = this._x2 - x,
33556           y23 = this._y2 - y;
33557       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33558     }
33559
33560     switch (this._point) {
33561       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33562       case 1: this._point = 2; break;
33563       case 2: this._point = 3; // proceed
33564       default: point$4(this, x, y); break;
33565     }
33566
33567     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33568     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33569     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33570     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33571   }
33572 };
33573
33574 var catmullRom = ((function custom(alpha) {
33575
33576   function catmullRom(context) {
33577     return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0);
33578   }
33579
33580   catmullRom.alpha = function(alpha) {
33581     return custom(+alpha);
33582   };
33583
33584   return catmullRom;
33585 }))(0.5);
33586
33587 function CatmullRomClosed(context, alpha) {
33588   this._context = context;
33589   this._alpha = alpha;
33590 }
33591
33592 CatmullRomClosed.prototype = {
33593   areaStart: noop$2,
33594   areaEnd: noop$2,
33595   lineStart: function() {
33596     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
33597     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
33598     this._l01_a = this._l12_a = this._l23_a =
33599     this._l01_2a = this._l12_2a = this._l23_2a =
33600     this._point = 0;
33601   },
33602   lineEnd: function() {
33603     switch (this._point) {
33604       case 1: {
33605         this._context.moveTo(this._x3, this._y3);
33606         this._context.closePath();
33607         break;
33608       }
33609       case 2: {
33610         this._context.lineTo(this._x3, this._y3);
33611         this._context.closePath();
33612         break;
33613       }
33614       case 3: {
33615         this.point(this._x3, this._y3);
33616         this.point(this._x4, this._y4);
33617         this.point(this._x5, this._y5);
33618         break;
33619       }
33620     }
33621   },
33622   point: function(x, y) {
33623     x = +x, y = +y;
33624
33625     if (this._point) {
33626       var x23 = this._x2 - x,
33627           y23 = this._y2 - y;
33628       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33629     }
33630
33631     switch (this._point) {
33632       case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
33633       case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
33634       case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
33635       default: point$4(this, x, y); break;
33636     }
33637
33638     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33639     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33640     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33641     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33642   }
33643 };
33644
33645 var catmullRomClosed = ((function custom(alpha) {
33646
33647   function catmullRom(context) {
33648     return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0);
33649   }
33650
33651   catmullRom.alpha = function(alpha) {
33652     return custom(+alpha);
33653   };
33654
33655   return catmullRom;
33656 }))(0.5);
33657
33658 function CatmullRomOpen(context, alpha) {
33659   this._context = context;
33660   this._alpha = alpha;
33661 }
33662
33663 CatmullRomOpen.prototype = {
33664   areaStart: function() {
33665     this._line = 0;
33666   },
33667   areaEnd: function() {
33668     this._line = NaN;
33669   },
33670   lineStart: function() {
33671     this._x0 = this._x1 = this._x2 =
33672     this._y0 = this._y1 = this._y2 = NaN;
33673     this._l01_a = this._l12_a = this._l23_a =
33674     this._l01_2a = this._l12_2a = this._l23_2a =
33675     this._point = 0;
33676   },
33677   lineEnd: function() {
33678     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33679     this._line = 1 - this._line;
33680   },
33681   point: function(x, y) {
33682     x = +x, y = +y;
33683
33684     if (this._point) {
33685       var x23 = this._x2 - x,
33686           y23 = this._y2 - y;
33687       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33688     }
33689
33690     switch (this._point) {
33691       case 0: this._point = 1; break;
33692       case 1: this._point = 2; break;
33693       case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
33694       case 3: this._point = 4; // proceed
33695       default: point$4(this, x, y); break;
33696     }
33697
33698     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33699     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33700     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33701     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33702   }
33703 };
33704
33705 var catmullRomOpen = ((function custom(alpha) {
33706
33707   function catmullRom(context) {
33708     return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0);
33709   }
33710
33711   catmullRom.alpha = function(alpha) {
33712     return custom(+alpha);
33713   };
33714
33715   return catmullRom;
33716 }))(0.5);
33717
33718 function LinearClosed(context) {
33719   this._context = context;
33720 }
33721
33722 LinearClosed.prototype = {
33723   areaStart: noop$2,
33724   areaEnd: noop$2,
33725   lineStart: function() {
33726     this._point = 0;
33727   },
33728   lineEnd: function() {
33729     if (this._point) this._context.closePath();
33730   },
33731   point: function(x, y) {
33732     x = +x, y = +y;
33733     if (this._point) this._context.lineTo(x, y);
33734     else this._point = 1, this._context.moveTo(x, y);
33735   }
33736 };
33737
33738 var linearClosed = function(context) {
33739   return new LinearClosed(context);
33740 };
33741
33742 function sign$1(x) {
33743   return x < 0 ? -1 : 1;
33744 }
33745
33746 // Calculate the slopes of the tangents (Hermite-type interpolation) based on
33747 // the following paper: Steffen, M. 1990. A Simple Method for Monotonic
33748 // Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.
33749 // NOV(II), P. 443, 1990.
33750 function slope3(that, x2, y2) {
33751   var h0 = that._x1 - that._x0,
33752       h1 = x2 - that._x1,
33753       s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),
33754       s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),
33755       p = (s0 * h1 + s1 * h0) / (h0 + h1);
33756   return (sign$1(s0) + sign$1(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
33757 }
33758
33759 // Calculate a one-sided slope.
33760 function slope2(that, t) {
33761   var h = that._x1 - that._x0;
33762   return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;
33763 }
33764
33765 // According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations
33766 // "you can express cubic Hermite interpolation in terms of cubic Bézier curves
33767 // with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1".
33768 function point$5(that, t0, t1) {
33769   var x0 = that._x0,
33770       y0 = that._y0,
33771       x1 = that._x1,
33772       y1 = that._y1,
33773       dx = (x1 - x0) / 3;
33774   that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);
33775 }
33776
33777 function MonotoneX(context) {
33778   this._context = context;
33779 }
33780
33781 MonotoneX.prototype = {
33782   areaStart: function() {
33783     this._line = 0;
33784   },
33785   areaEnd: function() {
33786     this._line = NaN;
33787   },
33788   lineStart: function() {
33789     this._x0 = this._x1 =
33790     this._y0 = this._y1 =
33791     this._t0 = NaN;
33792     this._point = 0;
33793   },
33794   lineEnd: function() {
33795     switch (this._point) {
33796       case 2: this._context.lineTo(this._x1, this._y1); break;
33797       case 3: point$5(this, this._t0, slope2(this, this._t0)); break;
33798     }
33799     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33800     this._line = 1 - this._line;
33801   },
33802   point: function(x, y) {
33803     var t1 = NaN;
33804
33805     x = +x, y = +y;
33806     if (x === this._x1 && y === this._y1) return; // Ignore coincident points.
33807     switch (this._point) {
33808       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33809       case 1: this._point = 2; break;
33810       case 2: this._point = 3; point$5(this, slope2(this, t1 = slope3(this, x, y)), t1); break;
33811       default: point$5(this, this._t0, t1 = slope3(this, x, y)); break;
33812     }
33813
33814     this._x0 = this._x1, this._x1 = x;
33815     this._y0 = this._y1, this._y1 = y;
33816     this._t0 = t1;
33817   }
33818 };
33819
33820 function MonotoneY(context) {
33821   this._context = new ReflectContext(context);
33822 }
33823
33824 (MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {
33825   MonotoneX.prototype.point.call(this, y, x);
33826 };
33827
33828 function ReflectContext(context) {
33829   this._context = context;
33830 }
33831
33832 ReflectContext.prototype = {
33833   moveTo: function(x, y) { this._context.moveTo(y, x); },
33834   closePath: function() { this._context.closePath(); },
33835   lineTo: function(x, y) { this._context.lineTo(y, x); },
33836   bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }
33837 };
33838
33839 function monotoneX(context) {
33840   return new MonotoneX(context);
33841 }
33842
33843 function monotoneY(context) {
33844   return new MonotoneY(context);
33845 }
33846
33847 function Natural(context) {
33848   this._context = context;
33849 }
33850
33851 Natural.prototype = {
33852   areaStart: function() {
33853     this._line = 0;
33854   },
33855   areaEnd: function() {
33856     this._line = NaN;
33857   },
33858   lineStart: function() {
33859     this._x = [];
33860     this._y = [];
33861   },
33862   lineEnd: function() {
33863     var x = this._x,
33864         y = this._y,
33865         n = x.length;
33866
33867     if (n) {
33868       this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);
33869       if (n === 2) {
33870         this._context.lineTo(x[1], y[1]);
33871       } else {
33872         var px = controlPoints(x),
33873             py = controlPoints(y);
33874         for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {
33875           this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);
33876         }
33877       }
33878     }
33879
33880     if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();
33881     this._line = 1 - this._line;
33882     this._x = this._y = null;
33883   },
33884   point: function(x, y) {
33885     this._x.push(+x);
33886     this._y.push(+y);
33887   }
33888 };
33889
33890 // See https://www.particleincell.com/2012/bezier-splines/ for derivation.
33891 function controlPoints(x) {
33892   var i,
33893       n = x.length - 1,
33894       m,
33895       a = new Array(n),
33896       b = new Array(n),
33897       r = new Array(n);
33898   a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];
33899   for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];
33900   a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];
33901   for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];
33902   a[n - 1] = r[n - 1] / b[n - 1];
33903   for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];
33904   b[n - 1] = (x[n] + a[n - 1]) / 2;
33905   for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];
33906   return [a, b];
33907 }
33908
33909 var natural = function(context) {
33910   return new Natural(context);
33911 };
33912
33913 function Step(context, t) {
33914   this._context = context;
33915   this._t = t;
33916 }
33917
33918 Step.prototype = {
33919   areaStart: function() {
33920     this._line = 0;
33921   },
33922   areaEnd: function() {
33923     this._line = NaN;
33924   },
33925   lineStart: function() {
33926     this._x = this._y = NaN;
33927     this._point = 0;
33928   },
33929   lineEnd: function() {
33930     if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
33931     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33932     if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
33933   },
33934   point: function(x, y) {
33935     x = +x, y = +y;
33936     switch (this._point) {
33937       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33938       case 1: this._point = 2; // proceed
33939       default: {
33940         if (this._t <= 0) {
33941           this._context.lineTo(this._x, y);
33942           this._context.lineTo(x, y);
33943         } else {
33944           var x1 = this._x * (1 - this._t) + x * this._t;
33945           this._context.lineTo(x1, this._y);
33946           this._context.lineTo(x1, y);
33947         }
33948         break;
33949       }
33950     }
33951     this._x = x, this._y = y;
33952   }
33953 };
33954
33955 var step = function(context) {
33956   return new Step(context, 0.5);
33957 };
33958
33959 function stepBefore(context) {
33960   return new Step(context, 0);
33961 }
33962
33963 function stepAfter(context) {
33964   return new Step(context, 1);
33965 }
33966
33967 var slice$5 = Array.prototype.slice;
33968
33969 var none$1 = function(series, order) {
33970   if (!((n = series.length) > 1)) return;
33971   for (var i = 1, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {
33972     s0 = s1, s1 = series[order[i]];
33973     for (var j = 0; j < m; ++j) {
33974       s1[j][1] += s1[j][0] = isNaN(s0[j][1]) ? s0[j][0] : s0[j][1];
33975     }
33976   }
33977 };
33978
33979 var none$2 = function(series) {
33980   var n = series.length, o = new Array(n);
33981   while (--n >= 0) o[n] = n;
33982   return o;
33983 };
33984
33985 function stackValue(d, key) {
33986   return d[key];
33987 }
33988
33989 var stack = function() {
33990   var keys = constant$10([]),
33991       order = none$2,
33992       offset = none$1,
33993       value = stackValue;
33994
33995   function stack(data) {
33996     var kz = keys.apply(this, arguments),
33997         i,
33998         m = data.length,
33999         n = kz.length,
34000         sz = new Array(n),
34001         oz;
34002
34003     for (i = 0; i < n; ++i) {
34004       for (var ki = kz[i], si = sz[i] = new Array(m), j = 0, sij; j < m; ++j) {
34005         si[j] = sij = [0, +value(data[j], ki, j, data)];
34006         sij.data = data[j];
34007       }
34008       si.key = ki;
34009     }
34010
34011     for (i = 0, oz = order(sz); i < n; ++i) {
34012       sz[oz[i]].index = i;
34013     }
34014
34015     offset(sz, oz);
34016     return sz;
34017   }
34018
34019   stack.keys = function(_) {
34020     return arguments.length ? (keys = typeof _ === "function" ? _ : constant$10(slice$5.call(_)), stack) : keys;
34021   };
34022
34023   stack.value = function(_) {
34024     return arguments.length ? (value = typeof _ === "function" ? _ : constant$10(+_), stack) : value;
34025   };
34026
34027   stack.order = function(_) {
34028     return arguments.length ? (order = _ == null ? none$2 : typeof _ === "function" ? _ : constant$10(slice$5.call(_)), stack) : order;
34029   };
34030
34031   stack.offset = function(_) {
34032     return arguments.length ? (offset = _ == null ? none$1 : _, stack) : offset;
34033   };
34034
34035   return stack;
34036 };
34037
34038 var expand = function(series, order) {
34039   if (!((n = series.length) > 0)) return;
34040   for (var i, n, j = 0, m = series[0].length, y; j < m; ++j) {
34041     for (y = i = 0; i < n; ++i) y += series[i][j][1] || 0;
34042     if (y) for (i = 0; i < n; ++i) series[i][j][1] /= y;
34043   }
34044   none$1(series, order);
34045 };
34046
34047 var silhouette = function(series, order) {
34048   if (!((n = series.length) > 0)) return;
34049   for (var j = 0, s0 = series[order[0]], n, m = s0.length; j < m; ++j) {
34050     for (var i = 0, y = 0; i < n; ++i) y += series[i][j][1] || 0;
34051     s0[j][1] += s0[j][0] = -y / 2;
34052   }
34053   none$1(series, order);
34054 };
34055
34056 var wiggle = function(series, order) {
34057   if (!((n = series.length) > 0) || !((m = (s0 = series[order[0]]).length) > 0)) return;
34058   for (var y = 0, j = 1, s0, m, n; j < m; ++j) {
34059     for (var i = 0, s1 = 0, s2 = 0; i < n; ++i) {
34060       var si = series[order[i]],
34061           sij0 = si[j][1] || 0,
34062           sij1 = si[j - 1][1] || 0,
34063           s3 = (sij0 - sij1) / 2;
34064       for (var k = 0; k < i; ++k) {
34065         var sk = series[order[k]],
34066             skj0 = sk[j][1] || 0,
34067             skj1 = sk[j - 1][1] || 0;
34068         s3 += skj0 - skj1;
34069       }
34070       s1 += sij0, s2 += s3 * sij0;
34071     }
34072     s0[j - 1][1] += s0[j - 1][0] = y;
34073     if (s1) y -= s2 / s1;
34074   }
34075   s0[j - 1][1] += s0[j - 1][0] = y;
34076   none$1(series, order);
34077 };
34078
34079 var ascending$2 = function(series) {
34080   var sums = series.map(sum$2);
34081   return none$2(series).sort(function(a, b) { return sums[a] - sums[b]; });
34082 };
34083
34084 function sum$2(series) {
34085   var s = 0, i = -1, n = series.length, v;
34086   while (++i < n) if (v = +series[i][1]) s += v;
34087   return s;
34088 }
34089
34090 var descending$2 = function(series) {
34091   return ascending$2(series).reverse();
34092 };
34093
34094 var insideOut = function(series) {
34095   var n = series.length,
34096       i,
34097       j,
34098       sums = series.map(sum$2),
34099       order = none$2(series).sort(function(a, b) { return sums[b] - sums[a]; }),
34100       top = 0,
34101       bottom = 0,
34102       tops = [],
34103       bottoms = [];
34104
34105   for (i = 0; i < n; ++i) {
34106     j = order[i];
34107     if (top < bottom) {
34108       top += sums[j];
34109       tops.push(j);
34110     } else {
34111       bottom += sums[j];
34112       bottoms.push(j);
34113     }
34114   }
34115
34116   return bottoms.reverse().concat(tops);
34117 };
34118
34119 var reverse = function(series) {
34120   return none$2(series).reverse();
34121 };
34122
34123 var constant$11 = function(x) {
34124   return function() {
34125     return x;
34126   };
34127 };
34128
34129 function x$4(d) {
34130   return d[0];
34131 }
34132
34133 function y$4(d) {
34134   return d[1];
34135 }
34136
34137 function RedBlackTree() {
34138   this._ = null; // root node
34139 }
34140
34141 function RedBlackNode(node) {
34142   node.U = // parent node
34143   node.C = // color - true for red, false for black
34144   node.L = // left node
34145   node.R = // right node
34146   node.P = // previous node
34147   node.N = null; // next node
34148 }
34149
34150 RedBlackTree.prototype = {
34151   constructor: RedBlackTree,
34152
34153   insert: function(after, node) {
34154     var parent, grandpa, uncle;
34155
34156     if (after) {
34157       node.P = after;
34158       node.N = after.N;
34159       if (after.N) after.N.P = node;
34160       after.N = node;
34161       if (after.R) {
34162         after = after.R;
34163         while (after.L) after = after.L;
34164         after.L = node;
34165       } else {
34166         after.R = node;
34167       }
34168       parent = after;
34169     } else if (this._) {
34170       after = RedBlackFirst(this._);
34171       node.P = null;
34172       node.N = after;
34173       after.P = after.L = node;
34174       parent = after;
34175     } else {
34176       node.P = node.N = null;
34177       this._ = node;
34178       parent = null;
34179     }
34180     node.L = node.R = null;
34181     node.U = parent;
34182     node.C = true;
34183
34184     after = node;
34185     while (parent && parent.C) {
34186       grandpa = parent.U;
34187       if (parent === grandpa.L) {
34188         uncle = grandpa.R;
34189         if (uncle && uncle.C) {
34190           parent.C = uncle.C = false;
34191           grandpa.C = true;
34192           after = grandpa;
34193         } else {
34194           if (after === parent.R) {
34195             RedBlackRotateLeft(this, parent);
34196             after = parent;
34197             parent = after.U;
34198           }
34199           parent.C = false;
34200           grandpa.C = true;
34201           RedBlackRotateRight(this, grandpa);
34202         }
34203       } else {
34204         uncle = grandpa.L;
34205         if (uncle && uncle.C) {
34206           parent.C = uncle.C = false;
34207           grandpa.C = true;
34208           after = grandpa;
34209         } else {
34210           if (after === parent.L) {
34211             RedBlackRotateRight(this, parent);
34212             after = parent;
34213             parent = after.U;
34214           }
34215           parent.C = false;
34216           grandpa.C = true;
34217           RedBlackRotateLeft(this, grandpa);
34218         }
34219       }
34220       parent = after.U;
34221     }
34222     this._.C = false;
34223   },
34224
34225   remove: function(node) {
34226     if (node.N) node.N.P = node.P;
34227     if (node.P) node.P.N = node.N;
34228     node.N = node.P = null;
34229
34230     var parent = node.U,
34231         sibling,
34232         left = node.L,
34233         right = node.R,
34234         next,
34235         red;
34236
34237     if (!left) next = right;
34238     else if (!right) next = left;
34239     else next = RedBlackFirst(right);
34240
34241     if (parent) {
34242       if (parent.L === node) parent.L = next;
34243       else parent.R = next;
34244     } else {
34245       this._ = next;
34246     }
34247
34248     if (left && right) {
34249       red = next.C;
34250       next.C = node.C;
34251       next.L = left;
34252       left.U = next;
34253       if (next !== right) {
34254         parent = next.U;
34255         next.U = node.U;
34256         node = next.R;
34257         parent.L = node;
34258         next.R = right;
34259         right.U = next;
34260       } else {
34261         next.U = parent;
34262         parent = next;
34263         node = next.R;
34264       }
34265     } else {
34266       red = node.C;
34267       node = next;
34268     }
34269
34270     if (node) node.U = parent;
34271     if (red) return;
34272     if (node && node.C) { node.C = false; return; }
34273
34274     do {
34275       if (node === this._) break;
34276       if (node === parent.L) {
34277         sibling = parent.R;
34278         if (sibling.C) {
34279           sibling.C = false;
34280           parent.C = true;
34281           RedBlackRotateLeft(this, parent);
34282           sibling = parent.R;
34283         }
34284         if ((sibling.L && sibling.L.C)
34285             || (sibling.R && sibling.R.C)) {
34286           if (!sibling.R || !sibling.R.C) {
34287             sibling.L.C = false;
34288             sibling.C = true;
34289             RedBlackRotateRight(this, sibling);
34290             sibling = parent.R;
34291           }
34292           sibling.C = parent.C;
34293           parent.C = sibling.R.C = false;
34294           RedBlackRotateLeft(this, parent);
34295           node = this._;
34296           break;
34297         }
34298       } else {
34299         sibling = parent.L;
34300         if (sibling.C) {
34301           sibling.C = false;
34302           parent.C = true;
34303           RedBlackRotateRight(this, parent);
34304           sibling = parent.L;
34305         }
34306         if ((sibling.L && sibling.L.C)
34307           || (sibling.R && sibling.R.C)) {
34308           if (!sibling.L || !sibling.L.C) {
34309             sibling.R.C = false;
34310             sibling.C = true;
34311             RedBlackRotateLeft(this, sibling);
34312             sibling = parent.L;
34313           }
34314           sibling.C = parent.C;
34315           parent.C = sibling.L.C = false;
34316           RedBlackRotateRight(this, parent);
34317           node = this._;
34318           break;
34319         }
34320       }
34321       sibling.C = true;
34322       node = parent;
34323       parent = parent.U;
34324     } while (!node.C);
34325
34326     if (node) node.C = false;
34327   }
34328 };
34329
34330 function RedBlackRotateLeft(tree, node) {
34331   var p = node,
34332       q = node.R,
34333       parent = p.U;
34334
34335   if (parent) {
34336     if (parent.L === p) parent.L = q;
34337     else parent.R = q;
34338   } else {
34339     tree._ = q;
34340   }
34341
34342   q.U = parent;
34343   p.U = q;
34344   p.R = q.L;
34345   if (p.R) p.R.U = p;
34346   q.L = p;
34347 }
34348
34349 function RedBlackRotateRight(tree, node) {
34350   var p = node,
34351       q = node.L,
34352       parent = p.U;
34353
34354   if (parent) {
34355     if (parent.L === p) parent.L = q;
34356     else parent.R = q;
34357   } else {
34358     tree._ = q;
34359   }
34360
34361   q.U = parent;
34362   p.U = q;
34363   p.L = q.R;
34364   if (p.L) p.L.U = p;
34365   q.R = p;
34366 }
34367
34368 function RedBlackFirst(node) {
34369   while (node.L) node = node.L;
34370   return node;
34371 }
34372
34373 function createEdge(left, right, v0, v1) {
34374   var edge = [null, null],
34375       index = edges.push(edge) - 1;
34376   edge.left = left;
34377   edge.right = right;
34378   if (v0) setEdgeEnd(edge, left, right, v0);
34379   if (v1) setEdgeEnd(edge, right, left, v1);
34380   cells[left.index].halfedges.push(index);
34381   cells[right.index].halfedges.push(index);
34382   return edge;
34383 }
34384
34385 function createBorderEdge(left, v0, v1) {
34386   var edge = [v0, v1];
34387   edge.left = left;
34388   return edge;
34389 }
34390
34391 function setEdgeEnd(edge, left, right, vertex) {
34392   if (!edge[0] && !edge[1]) {
34393     edge[0] = vertex;
34394     edge.left = left;
34395     edge.right = right;
34396   } else if (edge.left === right) {
34397     edge[1] = vertex;
34398   } else {
34399     edge[0] = vertex;
34400   }
34401 }
34402
34403 // Liang–Barsky line clipping.
34404 function clipEdge(edge, x0, y0, x1, y1) {
34405   var a = edge[0],
34406       b = edge[1],
34407       ax = a[0],
34408       ay = a[1],
34409       bx = b[0],
34410       by = b[1],
34411       t0 = 0,
34412       t1 = 1,
34413       dx = bx - ax,
34414       dy = by - ay,
34415       r;
34416
34417   r = x0 - ax;
34418   if (!dx && r > 0) return;
34419   r /= dx;
34420   if (dx < 0) {
34421     if (r < t0) return;
34422     if (r < t1) t1 = r;
34423   } else if (dx > 0) {
34424     if (r > t1) return;
34425     if (r > t0) t0 = r;
34426   }
34427
34428   r = x1 - ax;
34429   if (!dx && r < 0) return;
34430   r /= dx;
34431   if (dx < 0) {
34432     if (r > t1) return;
34433     if (r > t0) t0 = r;
34434   } else if (dx > 0) {
34435     if (r < t0) return;
34436     if (r < t1) t1 = r;
34437   }
34438
34439   r = y0 - ay;
34440   if (!dy && r > 0) return;
34441   r /= dy;
34442   if (dy < 0) {
34443     if (r < t0) return;
34444     if (r < t1) t1 = r;
34445   } else if (dy > 0) {
34446     if (r > t1) return;
34447     if (r > t0) t0 = r;
34448   }
34449
34450   r = y1 - ay;
34451   if (!dy && r < 0) return;
34452   r /= dy;
34453   if (dy < 0) {
34454     if (r > t1) return;
34455     if (r > t0) t0 = r;
34456   } else if (dy > 0) {
34457     if (r < t0) return;
34458     if (r < t1) t1 = r;
34459   }
34460
34461   if (!(t0 > 0) && !(t1 < 1)) return true; // TODO Better check?
34462
34463   if (t0 > 0) edge[0] = [ax + t0 * dx, ay + t0 * dy];
34464   if (t1 < 1) edge[1] = [ax + t1 * dx, ay + t1 * dy];
34465   return true;
34466 }
34467
34468 function connectEdge(edge, x0, y0, x1, y1) {
34469   var v1 = edge[1];
34470   if (v1) return true;
34471
34472   var v0 = edge[0],
34473       left = edge.left,
34474       right = edge.right,
34475       lx = left[0],
34476       ly = left[1],
34477       rx = right[0],
34478       ry = right[1],
34479       fx = (lx + rx) / 2,
34480       fy = (ly + ry) / 2,
34481       fm,
34482       fb;
34483
34484   if (ry === ly) {
34485     if (fx < x0 || fx >= x1) return;
34486     if (lx > rx) {
34487       if (!v0) v0 = [fx, y0];
34488       else if (v0[1] >= y1) return;
34489       v1 = [fx, y1];
34490     } else {
34491       if (!v0) v0 = [fx, y1];
34492       else if (v0[1] < y0) return;
34493       v1 = [fx, y0];
34494     }
34495   } else {
34496     fm = (lx - rx) / (ry - ly);
34497     fb = fy - fm * fx;
34498     if (fm < -1 || fm > 1) {
34499       if (lx > rx) {
34500         if (!v0) v0 = [(y0 - fb) / fm, y0];
34501         else if (v0[1] >= y1) return;
34502         v1 = [(y1 - fb) / fm, y1];
34503       } else {
34504         if (!v0) v0 = [(y1 - fb) / fm, y1];
34505         else if (v0[1] < y0) return;
34506         v1 = [(y0 - fb) / fm, y0];
34507       }
34508     } else {
34509       if (ly < ry) {
34510         if (!v0) v0 = [x0, fm * x0 + fb];
34511         else if (v0[0] >= x1) return;
34512         v1 = [x1, fm * x1 + fb];
34513       } else {
34514         if (!v0) v0 = [x1, fm * x1 + fb];
34515         else if (v0[0] < x0) return;
34516         v1 = [x0, fm * x0 + fb];
34517       }
34518     }
34519   }
34520
34521   edge[0] = v0;
34522   edge[1] = v1;
34523   return true;
34524 }
34525
34526 function clipEdges(x0, y0, x1, y1) {
34527   var i = edges.length,
34528       edge;
34529
34530   while (i--) {
34531     if (!connectEdge(edge = edges[i], x0, y0, x1, y1)
34532         || !clipEdge(edge, x0, y0, x1, y1)
34533         || !(Math.abs(edge[0][0] - edge[1][0]) > epsilon$4
34534             || Math.abs(edge[0][1] - edge[1][1]) > epsilon$4)) {
34535       delete edges[i];
34536     }
34537   }
34538 }
34539
34540 function createCell(site) {
34541   return cells[site.index] = {
34542     site: site,
34543     halfedges: []
34544   };
34545 }
34546
34547 function cellHalfedgeAngle(cell, edge) {
34548   var site = cell.site,
34549       va = edge.left,
34550       vb = edge.right;
34551   if (site === vb) vb = va, va = site;
34552   if (vb) return Math.atan2(vb[1] - va[1], vb[0] - va[0]);
34553   if (site === va) va = edge[1], vb = edge[0];
34554   else va = edge[0], vb = edge[1];
34555   return Math.atan2(va[0] - vb[0], vb[1] - va[1]);
34556 }
34557
34558 function cellHalfedgeStart(cell, edge) {
34559   return edge[+(edge.left !== cell.site)];
34560 }
34561
34562 function cellHalfedgeEnd(cell, edge) {
34563   return edge[+(edge.left === cell.site)];
34564 }
34565
34566 function sortCellHalfedges() {
34567   for (var i = 0, n = cells.length, cell, halfedges, j, m; i < n; ++i) {
34568     if ((cell = cells[i]) && (m = (halfedges = cell.halfedges).length)) {
34569       var index = new Array(m),
34570           array = new Array(m);
34571       for (j = 0; j < m; ++j) index[j] = j, array[j] = cellHalfedgeAngle(cell, edges[halfedges[j]]);
34572       index.sort(function(i, j) { return array[j] - array[i]; });
34573       for (j = 0; j < m; ++j) array[j] = halfedges[index[j]];
34574       for (j = 0; j < m; ++j) halfedges[j] = array[j];
34575     }
34576   }
34577 }
34578
34579 function clipCells(x0, y0, x1, y1) {
34580   var nCells = cells.length,
34581       iCell,
34582       cell,
34583       site,
34584       iHalfedge,
34585       halfedges,
34586       nHalfedges,
34587       start,
34588       startX,
34589       startY,
34590       end,
34591       endX,
34592       endY,
34593       cover = true;
34594
34595   for (iCell = 0; iCell < nCells; ++iCell) {
34596     if (cell = cells[iCell]) {
34597       site = cell.site;
34598       halfedges = cell.halfedges;
34599       iHalfedge = halfedges.length;
34600
34601       // Remove any dangling clipped edges.
34602       while (iHalfedge--) {
34603         if (!edges[halfedges[iHalfedge]]) {
34604           halfedges.splice(iHalfedge, 1);
34605         }
34606       }
34607
34608       // Insert any border edges as necessary.
34609       iHalfedge = 0, nHalfedges = halfedges.length;
34610       while (iHalfedge < nHalfedges) {
34611         end = cellHalfedgeEnd(cell, edges[halfedges[iHalfedge]]), endX = end[0], endY = end[1];
34612         start = cellHalfedgeStart(cell, edges[halfedges[++iHalfedge % nHalfedges]]), startX = start[0], startY = start[1];
34613         if (Math.abs(endX - startX) > epsilon$4 || Math.abs(endY - startY) > epsilon$4) {
34614           halfedges.splice(iHalfedge, 0, edges.push(createBorderEdge(site, end,
34615               Math.abs(endX - x0) < epsilon$4 && y1 - endY > epsilon$4 ? [x0, Math.abs(startX - x0) < epsilon$4 ? startY : y1]
34616               : Math.abs(endY - y1) < epsilon$4 && x1 - endX > epsilon$4 ? [Math.abs(startY - y1) < epsilon$4 ? startX : x1, y1]
34617               : Math.abs(endX - x1) < epsilon$4 && endY - y0 > epsilon$4 ? [x1, Math.abs(startX - x1) < epsilon$4 ? startY : y0]
34618               : Math.abs(endY - y0) < epsilon$4 && endX - x0 > epsilon$4 ? [Math.abs(startY - y0) < epsilon$4 ? startX : x0, y0]
34619               : null)) - 1);
34620           ++nHalfedges;
34621         }
34622       }
34623
34624       if (nHalfedges) cover = false;
34625     }
34626   }
34627
34628   // If there weren’t any edges, have the closest site cover the extent.
34629   // It doesn’t matter which corner of the extent we measure!
34630   if (cover) {
34631     var dx, dy, d2, dc = Infinity;
34632
34633     for (iCell = 0, cover = null; iCell < nCells; ++iCell) {
34634       if (cell = cells[iCell]) {
34635         site = cell.site;
34636         dx = site[0] - x0;
34637         dy = site[1] - y0;
34638         d2 = dx * dx + dy * dy;
34639         if (d2 < dc) dc = d2, cover = cell;
34640       }
34641     }
34642
34643     if (cover) {
34644       var v00 = [x0, y0], v01 = [x0, y1], v11 = [x1, y1], v10 = [x1, y0];
34645       cover.halfedges.push(
34646         edges.push(createBorderEdge(site = cover.site, v00, v01)) - 1,
34647         edges.push(createBorderEdge(site, v01, v11)) - 1,
34648         edges.push(createBorderEdge(site, v11, v10)) - 1,
34649         edges.push(createBorderEdge(site, v10, v00)) - 1
34650       );
34651     }
34652   }
34653
34654   // Lastly delete any cells with no edges; these were entirely clipped.
34655   for (iCell = 0; iCell < nCells; ++iCell) {
34656     if (cell = cells[iCell]) {
34657       if (!cell.halfedges.length) {
34658         delete cells[iCell];
34659       }
34660     }
34661   }
34662 }
34663
34664 var circlePool = [];
34665
34666 var firstCircle;
34667
34668 function Circle() {
34669   RedBlackNode(this);
34670   this.x =
34671   this.y =
34672   this.arc =
34673   this.site =
34674   this.cy = null;
34675 }
34676
34677 function attachCircle(arc) {
34678   var lArc = arc.P,
34679       rArc = arc.N;
34680
34681   if (!lArc || !rArc) return;
34682
34683   var lSite = lArc.site,
34684       cSite = arc.site,
34685       rSite = rArc.site;
34686
34687   if (lSite === rSite) return;
34688
34689   var bx = cSite[0],
34690       by = cSite[1],
34691       ax = lSite[0] - bx,
34692       ay = lSite[1] - by,
34693       cx = rSite[0] - bx,
34694       cy = rSite[1] - by;
34695
34696   var d = 2 * (ax * cy - ay * cx);
34697   if (d >= -epsilon2$2) return;
34698
34699   var ha = ax * ax + ay * ay,
34700       hc = cx * cx + cy * cy,
34701       x = (cy * ha - ay * hc) / d,
34702       y = (ax * hc - cx * ha) / d;
34703
34704   var circle = circlePool.pop() || new Circle;
34705   circle.arc = arc;
34706   circle.site = cSite;
34707   circle.x = x + bx;
34708   circle.y = (circle.cy = y + by) + Math.sqrt(x * x + y * y); // y bottom
34709
34710   arc.circle = circle;
34711
34712   var before = null,
34713       node = circles._;
34714
34715   while (node) {
34716     if (circle.y < node.y || (circle.y === node.y && circle.x <= node.x)) {
34717       if (node.L) node = node.L;
34718       else { before = node.P; break; }
34719     } else {
34720       if (node.R) node = node.R;
34721       else { before = node; break; }
34722     }
34723   }
34724
34725   circles.insert(before, circle);
34726   if (!before) firstCircle = circle;
34727 }
34728
34729 function detachCircle(arc) {
34730   var circle = arc.circle;
34731   if (circle) {
34732     if (!circle.P) firstCircle = circle.N;
34733     circles.remove(circle);
34734     circlePool.push(circle);
34735     RedBlackNode(circle);
34736     arc.circle = null;
34737   }
34738 }
34739
34740 var beachPool = [];
34741
34742 function Beach() {
34743   RedBlackNode(this);
34744   this.edge =
34745   this.site =
34746   this.circle = null;
34747 }
34748
34749 function createBeach(site) {
34750   var beach = beachPool.pop() || new Beach;
34751   beach.site = site;
34752   return beach;
34753 }
34754
34755 function detachBeach(beach) {
34756   detachCircle(beach);
34757   beaches.remove(beach);
34758   beachPool.push(beach);
34759   RedBlackNode(beach);
34760 }
34761
34762 function removeBeach(beach) {
34763   var circle = beach.circle,
34764       x = circle.x,
34765       y = circle.cy,
34766       vertex = [x, y],
34767       previous = beach.P,
34768       next = beach.N,
34769       disappearing = [beach];
34770
34771   detachBeach(beach);
34772
34773   var lArc = previous;
34774   while (lArc.circle
34775       && Math.abs(x - lArc.circle.x) < epsilon$4
34776       && Math.abs(y - lArc.circle.cy) < epsilon$4) {
34777     previous = lArc.P;
34778     disappearing.unshift(lArc);
34779     detachBeach(lArc);
34780     lArc = previous;
34781   }
34782
34783   disappearing.unshift(lArc);
34784   detachCircle(lArc);
34785
34786   var rArc = next;
34787   while (rArc.circle
34788       && Math.abs(x - rArc.circle.x) < epsilon$4
34789       && Math.abs(y - rArc.circle.cy) < epsilon$4) {
34790     next = rArc.N;
34791     disappearing.push(rArc);
34792     detachBeach(rArc);
34793     rArc = next;
34794   }
34795
34796   disappearing.push(rArc);
34797   detachCircle(rArc);
34798
34799   var nArcs = disappearing.length,
34800       iArc;
34801   for (iArc = 1; iArc < nArcs; ++iArc) {
34802     rArc = disappearing[iArc];
34803     lArc = disappearing[iArc - 1];
34804     setEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
34805   }
34806
34807   lArc = disappearing[0];
34808   rArc = disappearing[nArcs - 1];
34809   rArc.edge = createEdge(lArc.site, rArc.site, null, vertex);
34810
34811   attachCircle(lArc);
34812   attachCircle(rArc);
34813 }
34814
34815 function addBeach(site) {
34816   var x = site[0],
34817       directrix = site[1],
34818       lArc,
34819       rArc,
34820       dxl,
34821       dxr,
34822       node = beaches._;
34823
34824   while (node) {
34825     dxl = leftBreakPoint(node, directrix) - x;
34826     if (dxl > epsilon$4) node = node.L; else {
34827       dxr = x - rightBreakPoint(node, directrix);
34828       if (dxr > epsilon$4) {
34829         if (!node.R) {
34830           lArc = node;
34831           break;
34832         }
34833         node = node.R;
34834       } else {
34835         if (dxl > -epsilon$4) {
34836           lArc = node.P;
34837           rArc = node;
34838         } else if (dxr > -epsilon$4) {
34839           lArc = node;
34840           rArc = node.N;
34841         } else {
34842           lArc = rArc = node;
34843         }
34844         break;
34845       }
34846     }
34847   }
34848
34849   createCell(site);
34850   var newArc = createBeach(site);
34851   beaches.insert(lArc, newArc);
34852
34853   if (!lArc && !rArc) return;
34854
34855   if (lArc === rArc) {
34856     detachCircle(lArc);
34857     rArc = createBeach(lArc.site);
34858     beaches.insert(newArc, rArc);
34859     newArc.edge = rArc.edge = createEdge(lArc.site, newArc.site);
34860     attachCircle(lArc);
34861     attachCircle(rArc);
34862     return;
34863   }
34864
34865   if (!rArc) { // && lArc
34866     newArc.edge = createEdge(lArc.site, newArc.site);
34867     return;
34868   }
34869
34870   // else lArc !== rArc
34871   detachCircle(lArc);
34872   detachCircle(rArc);
34873
34874   var lSite = lArc.site,
34875       ax = lSite[0],
34876       ay = lSite[1],
34877       bx = site[0] - ax,
34878       by = site[1] - ay,
34879       rSite = rArc.site,
34880       cx = rSite[0] - ax,
34881       cy = rSite[1] - ay,
34882       d = 2 * (bx * cy - by * cx),
34883       hb = bx * bx + by * by,
34884       hc = cx * cx + cy * cy,
34885       vertex = [(cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay];
34886
34887   setEdgeEnd(rArc.edge, lSite, rSite, vertex);
34888   newArc.edge = createEdge(lSite, site, null, vertex);
34889   rArc.edge = createEdge(site, rSite, null, vertex);
34890   attachCircle(lArc);
34891   attachCircle(rArc);
34892 }
34893
34894 function leftBreakPoint(arc, directrix) {
34895   var site = arc.site,
34896       rfocx = site[0],
34897       rfocy = site[1],
34898       pby2 = rfocy - directrix;
34899
34900   if (!pby2) return rfocx;
34901
34902   var lArc = arc.P;
34903   if (!lArc) return -Infinity;
34904
34905   site = lArc.site;
34906   var lfocx = site[0],
34907       lfocy = site[1],
34908       plby2 = lfocy - directrix;
34909
34910   if (!plby2) return lfocx;
34911
34912   var hl = lfocx - rfocx,
34913       aby2 = 1 / pby2 - 1 / plby2,
34914       b = hl / plby2;
34915
34916   if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
34917
34918   return (rfocx + lfocx) / 2;
34919 }
34920
34921 function rightBreakPoint(arc, directrix) {
34922   var rArc = arc.N;
34923   if (rArc) return leftBreakPoint(rArc, directrix);
34924   var site = arc.site;
34925   return site[1] === directrix ? site[0] : Infinity;
34926 }
34927
34928 var epsilon$4 = 1e-6;
34929 var epsilon2$2 = 1e-12;
34930 var beaches;
34931 var cells;
34932 var circles;
34933 var edges;
34934
34935 function triangleArea(a, b, c) {
34936   return (a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]);
34937 }
34938
34939 function lexicographic(a, b) {
34940   return b[1] - a[1]
34941       || b[0] - a[0];
34942 }
34943
34944 function Diagram(sites, extent) {
34945   var site = sites.sort(lexicographic).pop(),
34946       x,
34947       y,
34948       circle;
34949
34950   edges = [];
34951   cells = new Array(sites.length);
34952   beaches = new RedBlackTree;
34953   circles = new RedBlackTree;
34954
34955   while (true) {
34956     circle = firstCircle;
34957     if (site && (!circle || site[1] < circle.y || (site[1] === circle.y && site[0] < circle.x))) {
34958       if (site[0] !== x || site[1] !== y) {
34959         addBeach(site);
34960         x = site[0], y = site[1];
34961       }
34962       site = sites.pop();
34963     } else if (circle) {
34964       removeBeach(circle.arc);
34965     } else {
34966       break;
34967     }
34968   }
34969
34970   sortCellHalfedges();
34971
34972   if (extent) {
34973     var x0 = +extent[0][0],
34974         y0 = +extent[0][1],
34975         x1 = +extent[1][0],
34976         y1 = +extent[1][1];
34977     clipEdges(x0, y0, x1, y1);
34978     clipCells(x0, y0, x1, y1);
34979   }
34980
34981   this.edges = edges;
34982   this.cells = cells;
34983
34984   beaches =
34985   circles =
34986   edges =
34987   cells = null;
34988 }
34989
34990 Diagram.prototype = {
34991   constructor: Diagram,
34992
34993   polygons: function() {
34994     var edges = this.edges;
34995
34996     return this.cells.map(function(cell) {
34997       var polygon = cell.halfedges.map(function(i) { return cellHalfedgeStart(cell, edges[i]); });
34998       polygon.data = cell.site.data;
34999       return polygon;
35000     });
35001   },
35002
35003   triangles: function() {
35004     var triangles = [],
35005         edges = this.edges;
35006
35007     this.cells.forEach(function(cell, i) {
35008       if (!(m = (halfedges = cell.halfedges).length)) return;
35009       var site = cell.site,
35010           halfedges,
35011           j = -1,
35012           m,
35013           s0,
35014           e1 = edges[halfedges[m - 1]],
35015           s1 = e1.left === site ? e1.right : e1.left;
35016
35017       while (++j < m) {
35018         s0 = s1;
35019         e1 = edges[halfedges[j]];
35020         s1 = e1.left === site ? e1.right : e1.left;
35021         if (s0 && s1 && i < s0.index && i < s1.index && triangleArea(site, s0, s1) < 0) {
35022           triangles.push([site.data, s0.data, s1.data]);
35023         }
35024       }
35025     });
35026
35027     return triangles;
35028   },
35029
35030   links: function() {
35031     return this.edges.filter(function(edge) {
35032       return edge.right;
35033     }).map(function(edge) {
35034       return {
35035         source: edge.left.data,
35036         target: edge.right.data
35037       };
35038     });
35039   },
35040
35041   find: function(x, y, radius) {
35042     var that = this, i0, i1 = that._found || 0, n = that.cells.length, cell;
35043
35044     // Use the previously-found cell, or start with an arbitrary one.
35045     while (!(cell = that.cells[i1])) if (++i1 >= n) return null;
35046     var dx = x - cell.site[0], dy = y - cell.site[1], d2 = dx * dx + dy * dy;
35047
35048     // Traverse the half-edges to find a closer cell, if any.
35049     do {
35050       cell = that.cells[i0 = i1], i1 = null;
35051       cell.halfedges.forEach(function(e) {
35052         var edge = that.edges[e], v = edge.left;
35053         if ((v === cell.site || !v) && !(v = edge.right)) return;
35054         var vx = x - v[0], vy = y - v[1], v2 = vx * vx + vy * vy;
35055         if (v2 < d2) d2 = v2, i1 = v.index;
35056       });
35057     } while (i1 !== null);
35058
35059     that._found = i0;
35060
35061     return radius == null || d2 <= radius * radius ? cell.site : null;
35062   }
35063 };
35064
35065 var voronoi = function() {
35066   var x$$1 = x$4,
35067       y$$1 = y$4,
35068       extent = null;
35069
35070   function voronoi(data) {
35071     return new Diagram(data.map(function(d, i) {
35072       var s = [Math.round(x$$1(d, i, data) / epsilon$4) * epsilon$4, Math.round(y$$1(d, i, data) / epsilon$4) * epsilon$4];
35073       s.index = i;
35074       s.data = d;
35075       return s;
35076     }), extent);
35077   }
35078
35079   voronoi.polygons = function(data) {
35080     return voronoi(data).polygons();
35081   };
35082
35083   voronoi.links = function(data) {
35084     return voronoi(data).links();
35085   };
35086
35087   voronoi.triangles = function(data) {
35088     return voronoi(data).triangles();
35089   };
35090
35091   voronoi.x = function(_) {
35092     return arguments.length ? (x$$1 = typeof _ === "function" ? _ : constant$11(+_), voronoi) : x$$1;
35093   };
35094
35095   voronoi.y = function(_) {
35096     return arguments.length ? (y$$1 = typeof _ === "function" ? _ : constant$11(+_), voronoi) : y$$1;
35097   };
35098
35099   voronoi.extent = function(_) {
35100     return arguments.length ? (extent = _ == null ? null : [[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]], voronoi) : extent && [[extent[0][0], extent[0][1]], [extent[1][0], extent[1][1]]];
35101   };
35102
35103   voronoi.size = function(_) {
35104     return arguments.length ? (extent = _ == null ? null : [[0, 0], [+_[0], +_[1]]], voronoi) : extent && [extent[1][0] - extent[0][0], extent[1][1] - extent[0][1]];
35105   };
35106
35107   return voronoi;
35108 };
35109
35110 var constant$12 = function(x) {
35111   return function() {
35112     return x;
35113   };
35114 };
35115
35116 function ZoomEvent(target, type, transform) {
35117   this.target = target;
35118   this.type = type;
35119   this.transform = transform;
35120 }
35121
35122 function Transform(k, x, y) {
35123   this.k = k;
35124   this.x = x;
35125   this.y = y;
35126 }
35127
35128 Transform.prototype = {
35129   constructor: Transform,
35130   scale: function(k) {
35131     return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
35132   },
35133   translate: function(x, y) {
35134     return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
35135   },
35136   apply: function(point) {
35137     return [point[0] * this.k + this.x, point[1] * this.k + this.y];
35138   },
35139   applyX: function(x) {
35140     return x * this.k + this.x;
35141   },
35142   applyY: function(y) {
35143     return y * this.k + this.y;
35144   },
35145   invert: function(location) {
35146     return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
35147   },
35148   invertX: function(x) {
35149     return (x - this.x) / this.k;
35150   },
35151   invertY: function(y) {
35152     return (y - this.y) / this.k;
35153   },
35154   rescaleX: function(x) {
35155     return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
35156   },
35157   rescaleY: function(y) {
35158     return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
35159   },
35160   toString: function() {
35161     return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
35162   }
35163 };
35164
35165 var identity$8 = new Transform(1, 0, 0);
35166
35167 transform$1.prototype = Transform.prototype;
35168
35169 function transform$1(node) {
35170   return node.__zoom || identity$8;
35171 }
35172
35173 function nopropagation$2() {
35174   event.stopImmediatePropagation();
35175 }
35176
35177 var noevent$2 = function() {
35178   event.preventDefault();
35179   event.stopImmediatePropagation();
35180 };
35181
35182 // Ignore right-click, since that should open the context menu.
35183 function defaultFilter$2() {
35184   return !event.button;
35185 }
35186
35187 function defaultExtent$1() {
35188   var e = this, w, h;
35189   if (e instanceof SVGElement) {
35190     e = e.ownerSVGElement || e;
35191     w = e.width.baseVal.value;
35192     h = e.height.baseVal.value;
35193   } else {
35194     w = e.clientWidth;
35195     h = e.clientHeight;
35196   }
35197   return [[0, 0], [w, h]];
35198 }
35199
35200 function defaultTransform() {
35201   return this.__zoom || identity$8;
35202 }
35203
35204 var zoom = function() {
35205   var filter = defaultFilter$2,
35206       extent = defaultExtent$1,
35207       k0 = 0,
35208       k1 = Infinity,
35209       x0 = -k1,
35210       x1 = k1,
35211       y0 = x0,
35212       y1 = x1,
35213       duration = 250,
35214       interpolate$$1 = interpolateZoom,
35215       gestures = [],
35216       listeners = dispatch("start", "zoom", "end"),
35217       touchstarting,
35218       touchending,
35219       touchDelay = 500,
35220       wheelDelay = 150;
35221
35222   function zoom(selection$$1) {
35223     selection$$1
35224         .on("wheel.zoom", wheeled)
35225         .on("mousedown.zoom", mousedowned)
35226         .on("dblclick.zoom", dblclicked)
35227         .on("touchstart.zoom", touchstarted)
35228         .on("touchmove.zoom", touchmoved)
35229         .on("touchend.zoom touchcancel.zoom", touchended)
35230         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
35231         .property("__zoom", defaultTransform);
35232   }
35233
35234   zoom.transform = function(collection, transform) {
35235     var selection$$1 = collection.selection ? collection.selection() : collection;
35236     selection$$1.property("__zoom", defaultTransform);
35237     if (collection !== selection$$1) {
35238       schedule(collection, transform);
35239     } else {
35240       selection$$1.interrupt().each(function() {
35241         gesture(this, arguments)
35242             .start()
35243             .zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform)
35244             .end();
35245       });
35246     }
35247   };
35248
35249   zoom.scaleBy = function(selection$$1, k) {
35250     zoom.scaleTo(selection$$1, function() {
35251       var k0 = this.__zoom.k,
35252           k1 = typeof k === "function" ? k.apply(this, arguments) : k;
35253       return k0 * k1;
35254     });
35255   };
35256
35257   zoom.scaleTo = function(selection$$1, k) {
35258     zoom.transform(selection$$1, function() {
35259       var e = extent.apply(this, arguments),
35260           t0 = this.__zoom,
35261           p0 = centroid(e),
35262           p1 = t0.invert(p0),
35263           k1 = typeof k === "function" ? k.apply(this, arguments) : k;
35264       return constrain(translate(scale(t0, k1), p0, p1), e);
35265     });
35266   };
35267
35268   zoom.translateBy = function(selection$$1, x, y) {
35269     zoom.transform(selection$$1, function() {
35270       return constrain(this.__zoom.translate(
35271         typeof x === "function" ? x.apply(this, arguments) : x,
35272         typeof y === "function" ? y.apply(this, arguments) : y
35273       ), extent.apply(this, arguments));
35274     });
35275   };
35276
35277   function scale(transform, k) {
35278     k = Math.max(k0, Math.min(k1, k));
35279     return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
35280   }
35281
35282   function translate(transform, p0, p1) {
35283     var x = p0[0] - p1[0] * transform.k, y = p0[1] - p1[1] * transform.k;
35284     return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
35285   }
35286
35287   function constrain(transform, extent) {
35288     var dx0 = transform.invertX(extent[0][0]) - x0,
35289         dx1 = transform.invertX(extent[1][0]) - x1,
35290         dy0 = transform.invertY(extent[0][1]) - y0,
35291         dy1 = transform.invertY(extent[1][1]) - y1;
35292     return transform.translate(
35293       dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1),
35294       dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1)
35295     );
35296   }
35297
35298   function centroid(extent) {
35299     return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
35300   }
35301
35302   function schedule(transition$$1, transform, center) {
35303     transition$$1
35304         .on("start.zoom", function() { gesture(this, arguments).start(); })
35305         .on("interrupt.zoom end.zoom", function() { gesture(this, arguments).end(); })
35306         .tween("zoom", function() {
35307           var that = this,
35308               args = arguments,
35309               g = gesture(that, args),
35310               e = extent.apply(that, args),
35311               p = center || centroid(e),
35312               w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
35313               a = that.__zoom,
35314               b = typeof transform === "function" ? transform.apply(that, args) : transform,
35315               i = interpolate$$1(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
35316           return function(t) {
35317             if (t === 1) t = b; // Avoid rounding error on end.
35318             else { var l = i(t), k = w / l[2]; t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k); }
35319             g.zoom(null, t);
35320           };
35321         });
35322   }
35323
35324   function gesture(that, args) {
35325     for (var i = 0, n = gestures.length, g; i < n; ++i) {
35326       if ((g = gestures[i]).that === that) {
35327         return g;
35328       }
35329     }
35330     return new Gesture(that, args);
35331   }
35332
35333   function Gesture(that, args) {
35334     this.that = that;
35335     this.args = args;
35336     this.index = -1;
35337     this.active = 0;
35338     this.extent = extent.apply(that, args);
35339   }
35340
35341   Gesture.prototype = {
35342     start: function() {
35343       if (++this.active === 1) {
35344         this.index = gestures.push(this) - 1;
35345         this.emit("start");
35346       }
35347       return this;
35348     },
35349     zoom: function(key, transform) {
35350       if (this.mouse && key !== "mouse") this.mouse[1] = transform.invert(this.mouse[0]);
35351       if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]);
35352       if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]);
35353       this.that.__zoom = transform;
35354       this.emit("zoom");
35355       return this;
35356     },
35357     end: function() {
35358       if (--this.active === 0) {
35359         gestures.splice(this.index, 1);
35360         this.index = -1;
35361         this.emit("end");
35362       }
35363       return this;
35364     },
35365     emit: function(type) {
35366       customEvent(new ZoomEvent(zoom, type, this.that.__zoom), listeners.apply, listeners, [type, this.that, this.args]);
35367     }
35368   };
35369
35370   function wheeled() {
35371     if (!filter.apply(this, arguments)) return;
35372     var g = gesture(this, arguments),
35373         t = this.__zoom,
35374         k = Math.max(k0, Math.min(k1, t.k * Math.pow(2, -event.deltaY * (event.deltaMode ? 120 : 1) / 500))),
35375         p = mouse(this);
35376
35377     // If the mouse is in the same location as before, reuse it.
35378     // If there were recent wheel events, reset the wheel idle timeout.
35379     if (g.wheel) {
35380       if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
35381         g.mouse[1] = t.invert(g.mouse[0] = p);
35382       }
35383       clearTimeout(g.wheel);
35384     }
35385
35386     // If this wheel event won’t trigger a transform change, ignore it.
35387     else if (t.k === k) return;
35388
35389     // Otherwise, capture the mouse point and location at the start.
35390     else {
35391       g.mouse = [p, t.invert(p)];
35392       interrupt(this);
35393       g.start();
35394     }
35395
35396     noevent$2();
35397     g.wheel = setTimeout(wheelidled, wheelDelay);
35398     g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent));
35399
35400     function wheelidled() {
35401       g.wheel = null;
35402       g.end();
35403     }
35404   }
35405
35406   function mousedowned() {
35407     if (touchending || !filter.apply(this, arguments)) return;
35408     var g = gesture(this, arguments),
35409         v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
35410         p = mouse(this);
35411
35412     dragDisable(event.view);
35413     nopropagation$2();
35414     g.mouse = [p, this.__zoom.invert(p)];
35415     interrupt(this);
35416     g.start();
35417
35418     function mousemoved() {
35419       noevent$2();
35420       g.moved = true;
35421       g.zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = mouse(g.that), g.mouse[1]), g.extent));
35422     }
35423
35424     function mouseupped() {
35425       v.on("mousemove.zoom mouseup.zoom", null);
35426       yesdrag(event.view, g.moved);
35427       noevent$2();
35428       g.end();
35429     }
35430   }
35431
35432   function dblclicked() {
35433     if (!filter.apply(this, arguments)) return;
35434     var t0 = this.__zoom,
35435         p0 = mouse(this),
35436         p1 = t0.invert(p0),
35437         k1 = t0.k * (event.shiftKey ? 0.5 : 2),
35438         t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, arguments));
35439
35440     noevent$2();
35441     if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0);
35442     else select(this).call(zoom.transform, t1);
35443   }
35444
35445   function touchstarted() {
35446     if (!filter.apply(this, arguments)) return;
35447     var g = gesture(this, arguments),
35448         touches$$1 = event.changedTouches,
35449         started,
35450         n = touches$$1.length, i, t, p;
35451
35452     nopropagation$2();
35453     for (i = 0; i < n; ++i) {
35454       t = touches$$1[i], p = touch(this, touches$$1, t.identifier);
35455       p = [p, this.__zoom.invert(p), t.identifier];
35456       if (!g.touch0) g.touch0 = p, started = true;
35457       else if (!g.touch1) g.touch1 = p;
35458     }
35459
35460     // If this is a dbltap, reroute to the (optional) dblclick.zoom handler.
35461     if (touchstarting) {
35462       touchstarting = clearTimeout(touchstarting);
35463       if (!g.touch1) {
35464         g.end();
35465         p = select(this).on("dblclick.zoom");
35466         if (p) p.apply(this, arguments);
35467         return;
35468       }
35469     }
35470
35471     if (started) {
35472       touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay);
35473       interrupt(this);
35474       g.start();
35475     }
35476   }
35477
35478   function touchmoved() {
35479     var g = gesture(this, arguments),
35480         touches$$1 = event.changedTouches,
35481         n = touches$$1.length, i, t, p, l;
35482
35483     noevent$2();
35484     if (touchstarting) touchstarting = clearTimeout(touchstarting);
35485     for (i = 0; i < n; ++i) {
35486       t = touches$$1[i], p = touch(this, touches$$1, t.identifier);
35487       if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p;
35488       else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p;
35489     }
35490     t = g.that.__zoom;
35491     if (g.touch1) {
35492       var p0 = g.touch0[0], l0 = g.touch0[1],
35493           p1 = g.touch1[0], l1 = g.touch1[1],
35494           dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
35495           dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
35496       t = scale(t, Math.sqrt(dp / dl));
35497       p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
35498       l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
35499     }
35500     else if (g.touch0) p = g.touch0[0], l = g.touch0[1];
35501     else return;
35502     g.zoom("touch", constrain(translate(t, p, l), g.extent));
35503   }
35504
35505   function touchended() {
35506     var g = gesture(this, arguments),
35507         touches$$1 = event.changedTouches,
35508         n = touches$$1.length, i, t;
35509
35510     nopropagation$2();
35511     if (touchending) clearTimeout(touchending);
35512     touchending = setTimeout(function() { touchending = null; }, touchDelay);
35513     for (i = 0; i < n; ++i) {
35514       t = touches$$1[i];
35515       if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;
35516       else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
35517     }
35518     if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
35519     if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);
35520     else g.end();
35521   }
35522
35523   zoom.filter = function(_) {
35524     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$12(!!_), zoom) : filter;
35525   };
35526
35527   zoom.extent = function(_) {
35528     return arguments.length ? (extent = typeof _ === "function" ? _ : constant$12([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
35529   };
35530
35531   zoom.scaleExtent = function(_) {
35532     return arguments.length ? (k0 = +_[0], k1 = +_[1], zoom) : [k0, k1];
35533   };
35534
35535   zoom.translateExtent = function(_) {
35536     return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], zoom) : [[x0, y0], [x1, y1]];
35537   };
35538
35539   zoom.duration = function(_) {
35540     return arguments.length ? (duration = +_, zoom) : duration;
35541   };
35542
35543   zoom.interpolate = function(_) {
35544     return arguments.length ? (interpolate$$1 = _, zoom) : interpolate$$1;
35545   };
35546
35547   zoom.on = function() {
35548     var value = listeners.on.apply(listeners, arguments);
35549     return value === listeners ? zoom : value;
35550   };
35551
35552   return zoom;
35553 };
35554
35555
35556
35557 var index$2 = Object.freeze({
35558         version: version,
35559         bisect: bisectRight,
35560         bisectRight: bisectRight,
35561         bisectLeft: bisectLeft,
35562         ascending: ascending,
35563         bisector: bisector,
35564         cross: cross,
35565         descending: descending,
35566         deviation: deviation,
35567         extent: extent,
35568         histogram: histogram,
35569         thresholdFreedmanDiaconis: freedmanDiaconis,
35570         thresholdScott: scott,
35571         thresholdSturges: sturges,
35572         max: max,
35573         mean: mean,
35574         median: median,
35575         merge: merge,
35576         min: min,
35577         pairs: pairs,
35578         permute: permute,
35579         quantile: threshold,
35580         range: sequence,
35581         scan: scan,
35582         shuffle: shuffle,
35583         sum: sum,
35584         ticks: ticks,
35585         tickIncrement: tickIncrement,
35586         tickStep: tickStep,
35587         transpose: transpose,
35588         variance: variance,
35589         zip: zip,
35590         axisTop: axisTop,
35591         axisRight: axisRight,
35592         axisBottom: axisBottom,
35593         axisLeft: axisLeft,
35594         brush: brush,
35595         brushX: brushX,
35596         brushY: brushY,
35597         brushSelection: brushSelection,
35598         chord: chord,
35599         ribbon: ribbon,
35600         nest: nest,
35601         set: set$2,
35602         map: map$1,
35603         keys: keys,
35604         values: values,
35605         entries: entries,
35606         color: color,
35607         rgb: rgb,
35608         hsl: hsl,
35609         lab: lab,
35610         hcl: hcl,
35611         cubehelix: cubehelix,
35612         dispatch: dispatch,
35613         drag: drag,
35614         dragDisable: dragDisable,
35615         dragEnable: yesdrag,
35616         dsvFormat: dsv,
35617         csvParse: csvParse,
35618         csvParseRows: csvParseRows,
35619         csvFormat: csvFormat,
35620         csvFormatRows: csvFormatRows,
35621         tsvParse: tsvParse,
35622         tsvParseRows: tsvParseRows,
35623         tsvFormat: tsvFormat,
35624         tsvFormatRows: tsvFormatRows,
35625         easeLinear: linear$1,
35626         easeQuad: quadInOut,
35627         easeQuadIn: quadIn,
35628         easeQuadOut: quadOut,
35629         easeQuadInOut: quadInOut,
35630         easeCubic: cubicInOut,
35631         easeCubicIn: cubicIn,
35632         easeCubicOut: cubicOut,
35633         easeCubicInOut: cubicInOut,
35634         easePoly: polyInOut,
35635         easePolyIn: polyIn,
35636         easePolyOut: polyOut,
35637         easePolyInOut: polyInOut,
35638         easeSin: sinInOut,
35639         easeSinIn: sinIn,
35640         easeSinOut: sinOut,
35641         easeSinInOut: sinInOut,
35642         easeExp: expInOut,
35643         easeExpIn: expIn,
35644         easeExpOut: expOut,
35645         easeExpInOut: expInOut,
35646         easeCircle: circleInOut,
35647         easeCircleIn: circleIn,
35648         easeCircleOut: circleOut,
35649         easeCircleInOut: circleInOut,
35650         easeBounce: bounceOut,
35651         easeBounceIn: bounceIn,
35652         easeBounceOut: bounceOut,
35653         easeBounceInOut: bounceInOut,
35654         easeBack: backInOut,
35655         easeBackIn: backIn,
35656         easeBackOut: backOut,
35657         easeBackInOut: backInOut,
35658         easeElastic: elasticOut,
35659         easeElasticIn: elasticIn,
35660         easeElasticOut: elasticOut,
35661         easeElasticInOut: elasticInOut,
35662         forceCenter: center$1,
35663         forceCollide: collide,
35664         forceLink: link,
35665         forceManyBody: manyBody,
35666         forceSimulation: simulation,
35667         forceX: x$2,
35668         forceY: y$2,
35669         formatDefaultLocale: defaultLocale,
35670         get format () { return format; },
35671         get formatPrefix () { return formatPrefix; },
35672         formatLocale: formatLocale,
35673         formatSpecifier: formatSpecifier,
35674         precisionFixed: precisionFixed,
35675         precisionPrefix: precisionPrefix,
35676         precisionRound: precisionRound,
35677         geoArea: area,
35678         geoBounds: bounds,
35679         geoCentroid: d3GeoCentroid,
35680         geoCircle: circle,
35681         geoClipExtent: extent$1,
35682         geoContains: contains,
35683         geoDistance: distance,
35684         geoGraticule: graticule,
35685         geoGraticule10: graticule10,
35686         geoInterpolate: interpolate$1,
35687         geoLength: d3GeoLength,
35688         geoPath: index$4,
35689         geoAlbers: albers,
35690         geoAlbersUsa: albersUsa,
35691         geoAzimuthalEqualArea: azimuthalEqualArea,
35692         geoAzimuthalEqualAreaRaw: azimuthalEqualAreaRaw,
35693         geoAzimuthalEquidistant: azimuthalEquidistant,
35694         geoAzimuthalEquidistantRaw: azimuthalEquidistantRaw,
35695         geoConicConformal: conicConformal,
35696         geoConicConformalRaw: conicConformalRaw,
35697         geoConicEqualArea: conicEqualArea,
35698         geoConicEqualAreaRaw: conicEqualAreaRaw,
35699         geoConicEquidistant: conicEquidistant,
35700         geoConicEquidistantRaw: conicEquidistantRaw,
35701         geoEquirectangular: equirectangular,
35702         geoEquirectangularRaw: equirectangularRaw,
35703         geoGnomonic: gnomonic,
35704         geoGnomonicRaw: gnomonicRaw,
35705         geoIdentity: identity$5,
35706         geoProjection: projection,
35707         geoProjectionMutator: projectionMutator,
35708         geoMercator: mercator,
35709         geoMercatorRaw: mercatorRaw,
35710         geoOrthographic: orthographic,
35711         geoOrthographicRaw: orthographicRaw,
35712         geoStereographic: stereographic,
35713         geoStereographicRaw: stereographicRaw,
35714         geoTransverseMercator: transverseMercator,
35715         geoTransverseMercatorRaw: transverseMercatorRaw,
35716         geoRotation: rotation,
35717         geoStream: geoStream,
35718         geoTransform: transform,
35719         cluster: cluster,
35720         hierarchy: hierarchy,
35721         pack: index$5,
35722         packSiblings: siblings,
35723         packEnclose: enclose,
35724         partition: partition,
35725         stratify: stratify,
35726         tree: tree,
35727         treemap: index$6,
35728         treemapBinary: binary,
35729         treemapDice: treemapDice,
35730         treemapSlice: treemapSlice,
35731         treemapSliceDice: sliceDice,
35732         treemapSquarify: squarify,
35733         treemapResquarify: resquarify,
35734         interpolate: interpolateValue,
35735         interpolateArray: array$1,
35736         interpolateBasis: basis$1,
35737         interpolateBasisClosed: basisClosed,
35738         interpolateDate: date,
35739         interpolateNumber: reinterpolate,
35740         interpolateObject: object,
35741         interpolateRound: interpolateRound,
35742         interpolateString: interpolateString,
35743         interpolateTransformCss: interpolateTransformCss,
35744         interpolateTransformSvg: interpolateTransformSvg,
35745         interpolateZoom: interpolateZoom,
35746         interpolateRgb: interpolateRgb,
35747         interpolateRgbBasis: rgbBasis,
35748         interpolateRgbBasisClosed: rgbBasisClosed,
35749         interpolateHsl: hsl$2,
35750         interpolateHslLong: hslLong,
35751         interpolateLab: lab$1,
35752         interpolateHcl: hcl$2,
35753         interpolateHclLong: hclLong,
35754         interpolateCubehelix: cubehelix$2,
35755         interpolateCubehelixLong: cubehelixLong,
35756         quantize: quantize,
35757         path: path,
35758         polygonArea: d3polygonArea,
35759         polygonCentroid: d3polygonCentroid,
35760         polygonHull: d3polygonHull,
35761         polygonContains: contains$1,
35762         polygonLength: length$1,
35763         quadtree: quadtree,
35764         queue: queue,
35765         randomUniform: uniform,
35766         randomNormal: normal,
35767         randomLogNormal: logNormal,
35768         randomBates: bates,
35769         randomIrwinHall: irwinHall,
35770         randomExponential: exponential$1,
35771         request: request,
35772         html: html,
35773         json: json,
35774         text: text,
35775         xml: xml,
35776         csv: csv$1,
35777         tsv: tsv$1,
35778         scaleBand: band,
35779         scalePoint: point$1,
35780         scaleIdentity: identity$6,
35781         scaleLinear: linear$2,
35782         scaleLog: log$1,
35783         scaleOrdinal: ordinal,
35784         scaleImplicit: implicit,
35785         scalePow: pow$1,
35786         scaleSqrt: sqrt$1,
35787         scaleQuantile: quantile$$1,
35788         scaleQuantize: quantize$1,
35789         scaleThreshold: threshold$1,
35790         scaleTime: time,
35791         scaleUtc: utcTime,
35792         schemeCategory10: category10,
35793         schemeCategory20b: category20b,
35794         schemeCategory20c: category20c,
35795         schemeCategory20: category20,
35796         interpolateCubehelixDefault: cubehelix$3,
35797         interpolateRainbow: rainbow$1,
35798         interpolateWarm: warm,
35799         interpolateCool: cool,
35800         interpolateViridis: viridis,
35801         interpolateMagma: magma,
35802         interpolateInferno: inferno,
35803         interpolatePlasma: plasma,
35804         scaleSequential: sequential,
35805         creator: creator,
35806         local: local$1,
35807         matcher: matcher$1,
35808         mouse: mouse,
35809         namespace: namespace,
35810         namespaces: namespaces,
35811         select: select,
35812         selectAll: selectAll,
35813         selection: selection,
35814         selector: selector,
35815         selectorAll: selectorAll,
35816         touch: touch,
35817         touches: touches,
35818         window: window$1,
35819         get event () { return event; },
35820         customEvent: customEvent,
35821         arc: arc,
35822         area: area$1,
35823         line: line,
35824         pie: pie,
35825         radialArea: radialArea,
35826         radialLine: radialLine$1,
35827         symbol: symbol,
35828         symbols: symbols,
35829         symbolCircle: circle$2,
35830         symbolCross: cross$2,
35831         symbolDiamond: diamond,
35832         symbolSquare: square,
35833         symbolStar: star,
35834         symbolTriangle: triangle,
35835         symbolWye: wye,
35836         curveBasisClosed: basisClosed$1,
35837         curveBasisOpen: basisOpen,
35838         curveBasis: basis$2,
35839         curveBundle: bundle,
35840         curveCardinalClosed: cardinalClosed,
35841         curveCardinalOpen: cardinalOpen,
35842         curveCardinal: cardinal,
35843         curveCatmullRomClosed: catmullRomClosed,
35844         curveCatmullRomOpen: catmullRomOpen,
35845         curveCatmullRom: catmullRom,
35846         curveLinearClosed: linearClosed,
35847         curveLinear: curveLinear,
35848         curveMonotoneX: monotoneX,
35849         curveMonotoneY: monotoneY,
35850         curveNatural: natural,
35851         curveStep: step,
35852         curveStepAfter: stepAfter,
35853         curveStepBefore: stepBefore,
35854         stack: stack,
35855         stackOffsetExpand: expand,
35856         stackOffsetNone: none$1,
35857         stackOffsetSilhouette: silhouette,
35858         stackOffsetWiggle: wiggle,
35859         stackOrderAscending: ascending$2,
35860         stackOrderDescending: descending$2,
35861         stackOrderInsideOut: insideOut,
35862         stackOrderNone: none$2,
35863         stackOrderReverse: reverse,
35864         timeInterval: newInterval,
35865         timeMillisecond: millisecond,
35866         timeMilliseconds: milliseconds,
35867         utcMillisecond: millisecond,
35868         utcMilliseconds: milliseconds,
35869         timeSecond: second,
35870         timeSeconds: seconds,
35871         utcSecond: second,
35872         utcSeconds: seconds,
35873         timeMinute: minute,
35874         timeMinutes: minutes,
35875         timeHour: hour,
35876         timeHours: hours,
35877         timeDay: day,
35878         timeDays: days,
35879         timeWeek: sunday,
35880         timeWeeks: sundays,
35881         timeSunday: sunday,
35882         timeSundays: sundays,
35883         timeMonday: monday,
35884         timeMondays: mondays,
35885         timeTuesday: tuesday,
35886         timeTuesdays: tuesdays,
35887         timeWednesday: wednesday,
35888         timeWednesdays: wednesdays,
35889         timeThursday: thursday,
35890         timeThursdays: thursdays,
35891         timeFriday: friday,
35892         timeFridays: fridays,
35893         timeSaturday: saturday,
35894         timeSaturdays: saturdays,
35895         timeMonth: month,
35896         timeMonths: months,
35897         timeYear: year,
35898         timeYears: years,
35899         utcMinute: utcMinute,
35900         utcMinutes: utcMinutes,
35901         utcHour: utcHour,
35902         utcHours: utcHours,
35903         utcDay: utcDay,
35904         utcDays: utcDays,
35905         utcWeek: utcSunday,
35906         utcWeeks: utcSundays,
35907         utcSunday: utcSunday,
35908         utcSundays: utcSundays,
35909         utcMonday: utcMonday,
35910         utcMondays: utcMondays,
35911         utcTuesday: utcTuesday,
35912         utcTuesdays: utcTuesdays,
35913         utcWednesday: utcWednesday,
35914         utcWednesdays: utcWednesdays,
35915         utcThursday: utcThursday,
35916         utcThursdays: utcThursdays,
35917         utcFriday: utcFriday,
35918         utcFridays: utcFridays,
35919         utcSaturday: utcSaturday,
35920         utcSaturdays: utcSaturdays,
35921         utcMonth: utcMonth,
35922         utcMonths: utcMonths,
35923         utcYear: utcYear,
35924         utcYears: utcYears,
35925         timeFormatDefaultLocale: defaultLocale$1,
35926         get timeFormat () { return timeFormat; },
35927         get timeParse () { return timeParse; },
35928         get utcFormat () { return utcFormat; },
35929         get utcParse () { return utcParse; },
35930         timeFormatLocale: formatLocale$1,
35931         isoFormat: formatIso,
35932         isoParse: parseIso,
35933         now: now,
35934         timer: timer,
35935         timerFlush: timerFlush,
35936         timeout: timeout$1,
35937         interval: interval$1,
35938         transition: transition,
35939         active: active,
35940         interrupt: interrupt,
35941         voronoi: voronoi,
35942         zoom: zoom,
35943         zoomTransform: transform$1,
35944         zoomIdentity: identity$8
35945 });
35946
35947 /*
35948     Bypasses features of D3's default projection stream pipeline that are unnecessary:
35949     * Antimeridian clipping
35950     * Spherical rotation
35951     * Resampling
35952 */
35953 function geoRawMercator() {
35954     var project = mercatorRaw,
35955         k = 512 / Math.PI, // scale
35956         x = 0, y = 0, // translate
35957         clipExtent = [[0, 0], [0, 0]];
35958
35959
35960     function projection(point) {
35961         point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
35962         return [point[0] * k + x, y - point[1] * k];
35963     }
35964
35965
35966     projection.invert = function(point) {
35967         point = project.invert((point[0] - x) / k, (y - point[1]) / k);
35968         return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
35969     };
35970
35971
35972     projection.scale = function(_) {
35973         if (!arguments.length) return k;
35974         k = +_;
35975         return projection;
35976     };
35977
35978
35979     projection.translate = function(_) {
35980         if (!arguments.length) return [x, y];
35981         x = +_[0];
35982         y = +_[1];
35983         return projection;
35984     };
35985
35986
35987     projection.clipExtent = function(_) {
35988         if (!arguments.length) return clipExtent;
35989         clipExtent = _;
35990         return projection;
35991     };
35992
35993
35994     projection.transform = function(_) {
35995         if (!arguments.length) return identity$8.translate(x, y).scale(k);
35996         x = +_.x;
35997         y = +_.y;
35998         k = +_.k;
35999         return projection;
36000     };
36001
36002
36003     projection.stream = transform({
36004         point: function(x, y) {
36005             x = projection([x, y]);
36006             this.stream.point(x[0], x[1]);
36007         }
36008     }).stream;
36009
36010
36011     return projection;
36012 }
36013
36014 function osmChangeset() {
36015     if (!(this instanceof osmChangeset)) {
36016         return (new osmChangeset()).initialize(arguments);
36017     } else if (arguments.length) {
36018         this.initialize(arguments);
36019     }
36020 }
36021
36022
36023 osmEntity$$1.changeset = osmChangeset;
36024
36025 osmChangeset.prototype = Object.create(osmEntity$$1.prototype);
36026
36027 lodash.extend(osmChangeset.prototype, {
36028
36029     type: 'changeset',
36030
36031
36032     extent: function() {
36033         return new geoExtent$$1();
36034     },
36035
36036
36037     geometry: function() {
36038         return 'changeset';
36039     },
36040
36041
36042     asJXON: function() {
36043         return {
36044             osm: {
36045                 changeset: {
36046                     tag: lodash.map(this.tags, function(value, key) {
36047                         return { '@k': key, '@v': value };
36048                     }),
36049                     '@version': 0.6,
36050                     '@generator': 'iD'
36051                 }
36052             }
36053         };
36054     },
36055
36056
36057     // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
36058     // XML. Returns a string.
36059     osmChangeJXON: function(changes) {
36060         var changeset_id = this.id;
36061
36062         function nest(x, order) {
36063             var groups = {};
36064             for (var i = 0; i < x.length; i++) {
36065                 var tagName = Object.keys(x[i])[0];
36066                 if (!groups[tagName]) groups[tagName] = [];
36067                 groups[tagName].push(x[i][tagName]);
36068             }
36069             var ordered = {};
36070             order.forEach(function(o) {
36071                 if (groups[o]) ordered[o] = groups[o];
36072             });
36073             return ordered;
36074         }
36075
36076
36077         // sort relations in a changeset by dependencies
36078         function sort(changes) {
36079
36080             // find a referenced relation in the current changeset
36081             function resolve(item) {
36082                 return lodash.find(relations, function(relation) {
36083                     return item.keyAttributes.type === 'relation'
36084                         && item.keyAttributes.ref === relation['@id'];
36085                 });
36086             }
36087
36088             // a new item is an item that has not been already processed
36089             function isNew(item) {
36090                 return !sorted[ item['@id'] ] && !lodash.find(processing, function(proc) {
36091                     return proc['@id'] === item['@id'];
36092                 });
36093             }
36094
36095             var processing = [],
36096                 sorted = {},
36097                 relations = changes.relation;
36098
36099             if (!relations) return changes;
36100
36101             for (var i = 0; i < relations.length; i++) {
36102                 var relation = relations[i];
36103
36104                 // skip relation if already sorted
36105                 if (!sorted[relation['@id']]) {
36106                     processing.push(relation);
36107                 }
36108
36109                 while (processing.length > 0) {
36110                     var next = processing[0],
36111                     deps = lodash.filter(lodash.compact(next.member.map(resolve)), isNew);
36112                     if (deps.length === 0) {
36113                         sorted[next['@id']] = next;
36114                         processing.shift();
36115                     } else {
36116                         processing = deps.concat(processing);
36117                     }
36118                 }
36119             }
36120
36121             changes.relation = lodash.values(sorted);
36122             return changes;
36123         }
36124
36125         function rep(entity) {
36126             return entity.asJXON(changeset_id);
36127         }
36128
36129         return {
36130             osmChange: {
36131                 '@version': 0.6,
36132                 '@generator': 'iD',
36133                 'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
36134                 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
36135                 'delete': lodash.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), { '@if-unused': true })
36136             }
36137         };
36138     },
36139
36140
36141     asGeoJSON: function() {
36142         return {};
36143     }
36144
36145 });
36146
36147 function osmNode() {
36148     if (!(this instanceof osmNode)) {
36149         return (new osmNode()).initialize(arguments);
36150     } else if (arguments.length) {
36151         this.initialize(arguments);
36152     }
36153 }
36154
36155 osmEntity$$1.node = osmNode;
36156
36157 osmNode.prototype = Object.create(osmEntity$$1.prototype);
36158
36159 lodash.extend(osmNode.prototype, {
36160
36161     type: 'node',
36162
36163
36164     extent: function() {
36165         return new geoExtent$$1(this.loc);
36166     },
36167
36168
36169     geometry: function(graph) {
36170         return graph.transient(this, 'geometry', function() {
36171             return graph.isPoi(this) ? 'point' : 'vertex';
36172         });
36173     },
36174
36175
36176     move: function(loc) {
36177         return this.update({loc: loc});
36178     },
36179
36180
36181     isDegenerate: function() {
36182         return !(
36183             Array.isArray(this.loc) && this.loc.length === 2 &&
36184             this.loc[0] >= -180 && this.loc[0] <= 180 &&
36185             this.loc[1] >= -90 && this.loc[1] <= 90
36186         );
36187     },
36188
36189
36190     isEndpoint: function(resolver) {
36191         return resolver.transient(this, 'isEndpoint', function() {
36192             var id = this.id;
36193             return resolver.parentWays(this).filter(function(parent) {
36194                 return !parent.isClosed() && !!parent.affix(id);
36195             }).length > 0;
36196         });
36197     },
36198
36199
36200     isConnected: function(resolver) {
36201         return resolver.transient(this, 'isConnected', function() {
36202             var parents = resolver.parentWays(this);
36203
36204             function isLine(entity) {
36205                 return entity.geometry(resolver) === 'line' &&
36206                     entity.hasInterestingTags();
36207             }
36208
36209             // vertex is connected to multiple parent lines
36210             if (parents.length > 1 && lodash.some(parents, isLine)) {
36211                 return true;
36212
36213             } else if (parents.length === 1) {
36214                 var way = parents[0],
36215                     nodes = way.nodes.slice();
36216                 if (way.isClosed()) { nodes.pop(); }  // ignore connecting node if closed
36217
36218                 // return true if vertex appears multiple times (way is self intersecting)
36219                 return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
36220             }
36221
36222             return false;
36223         });
36224     },
36225
36226
36227     isIntersection: function(resolver) {
36228         return resolver.transient(this, 'isIntersection', function() {
36229             return resolver.parentWays(this).filter(function(parent) {
36230                 return (parent.tags.highway ||
36231                     parent.tags.waterway ||
36232                     parent.tags.railway ||
36233                     parent.tags.aeroway) &&
36234                     parent.geometry(resolver) === 'line';
36235             }).length > 1;
36236         });
36237     },
36238
36239
36240     isHighwayIntersection: function(resolver) {
36241         return resolver.transient(this, 'isHighwayIntersection', function() {
36242             return resolver.parentWays(this).filter(function(parent) {
36243                 return parent.tags.highway && parent.geometry(resolver) === 'line';
36244             }).length > 1;
36245         });
36246     },
36247
36248
36249     isOnAddressLine: function(resolver) {
36250         return resolver.transient(this, 'isOnAddressLine', function() {
36251             return resolver.parentWays(this).filter(function(parent) {
36252                 return parent.tags.hasOwnProperty('addr:interpolation') &&
36253                     parent.geometry(resolver) === 'line';
36254             }).length > 0;
36255         });
36256     },
36257
36258
36259     asJXON: function(changeset_id) {
36260         var r = {
36261             node: {
36262                 '@id': this.osmId(),
36263                 '@lon': this.loc[0],
36264                 '@lat': this.loc[1],
36265                 '@version': (this.version || 0),
36266                 tag: lodash.map(this.tags, function(v, k) {
36267                     return { keyAttributes: { k: k, v: v } };
36268                 })
36269             }
36270         };
36271         if (changeset_id) r.node['@changeset'] = changeset_id;
36272         return r;
36273     },
36274
36275
36276     asGeoJSON: function() {
36277         return {
36278             type: 'Point',
36279             coordinates: this.loc
36280         };
36281     }
36282 });
36283
36284 /*
36285   Order the nodes of a way in reverse order and reverse any direction dependent tags
36286   other than `oneway`. (We assume that correcting a backwards oneway is the primary
36287   reason for reversing a way.)
36288
36289   The following transforms are performed:
36290
36291     Keys:
36292           *:right=* ⟺ *:left=*
36293         *:forward=* ⟺ *:backward=*
36294        direction=up ⟺ direction=down
36295          incline=up ⟺ incline=down
36296             *=right ⟺ *=left
36297
36298     Relation members:
36299        role=forward ⟺ role=backward
36300          role=north ⟺ role=south
36301           role=east ⟺ role=west
36302
36303    In addition, numeric-valued `incline` tags are negated.
36304
36305    The JOSM implementation was used as a guide, but transformations that were of unclear benefit
36306    or adjusted tags that don't seem to be used in practice were omitted.
36307
36308    Also, each node on the way is examined for its own tags and the following transformations are performed
36309    in order to ensure associated nodes (eg a Stop Sign) is also reversed
36310
36311     Node Keys:
36312         direction=forward ⟺ direction=backward
36313         direction=left ⟺ direction=right
36314         *:forward=* ⟺ *:backward=*
36315         *:left=* ⟺ *:right=*
36316
36317    References:
36318       http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
36319       http://wiki.openstreetmap.org/wiki/Key:direction#Steps
36320       http://wiki.openstreetmap.org/wiki/Key:incline
36321       http://wiki.openstreetmap.org/wiki/Route#Members
36322       http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
36323       http://wiki.openstreetmap.org/wiki/Tag:highway%3Dstop
36324       http://wiki.openstreetmap.org/wiki/Key:traffic_sign#On_a_way_or_area
36325  */
36326 function actionReverse(wayId, options) {
36327     var replacements = [
36328             [/:right$/, ':left'], [/:left$/, ':right'],
36329             [/:forward$/, ':backward'], [/:backward$/, ':forward']
36330         ],
36331         numeric = /^([+\-]?)(?=[\d.])/,
36332         roleReversals = {
36333             forward: 'backward',
36334             backward: 'forward',
36335             north: 'south',
36336             south: 'north',
36337             east: 'west',
36338             west: 'east'
36339         };
36340
36341
36342     function reverseKey(key) {
36343         for (var i = 0; i < replacements.length; ++i) {
36344             var replacement = replacements[i];
36345             if (replacement[0].test(key)) {
36346                 return key.replace(replacement[0], replacement[1]);
36347             }
36348         }
36349         return key;
36350     }
36351
36352
36353     function reverseValue(key, value) {
36354         if (key === 'incline' && numeric.test(value)) {
36355             return value.replace(numeric, function(_, sign) { return sign === '-' ? '' : '-'; });
36356         } else if (key === 'incline' || key === 'direction') {
36357             return {up: 'down', down: 'up'}[value] || value;
36358         } else if (options && options.reverseOneway && key === 'oneway') {
36359             return {yes: '-1', '1': '-1', '-1': 'yes'}[value] || value;
36360         } else {
36361             return {left: 'right', right: 'left'}[value] || value;
36362         }
36363     }
36364
36365
36366     function reverseDirectionTags(node) {
36367         // Update the direction based tags as appropriate then return an updated node
36368         return node.update({tags: lodash.transform(node.tags, function(acc, tagValue, tagKey) {
36369             // See if this is a direction tag and reverse (or use existing value if not recognised)
36370             if (tagKey === 'direction') {
36371                 acc[tagKey] = {forward: 'backward', backward: 'forward', left: 'right', right: 'left'}[tagValue] || tagValue;
36372             } else {
36373                 // Use the reverseKey method to cater for situations such as traffic_sign:forward=stop
36374                 // This will pass through other tags unchanged
36375                 acc[reverseKey(tagKey)] = tagValue;
36376             }
36377             return acc;
36378         }, {})});
36379     }
36380
36381
36382     function reverseTagsOnNodes(graph, nodeIds) {
36383         // Reverse the direction of appropriate tags attached to the nodes (#3076)
36384         return lodash(nodeIds)
36385             // Get each node from the graph
36386             .map(function(nodeId) { return graph.entity(nodeId);})
36387             // Check tags on the node, if there aren't any, we can skip
36388             .filter(function(existingNode) { return existingNode.tags !== undefined;})
36389             // Get a new version of each node with the appropriate tags reversed
36390             .map(function(existingNode) { return reverseDirectionTags(existingNode);})
36391             // Chain together consecutive updates to the graph for each updated node and return
36392             .reduce(function (accGraph, value) { return accGraph.replace(value); }, graph);
36393     }
36394
36395
36396     return function(graph) {
36397         var way = graph.entity(wayId),
36398             nodes = way.nodes.slice().reverse(),
36399             tags = {}, key, role;
36400
36401         for (key in way.tags) {
36402             tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
36403         }
36404
36405         graph.parentRelations(way).forEach(function(relation) {
36406             relation.members.forEach(function(member, index) {
36407                 if (member.id === way.id && (role = roleReversals[member.role])) {
36408                     relation = relation.updateMember({role: role}, index);
36409                     graph = graph.replace(relation);
36410                 }
36411             });
36412         });
36413
36414         // Reverse any associated directions on nodes on the way and then replace
36415         // the way itself with the reversed node ids and updated way tags
36416         return reverseTagsOnNodes(graph, nodes).replace(way.update({nodes: nodes, tags: tags}));
36417     };
36418 }
36419
36420 // For fixing up rendering of multipolygons with tags on the outer member.
36421 // https://github.com/openstreetmap/iD/issues/613
36422 function osmIsSimpleMultipolygonOuterMember(entity, graph) {
36423     if (entity.type !== 'way' || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0)
36424         return false;
36425
36426     var parents = graph.parentRelations(entity);
36427     if (parents.length !== 1)
36428         return false;
36429
36430     var parent = parents[0];
36431     if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1)
36432         return false;
36433
36434     var members = parent.members, member;
36435     for (var i = 0; i < members.length; i++) {
36436         member = members[i];
36437         if (member.id === entity.id && member.role && member.role !== 'outer')
36438             return false; // Not outer member
36439         if (member.id !== entity.id && (!member.role || member.role === 'outer'))
36440             return false; // Not a simple multipolygon
36441     }
36442
36443     return parent;
36444 }
36445
36446
36447 function osmSimpleMultipolygonOuterMember(entity, graph) {
36448     if (entity.type !== 'way')
36449         return false;
36450
36451     var parents = graph.parentRelations(entity);
36452     if (parents.length !== 1)
36453         return false;
36454
36455     var parent = parents[0];
36456     if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1)
36457         return false;
36458
36459     var members = parent.members, member, outerMember;
36460     for (var i = 0; i < members.length; i++) {
36461         member = members[i];
36462         if (!member.role || member.role === 'outer') {
36463             if (outerMember)
36464                 return false; // Not a simple multipolygon
36465             outerMember = member;
36466         }
36467     }
36468
36469     if (!outerMember)
36470         return false;
36471
36472     var outerEntity = graph.hasEntity(outerMember.id);
36473     if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length)
36474         return false;
36475
36476     return outerEntity;
36477 }
36478
36479
36480 // Join `array` into sequences of connecting ways.
36481 //
36482 // Segments which share identical start/end nodes will, as much as possible,
36483 // be connected with each other.
36484 //
36485 // The return value is a nested array. Each constituent array contains elements
36486 // of `array` which have been determined to connect. Each consitituent array
36487 // also has a `nodes` property whose value is an ordered array of member nodes,
36488 // with appropriate order reversal and start/end coordinate de-duplication.
36489 //
36490 // Members of `array` must have, at minimum, `type` and `id` properties.
36491 // Thus either an array of `osmWay`s or a relation member array may be
36492 // used.
36493 //
36494 // If an member has a `tags` property, its tags will be reversed via
36495 // `actionReverse` in the output.
36496 //
36497 // Incomplete members (those for which `graph.hasEntity(element.id)` returns
36498 // false) and non-way members are ignored.
36499 //
36500 function osmJoinWays(array, graph) {
36501     var joined = [], member, current, nodes, first, last, i, how, what;
36502
36503     array = array.filter(function(member) {
36504         return member.type === 'way' && graph.hasEntity(member.id);
36505     });
36506
36507     function resolve(member) {
36508         return graph.childNodes(graph.entity(member.id));
36509     }
36510
36511     function reverse(member) {
36512         return member.tags ? actionReverse(member.id, { reverseOneway: true })(graph).entity(member.id) : member;
36513     }
36514
36515     while (array.length) {
36516         member = array.shift();
36517         current = [member];
36518         current.nodes = nodes = resolve(member).slice();
36519         joined.push(current);
36520
36521         while (array.length && lodash.first(nodes) !== lodash.last(nodes)) {
36522             first = lodash.first(nodes);
36523             last  = lodash.last(nodes);
36524
36525             for (i = 0; i < array.length; i++) {
36526                 member = array[i];
36527                 what = resolve(member);
36528
36529                 if (last === lodash.first(what)) {
36530                     how  = nodes.push;
36531                     what = what.slice(1);
36532                     break;
36533                 } else if (last === lodash.last(what)) {
36534                     how  = nodes.push;
36535                     what = what.slice(0, -1).reverse();
36536                     member = reverse(member);
36537                     break;
36538                 } else if (first === lodash.last(what)) {
36539                     how  = nodes.unshift;
36540                     what = what.slice(0, -1);
36541                     break;
36542                 } else if (first === lodash.first(what)) {
36543                     how  = nodes.unshift;
36544                     what = what.slice(1).reverse();
36545                     member = reverse(member);
36546                     break;
36547                 } else {
36548                     what = how = null;
36549                 }
36550             }
36551
36552             if (!what)
36553                 break; // No more joinable ways.
36554
36555             how.apply(current, [member]);
36556             how.apply(nodes, what);
36557
36558             array.splice(i, 1);
36559         }
36560     }
36561
36562     return joined;
36563 }
36564
36565 function osmRelation() {
36566     if (!(this instanceof osmRelation)) {
36567         return (new osmRelation()).initialize(arguments);
36568     } else if (arguments.length) {
36569         this.initialize(arguments);
36570     }
36571 }
36572
36573
36574 osmEntity$$1.relation = osmRelation;
36575
36576 osmRelation.prototype = Object.create(osmEntity$$1.prototype);
36577
36578
36579 osmRelation.creationOrder = function(a, b) {
36580     var aId = parseInt(osmEntity$$1.id.toOSM(a.id), 10);
36581     var bId = parseInt(osmEntity$$1.id.toOSM(b.id), 10);
36582
36583     if (aId < 0 || bId < 0) return aId - bId;
36584     return bId - aId;
36585 };
36586
36587
36588 lodash.extend(osmRelation.prototype, {
36589     type: 'relation',
36590     members: [],
36591
36592
36593     copy: function(resolver, copies) {
36594         if (copies[this.id])
36595             return copies[this.id];
36596
36597         var copy = osmEntity$$1.prototype.copy.call(this, resolver, copies);
36598
36599         var members = this.members.map(function(member) {
36600             return lodash.extend({}, member, { id: resolver.entity(member.id).copy(resolver, copies).id });
36601         });
36602
36603         copy = copy.update({members: members});
36604         copies[this.id] = copy;
36605
36606         return copy;
36607     },
36608
36609
36610     extent: function(resolver, memo) {
36611         return resolver.transient(this, 'extent', function() {
36612             if (memo && memo[this.id]) return geoExtent$$1();
36613             memo = memo || {};
36614             memo[this.id] = true;
36615
36616             var extent$$1 = geoExtent$$1();
36617             for (var i = 0; i < this.members.length; i++) {
36618                 var member = resolver.hasEntity(this.members[i].id);
36619                 if (member) {
36620                     extent$$1._extend(member.extent(resolver, memo));
36621                 }
36622             }
36623             return extent$$1;
36624         });
36625     },
36626
36627
36628     geometry: function(graph) {
36629         return graph.transient(this, 'geometry', function() {
36630             return this.isMultipolygon() ? 'area' : 'relation';
36631         });
36632     },
36633
36634
36635     isDegenerate: function() {
36636         return this.members.length === 0;
36637     },
36638
36639
36640     // Return an array of members, each extended with an 'index' property whose value
36641     // is the member index.
36642     indexedMembers: function() {
36643         var result = new Array(this.members.length);
36644         for (var i = 0; i < this.members.length; i++) {
36645             result[i] = lodash.extend({}, this.members[i], {index: i});
36646         }
36647         return result;
36648     },
36649
36650
36651     // Return the first member with the given role. A copy of the member object
36652     // is returned, extended with an 'index' property whose value is the member index.
36653     memberByRole: function(role) {
36654         for (var i = 0; i < this.members.length; i++) {
36655             if (this.members[i].role === role) {
36656                 return lodash.extend({}, this.members[i], {index: i});
36657             }
36658         }
36659     },
36660
36661
36662     // Return the first member with the given id. A copy of the member object
36663     // is returned, extended with an 'index' property whose value is the member index.
36664     memberById: function(id) {
36665         for (var i = 0; i < this.members.length; i++) {
36666             if (this.members[i].id === id) {
36667                 return lodash.extend({}, this.members[i], {index: i});
36668             }
36669         }
36670     },
36671
36672
36673     // Return the first member with the given id and role. A copy of the member object
36674     // is returned, extended with an 'index' property whose value is the member index.
36675     memberByIdAndRole: function(id, role) {
36676         for (var i = 0; i < this.members.length; i++) {
36677             if (this.members[i].id === id && this.members[i].role === role) {
36678                 return lodash.extend({}, this.members[i], {index: i});
36679             }
36680         }
36681     },
36682
36683
36684     addMember: function(member, index) {
36685         var members = this.members.slice();
36686         members.splice(index === undefined ? members.length : index, 0, member);
36687         return this.update({members: members});
36688     },
36689
36690
36691     updateMember: function(member, index) {
36692         var members = this.members.slice();
36693         members.splice(index, 1, lodash.extend({}, members[index], member));
36694         return this.update({members: members});
36695     },
36696
36697
36698     removeMember: function(index) {
36699         var members = this.members.slice();
36700         members.splice(index, 1);
36701         return this.update({members: members});
36702     },
36703
36704
36705     removeMembersWithID: function(id) {
36706         var members = lodash.reject(this.members, function(m) { return m.id === id; });
36707         return this.update({members: members});
36708     },
36709
36710
36711     // Wherever a member appears with id `needle.id`, replace it with a member
36712     // with id `replacement.id`, type `replacement.type`, and the original role,
36713     // unless a member already exists with that id and role. Return an updated
36714     // relation.
36715     replaceMember: function(needle, replacement) {
36716         if (!this.memberById(needle.id))
36717             return this;
36718
36719         var members = [];
36720
36721         for (var i = 0; i < this.members.length; i++) {
36722             var member = this.members[i];
36723             if (member.id !== needle.id) {
36724                 members.push(member);
36725             } else if (!this.memberByIdAndRole(replacement.id, member.role)) {
36726                 members.push({id: replacement.id, type: replacement.type, role: member.role});
36727             }
36728         }
36729
36730         return this.update({members: members});
36731     },
36732
36733
36734     asJXON: function(changeset_id) {
36735         var r = {
36736             relation: {
36737                 '@id': this.osmId(),
36738                 '@version': this.version || 0,
36739                 member: lodash.map(this.members, function(member) {
36740                     return {
36741                         keyAttributes: {
36742                             type: member.type,
36743                             role: member.role,
36744                             ref: osmEntity$$1.id.toOSM(member.id)
36745                         }
36746                     };
36747                 }),
36748                 tag: lodash.map(this.tags, function(v, k) {
36749                     return { keyAttributes: { k: k, v: v } };
36750                 })
36751             }
36752         };
36753         if (changeset_id) r.relation['@changeset'] = changeset_id;
36754         return r;
36755     },
36756
36757
36758     asGeoJSON: function(resolver) {
36759         return resolver.transient(this, 'GeoJSON', function () {
36760             if (this.isMultipolygon()) {
36761                 return {
36762                     type: 'MultiPolygon',
36763                     coordinates: this.multipolygon(resolver)
36764                 };
36765             } else {
36766                 return {
36767                     type: 'FeatureCollection',
36768                     properties: this.tags,
36769                     features: this.members.map(function (member) {
36770                         return lodash.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
36771                     })
36772                 };
36773             }
36774         });
36775     },
36776
36777
36778     area: function(resolver) {
36779         return resolver.transient(this, 'area', function() {
36780             return area(this.asGeoJSON(resolver));
36781         });
36782     },
36783
36784
36785     isMultipolygon: function() {
36786         return this.tags.type === 'multipolygon';
36787     },
36788
36789
36790     isComplete: function(resolver) {
36791         for (var i = 0; i < this.members.length; i++) {
36792             if (!resolver.hasEntity(this.members[i].id)) {
36793                 return false;
36794             }
36795         }
36796         return true;
36797     },
36798
36799
36800     isRestriction: function() {
36801         return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
36802     },
36803
36804
36805     // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
36806     // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
36807     //
36808     // This corresponds to the structure needed for rendering a multipolygon path using a
36809     // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
36810     //
36811     // In the case of invalid geometries, this function will still return a result which
36812     // includes the nodes of all way members, but some Nds may be unclosed and some inner
36813     // rings not matched with the intended outer ring.
36814     //
36815     multipolygon: function(resolver) {
36816         var outers = this.members.filter(function(m) { return 'outer' === (m.role || 'outer'); }),
36817             inners = this.members.filter(function(m) { return 'inner' === m.role; });
36818
36819         outers = osmJoinWays(outers, resolver);
36820         inners = osmJoinWays(inners, resolver);
36821
36822         outers = outers.map(function(outer) { return lodash.map(outer.nodes, 'loc'); });
36823         inners = inners.map(function(inner) { return lodash.map(inner.nodes, 'loc'); });
36824
36825         var result = outers.map(function(o) {
36826             // Heuristic for detecting counterclockwise winding order. Assumes
36827             // that OpenStreetMap polygons are not hemisphere-spanning.
36828             return [area({ type: 'Polygon', coordinates: [o] }) > 2 * Math.PI ? o.reverse() : o];
36829         });
36830
36831         function findOuter(inner) {
36832             var o, outer;
36833
36834             for (o = 0; o < outers.length; o++) {
36835                 outer = outers[o];
36836                 if (geoPolygonContainsPolygon(outer, inner))
36837                     return o;
36838             }
36839
36840             for (o = 0; o < outers.length; o++) {
36841                 outer = outers[o];
36842                 if (geoPolygonIntersectsPolygon(outer, inner, false))
36843                     return o;
36844             }
36845         }
36846
36847         for (var i = 0; i < inners.length; i++) {
36848             var inner = inners[i];
36849
36850             if (area({ type: 'Polygon', coordinates: [inner] }) < 2 * Math.PI) {
36851                 inner = inner.reverse();
36852             }
36853
36854             var o = findOuter(inners[i]);
36855             if (o !== undefined)
36856                 result[o].push(inners[i]);
36857             else
36858                 result.push([inners[i]]); // Invalid geometry
36859         }
36860
36861         return result;
36862     }
36863 });
36864
36865 function osmLanes(entity) {
36866     if (entity.type !== 'way') return null;
36867     if (!entity.tags.highway) return null;
36868
36869     var tags = entity.tags;
36870     var isOneWay = entity.isOneWay();
36871     var laneCount = getLaneCount(tags, isOneWay);
36872     var maxspeed = parseMaxspeed(tags);
36873
36874     var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
36875     var forward = laneDirections.forward;
36876     var backward = laneDirections.backward;
36877     var bothways = laneDirections.bothways;
36878
36879     // parse the piped string 'x|y|z' format
36880     var turnLanes = {};
36881     turnLanes.unspecified = parseTurnLanes(tags['turn:lanes']);
36882     turnLanes.forward = parseTurnLanes(tags['turn:lanes:forward']);
36883     turnLanes.backward = parseTurnLanes(tags['turn:lanes:backward']);
36884
36885     var maxspeedLanes = {};
36886     maxspeedLanes.unspecified = parseMaxspeedLanes(tags['maxspeed:lanes'], maxspeed);
36887     maxspeedLanes.forward = parseMaxspeedLanes(tags['maxspeed:lanes:forward'], maxspeed);
36888     maxspeedLanes.backward = parseMaxspeedLanes(tags['maxspeed:lanes:backward'], maxspeed);
36889
36890     var psvLanes = {};
36891     psvLanes.unspecified = parseMiscLanes(tags['psv:lanes']);
36892     psvLanes.forward = parseMiscLanes(tags['psv:lanes:forward']);
36893     psvLanes.backward = parseMiscLanes(tags['psv:lanes:backward']);
36894
36895     var busLanes = {};
36896     busLanes.unspecified = parseMiscLanes(tags['bus:lanes']);
36897     busLanes.forward = parseMiscLanes(tags['bus:lanes:forward']);
36898     busLanes.backward = parseMiscLanes(tags['bus:lanes:backward']);
36899
36900     var taxiLanes = {};
36901     taxiLanes.unspecified = parseMiscLanes(tags['taxi:lanes']);
36902     taxiLanes.forward = parseMiscLanes(tags['taxi:lanes:forward']);
36903     taxiLanes.backward = parseMiscLanes(tags['taxi:lanes:backward']);
36904
36905     var hovLanes = {};
36906     hovLanes.unspecified = parseMiscLanes(tags['hov:lanes']);
36907     hovLanes.forward = parseMiscLanes(tags['hov:lanes:forward']);
36908     hovLanes.backward = parseMiscLanes(tags['hov:lanes:backward']);
36909
36910     var hgvLanes = {};
36911     hgvLanes.unspecified = parseMiscLanes(tags['hgv:lanes']);
36912     hgvLanes.forward = parseMiscLanes(tags['hgv:lanes:forward']);
36913     hgvLanes.backward = parseMiscLanes(tags['hgv:lanes:backward']);
36914
36915     var bicyclewayLanes = {};
36916     bicyclewayLanes.unspecified = parseBicycleWay(tags['bicycleway:lanes']);
36917     bicyclewayLanes.forward = parseBicycleWay(tags['bicycleway:lanes:forward']);
36918     bicyclewayLanes.backward = parseBicycleWay(tags['bicycleway:lanes:backward']);
36919
36920     var lanesObj = {
36921         forward: [],
36922         backward: [],
36923         unspecified: []
36924     };
36925
36926     // map forward/backward/unspecified of each lane type to lanesObj
36927     mapToLanesObj(lanesObj, turnLanes, 'turnLane');
36928     mapToLanesObj(lanesObj, maxspeedLanes, 'maxspeed');
36929     mapToLanesObj(lanesObj, psvLanes, 'psv');
36930     mapToLanesObj(lanesObj, busLanes, 'bus');
36931     mapToLanesObj(lanesObj, taxiLanes, 'taxi');
36932     mapToLanesObj(lanesObj, hovLanes, 'hov');
36933     mapToLanesObj(lanesObj, hgvLanes, 'hgv');
36934     mapToLanesObj(lanesObj, bicyclewayLanes, 'bicycleway');
36935
36936     return {
36937         metadata: {
36938             count: laneCount,
36939             oneway: isOneWay,
36940             forward: forward,
36941             backward: backward,
36942             bothways: bothways,
36943             turnLanes: turnLanes,
36944             maxspeed: maxspeed,
36945             maxspeedLanes: maxspeedLanes,
36946             psvLanes: psvLanes,
36947             busLanes: busLanes,
36948             taxiLanes: taxiLanes,
36949             hovLanes: hovLanes,
36950             hgvLanes: hgvLanes,
36951             bicyclewayLanes: bicyclewayLanes
36952         },
36953         lanes: lanesObj
36954     };
36955 }
36956
36957
36958 function getLaneCount(tags, isOneWay) {
36959     var count;
36960     if (tags.lanes) {
36961         count = parseInt(tags.lanes, 10);
36962         if (count > 0) {
36963             return count;
36964         }
36965     }
36966
36967
36968     switch (tags.highway) {
36969         case 'trunk':
36970         case 'motorway':
36971             count = isOneWay ? 2 : 4;
36972             break;
36973         default:
36974             count = isOneWay ? 1 : 2;
36975             break;
36976     }
36977
36978     return count;
36979 }
36980
36981
36982 function parseMaxspeed(tags) {
36983     var maxspeed = tags.maxspeed;
36984     if (lodash.isNumber(maxspeed)) return maxspeed;
36985     if (lodash.isString(maxspeed)) {
36986         maxspeed = maxspeed.match(/^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/g);
36987         if (!maxspeed) return;
36988         return parseInt(maxspeed, 10);
36989     }
36990 }
36991
36992
36993 function parseLaneDirections(tags, isOneWay, laneCount) {
36994     var forward = parseInt(tags['lanes:forward'], 10);
36995     var backward = parseInt(tags['lanes:backward'], 10);
36996     var bothways = parseInt(tags['lanes:both_ways'], 10) > 0 ? 1 : 0;
36997
36998     if (parseInt(tags.oneway, 10) === -1) {
36999         forward = 0;
37000         bothways = 0;
37001         backward = laneCount;
37002     }
37003     else if (isOneWay) {
37004         forward = laneCount;
37005         bothways = 0;
37006         backward = 0;
37007     }
37008     else if (lodash.isNaN(forward) && lodash.isNaN(backward)) {
37009         backward = Math.floor((laneCount - bothways) / 2);
37010         forward = laneCount - bothways - backward;
37011     }
37012     else if (lodash.isNaN(forward)) {
37013         if (backward > laneCount - bothways) {
37014             backward = laneCount - bothways;
37015         }
37016         forward = laneCount - bothways - backward;
37017     }
37018     else if (lodash.isNaN(backward)) {
37019         if (forward > laneCount - bothways) {
37020             forward = laneCount - bothways;
37021         }
37022         backward = laneCount - bothways - forward;
37023     }
37024     return {
37025         forward: forward,
37026         backward: backward,
37027         bothways: bothways
37028     };
37029 }
37030
37031
37032 function parseTurnLanes(tag){
37033     if (!tag) return;
37034
37035     var validValues = [
37036         'left', 'slight_left', 'sharp_left', 'through', 'right', 'slight_right',
37037         'sharp_right', 'reverse', 'merge_to_left', 'merge_to_right', 'none'
37038     ];
37039
37040     return tag.split('|')
37041         .map(function (s) {
37042             if (s === '') s = 'none';
37043             return s.split(';')
37044                 .map(function (d) {
37045                     return validValues.indexOf(d) === -1 ? 'unknown': d;
37046                 });
37047         });
37048 }
37049
37050
37051 function parseMaxspeedLanes(tag, maxspeed) {
37052     if (!tag) return;
37053
37054     return tag.split('|')
37055         .map(function (s) {
37056             if (s === 'none') return s;
37057             var m = parseInt(s, 10);
37058             if (s === '' || m === maxspeed) return null;
37059             return lodash.isNaN(m) ? 'unknown': m;
37060         });
37061 }
37062
37063
37064 function parseMiscLanes(tag) {
37065     if (!tag) return;
37066
37067     var validValues = [
37068         'yes', 'no', 'designated'
37069     ];
37070
37071     return tag.split('|')
37072         .map(function (s) {
37073             if (s === '') s = 'no';
37074             return validValues.indexOf(s) === -1 ? 'unknown': s;
37075         });
37076 }
37077
37078
37079 function parseBicycleWay(tag) {
37080     if (!tag) return;
37081
37082     var validValues = [
37083         'yes', 'no', 'designated', 'lane'
37084     ];
37085
37086     return tag.split('|')
37087         .map(function (s) {
37088             if (s === '') s = 'no';
37089             return validValues.indexOf(s) === -1 ? 'unknown': s;
37090         });
37091 }
37092
37093
37094 function mapToLanesObj(lanesObj, data, key) {
37095     if (data.forward) data.forward.forEach(function(l, i) {
37096         if (!lanesObj.forward[i]) lanesObj.forward[i] = {};
37097         lanesObj.forward[i][key] = l;
37098     });
37099     if (data.backward) data.backward.forEach(function(l, i) {
37100         if (!lanesObj.backward[i]) lanesObj.backward[i] = {};
37101         lanesObj.backward[i][key] = l;
37102     });
37103     if (data.unspecified) data.unspecified.forEach(function(l, i) {
37104         if (!lanesObj.unspecified[i]) lanesObj.unspecified[i] = {};
37105         lanesObj.unspecified[i][key] = l;
37106     });
37107 }
37108
37109 var translations = Object.create(null);
37110
37111 var currentLocale = 'en';
37112 var textDirection = 'ltr';
37113
37114 function setLocale(_) {
37115     if (translations[_] !== undefined) {
37116         currentLocale = _;
37117     } else if (translations[_.split('-')[0]]) {
37118         currentLocale = _.split('-')[0];
37119     }
37120 }
37121
37122 function addTranslation(id, value) {
37123     translations[id] = value;
37124 }
37125
37126 /**
37127  * Given a string identifier, try to find that string in the current
37128  * language, and return it.
37129  *
37130  * @param {string} s string identifier
37131  * @returns {string?} locale string
37132  */
37133 function t(s, o, loc) {
37134     loc = loc || currentLocale;
37135
37136     var path = s.split('.').reverse();
37137     var rep = translations[loc];
37138
37139     while (rep !== undefined && path.length) rep = rep[path.pop()];
37140
37141     if (rep !== undefined) {
37142         if (o) for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
37143         return rep;
37144     }
37145
37146     if (loc !== 'en') {
37147         return t(s, o, 'en');
37148     }
37149
37150     if (o && 'default' in o) {
37151         return o.default;
37152     }
37153
37154     var missing = 'Missing ' + loc + ' translation: ' + s;
37155     if (typeof console !== 'undefined') console.error(missing); // eslint-disable-line
37156
37157     return missing;
37158 }
37159
37160 /**
37161  * Given string 'ltr' or 'rtl', save that setting
37162  *
37163  * @param {string} s ltr or rtl
37164  */
37165
37166 function setTextDirection(dir) {
37167     textDirection = dir;
37168 }
37169
37170 var detected;
37171
37172 function utilDetect(force) {
37173     if (detected && !force) return detected;
37174     detected = {};
37175
37176     var ua = navigator.userAgent,
37177         m = null;
37178
37179     m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i);   // Edge
37180     if (m !== null) {
37181         detected.browser = m[1];
37182         detected.version = m[2];
37183     }
37184     if (!detected.browser) {
37185         m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i);   // IE11
37186         if (m !== null) {
37187             detected.browser = 'msie';
37188             detected.version = m[1];
37189         }
37190     }
37191     if (!detected.browser) {
37192         m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i);   // Opera 15+
37193         if (m !== null) {
37194             detected.browser = 'Opera';
37195             detected.version = m[2];
37196         }
37197     }
37198     if (!detected.browser) {
37199         m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
37200         if (m !== null) {
37201             detected.browser = m[1];
37202             detected.version = m[2];
37203             m = ua.match(/version\/([\.\d]+)/i);
37204             if (m !== null) detected.version = m[1];
37205         }
37206     }
37207     if (!detected.browser) {
37208         detected.browser = navigator.appName;
37209         detected.version = navigator.appVersion;
37210     }
37211
37212     // keep major.minor version only..
37213     detected.version = detected.version.split(/\W/).slice(0,2).join('.');
37214
37215     if (detected.browser.toLowerCase() === 'msie') {
37216         detected.ie = true;
37217         detected.browser = 'Internet Explorer';
37218         detected.support = parseFloat(detected.version) >= 11;
37219     } else {
37220         detected.ie = false;
37221         detected.support = true;
37222     }
37223
37224     // Added due to incomplete svg style support. See #715
37225     detected.opera = (detected.browser.toLowerCase() === 'opera' && parseFloat(detected.version) < 15 );
37226
37227     detected.locale = (navigator.language || navigator.userLanguage || 'en-US');
37228     detected.language = detected.locale.split('-')[0];
37229
37230     // Search `navigator.languages` for a better locale.. Prefer the first language,
37231     // unless the second language is a culture-specific version of the first one, see #3842
37232     if (navigator.languages && navigator.languages.length > 0) {
37233         var code0 = navigator.languages[0],
37234             parts0 = code0.split('-');
37235
37236         detected.locale = code0;
37237         detected.language = parts0[0];
37238
37239         if (navigator.languages.length > 1 && parts0.length === 1) {
37240             var code1 = navigator.languages[1],
37241                 parts1 = code1.split('-');
37242
37243             if (parts1[0] === parts0[0]) {
37244                 detected.locale = code1;
37245             }
37246         }
37247     }
37248
37249     // Loaded locale is stored in currentLocale
37250     // return that instead (except in the situation where 'en' might override 'en-US')
37251     var loadedLocale = currentLocale || 'en';
37252     if (loadedLocale !== 'en') {
37253         detected.locale = loadedLocale;
37254         detected.language = detected.locale.split('-')[0];
37255     }
37256
37257     // detect text direction
37258     var q = utilStringQs(window.location.hash.substring(1));
37259     var lang = dataLocales[detected.locale];
37260     if ((lang && lang.rtl) || q.hasOwnProperty('rtl')) {
37261         detected.textDirection = 'rtl';
37262     } else {
37263         detected.textDirection = 'ltr';
37264     }
37265     setTextDirection(detected.textDirection);
37266
37267     // detect host
37268     var loc = window.top.location;
37269     var origin = loc.origin;
37270     if (!origin) {  // for unpatched IE11
37271         origin = loc.protocol + '//' + loc.hostname + (loc.port ? ':' + loc.port: '');
37272     }
37273
37274     detected.host = origin + loc.pathname;
37275
37276     detected.filedrop = (window.FileReader && 'ondrop' in window);
37277
37278     function nav(x) {
37279         return navigator.userAgent.indexOf(x) !== -1;
37280     }
37281
37282     if (nav('Win')) {
37283         detected.os = 'win';
37284         detected.platform = 'Windows';
37285     }
37286     else if (nav('Mac')) {
37287         detected.os = 'mac';
37288         detected.platform = 'Macintosh';
37289     }
37290     else if (nav('X11') || nav('Linux')) {
37291         detected.os = 'linux';
37292         detected.platform = 'Linux';
37293     }
37294     else {
37295         detected.os = 'win';
37296         detected.platform = 'Unknown';
37297     }
37298
37299     return detected;
37300 }
37301
37302 var remove$1 = removeDiacritics;
37303
37304 var replacementList = [
37305   {
37306     base: ' ',
37307     chars: "\u00A0",
37308   }, {
37309     base: '0',
37310     chars: "\u07C0",
37311   }, {
37312     base: 'A',
37313     chars: "\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F",
37314   }, {
37315     base: 'AA',
37316     chars: "\uA732",
37317   }, {
37318     base: 'AE',
37319     chars: "\u00C6\u01FC\u01E2",
37320   }, {
37321     base: 'AO',
37322     chars: "\uA734",
37323   }, {
37324     base: 'AU',
37325     chars: "\uA736",
37326   }, {
37327     base: 'AV',
37328     chars: "\uA738\uA73A",
37329   }, {
37330     base: 'AY',
37331     chars: "\uA73C",
37332   }, {
37333     base: 'B',
37334     chars: "\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0181",
37335   }, {
37336     base: 'C',
37337     chars: "\u24b8\uff23\uA73E\u1E08\u0106\u0043\u0108\u010A\u010C\u00C7\u0187\u023B",
37338   }, {
37339     base: 'D',
37340     chars: "\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018A\u0189\u1D05\uA779",
37341   }, {
37342     base: 'Dh',
37343     chars: "\u00D0",
37344   }, {
37345     base: 'DZ',
37346     chars: "\u01F1\u01C4",
37347   }, {
37348     base: 'Dz',
37349     chars: "\u01F2\u01C5",
37350   }, {
37351     base: 'E',
37352     chars: "\u025B\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E\u1D07",
37353   }, {
37354     base: 'F',
37355     chars: "\uA77C\u24BB\uFF26\u1E1E\u0191\uA77B",
37356   }, {
37357     base: 'G',
37358     chars: "\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E\u0262",
37359   }, {
37360     base: 'H',
37361     chars: "\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D",
37362   }, {
37363     base: 'I',
37364     chars: "\u24BE\uFF29\xCC\xCD\xCE\u0128\u012A\u012C\u0130\xCF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197",
37365   }, {
37366     base: 'J',
37367     chars: "\u24BF\uFF2A\u0134\u0248\u0237",
37368   }, {
37369     base: 'K',
37370     chars: "\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2",
37371   }, {
37372     base: 'L',
37373     chars: "\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780",
37374   }, {
37375     base: 'LJ',
37376     chars: "\u01C7",
37377   }, {
37378     base: 'Lj',
37379     chars: "\u01C8",
37380   }, {
37381     base: 'M',
37382     chars: "\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C\u03FB",
37383   }, {
37384     base: 'N',
37385     chars: "\uA7A4\u0220\u24C3\uFF2E\u01F8\u0143\xD1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u019D\uA790\u1D0E",
37386   }, {
37387     base: 'NJ',
37388     chars: "\u01CA",
37389   }, {
37390     base: 'Nj',
37391     chars: "\u01CB",
37392   }, {
37393     base: 'O',
37394     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",
37395   }, {
37396     base: 'OE',
37397     chars: "\u0152",
37398   }, {
37399     base: 'OI',
37400     chars: "\u01A2",
37401   }, {
37402     base: 'OO',
37403     chars: "\uA74E",
37404   }, {
37405     base: 'OU',
37406     chars: "\u0222",
37407   }, {
37408     base: 'P',
37409     chars: "\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754",
37410   }, {
37411     base: 'Q',
37412     chars: "\u24C6\uFF31\uA756\uA758\u024A",
37413   }, {
37414     base: 'R',
37415     chars: "\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782",
37416   }, {
37417     base: 'S',
37418     chars: "\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784",
37419   }, {
37420     base: 'T',
37421     chars: "\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786",
37422   }, {
37423     base: 'Th',
37424     chars: "\u00DE",
37425   }, {
37426     base: 'TZ',
37427     chars: "\uA728",
37428   }, {
37429     base: 'U',
37430     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",
37431   }, {
37432     base: 'V',
37433     chars: "\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245",
37434   }, {
37435     base: 'VY',
37436     chars: "\uA760",
37437   }, {
37438     base: 'W',
37439     chars: "\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72",
37440   }, {
37441     base: 'X',
37442     chars: "\u24CD\uFF38\u1E8A\u1E8C",
37443   }, {
37444     base: 'Y',
37445     chars: "\u24CE\uFF39\u1EF2\xDD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE",
37446   }, {
37447     base: 'Z',
37448     chars: "\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762",
37449   }, {
37450     base: 'a',
37451     chars: "\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250\u0251",
37452   }, {
37453     base: 'aa',
37454     chars: "\uA733",
37455   }, {
37456     base: 'ae',
37457     chars: "\u00E6\u01FD\u01E3",
37458   }, {
37459     base: 'ao',
37460     chars: "\uA735",
37461   }, {
37462     base: 'au',
37463     chars: "\uA737",
37464   }, {
37465     base: 'av',
37466     chars: "\uA739\uA73B",
37467   }, {
37468     base: 'ay',
37469     chars: "\uA73D",
37470   }, {
37471     base: 'b',
37472     chars: "\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0182",
37473   }, {
37474     base: 'c',
37475     chars: "\uFF43\u24D2\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184",
37476   }, {
37477     base: 'd',
37478     chars: "\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\u018B\u13E7\u0501\uA7AA",
37479   }, {
37480     base: 'dh',
37481     chars: "\u00F0",
37482   }, {
37483     base: 'dz',
37484     chars: "\u01F3\u01C6",
37485   }, {
37486     base: 'e',
37487     chars: "\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u01DD",
37488   }, {
37489     base: 'f',
37490     chars: "\u24D5\uFF46\u1E1F\u0192",
37491   }, {
37492     base: 'ff',
37493     chars: "\uFB00",
37494   }, {
37495     base: 'fi',
37496     chars: "\uFB01",
37497   }, {
37498     base: 'fl',
37499     chars: "\uFB02",
37500   }, {
37501     base: 'ffi',
37502     chars: "\uFB03",
37503   }, {
37504     base: 'ffl',
37505     chars: "\uFB04",
37506   }, {
37507     base: 'g',
37508     chars: "\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\uA77F\u1D79",
37509   }, {
37510     base: 'h',
37511     chars: "\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265",
37512   }, {
37513     base: 'hv',
37514     chars: "\u0195",
37515   }, {
37516     base: 'i',
37517     chars: "\u24D8\uFF49\xEC\xED\xEE\u0129\u012B\u012D\xEF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131",
37518   }, {
37519     base: 'j',
37520     chars: "\u24D9\uFF4A\u0135\u01F0\u0249",
37521   }, {
37522     base: 'k',
37523     chars: "\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3",
37524   }, {
37525     base: 'l',
37526     chars: "\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u026D",
37527   }, {
37528     base: 'lj',
37529     chars: "\u01C9",
37530   }, {
37531     base: 'm',
37532     chars: "\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F",
37533   }, {
37534     base: 'n',
37535     chars: "\u24DD\uFF4E\u01F9\u0144\xF1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u043B\u0509",
37536   }, {
37537     base: 'nj',
37538     chars: "\u01CC",
37539   }, {
37540     base: 'o',
37541     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",
37542   }, {
37543     base: 'oe',
37544     chars: "\u0153",
37545   }, {
37546     base: 'oi',
37547     chars: "\u01A3",
37548   }, {
37549     base: 'oo',
37550     chars: "\uA74F",
37551   }, {
37552     base: 'ou',
37553     chars: "\u0223",
37554   }, {
37555     base: 'p',
37556     chars: "\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u03C1",
37557   }, {
37558     base: 'q',
37559     chars: "\u24E0\uFF51\u024B\uA757\uA759",
37560   }, {
37561     base: 'r',
37562     chars: "\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783",
37563   }, {
37564     base: 's',
37565     chars: "\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0282",
37566   }, {
37567     base: 'ss',
37568     chars: "\xDF",
37569   }, {
37570     base: 't',
37571     chars: "\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787",
37572   }, {
37573     base: 'th',
37574     chars: "\u00FE",
37575   }, {
37576     base: 'tz',
37577     chars: "\uA729",
37578   }, {
37579     base: 'u',
37580     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",
37581   }, {
37582     base: 'v',
37583     chars: "\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C",
37584   }, {
37585     base: 'vy',
37586     chars: "\uA761",
37587   }, {
37588     base: 'w',
37589     chars: "\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73",
37590   }, {
37591     base: 'x',
37592     chars: "\u24E7\uFF58\u1E8B\u1E8D",
37593   }, {
37594     base: 'y',
37595     chars: "\u24E8\uFF59\u1EF3\xFD\u0177\u1EF9\u0233\u1E8F\xFF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF",
37596   }, {
37597     base: 'z',
37598     chars: "\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763",
37599   }
37600 ];
37601
37602 var diacriticsMap = {};
37603 for (var i = 0; i < replacementList.length; i += 1) {
37604   var chars = replacementList[i].chars;
37605   for (var j = 0; j < chars.length; j += 1) {
37606     diacriticsMap[chars[j]] = replacementList[i].base;
37607   }
37608 }
37609
37610 function removeDiacritics(str) {
37611   return str.replace(/[^\u0000-\u007e]/g, function(c) {
37612     return diacriticsMap[c] || c;
37613   });
37614 }
37615
37616 // see https://github.com/openstreetmap/iD/pull/3707
37617 // https://gist.github.com/mapmeld/556b09ddec07a2044c76e1ef45f01c60
37618
37619 var chars$1 = {
37620     // madda above alef
37621     1570: { initial: 'آ‎', isolated: 'ﺁ', medial: 'ﺁ', final: 'ﺂ' },
37622
37623     // hamza above and below alef
37624     1571: { initial: 'أ', isolated: 'ﺃ', medial: '', final: 'ﺄ' },
37625     // 1572 is ؤ
37626     1573: { initial: 'إ', isolated: 'ﺇ', medial: '', final: 'ﺈ' },
37627     // 1574 is ئ
37628     1575: { initial: 'ا', isolated: 'ا', medial: '', final: 'ﺎ' },
37629     1576: { initial: 'ﺑ', isolated: 'ﺏ', medial: 'ﺒ', final: 'ﺐ' },
37630
37631     // 1577 ة
37632     1577: { initial: '', isolated: 'ة', medial: '', final: 'ﺔ' },
37633
37634     1578: { initial: 'ﺗ', isolated: 'ﺕ', medial: 'ﺘ', final: 'ﺖ' },
37635     1579: { initial: 'ﺛ', isolated: 'ﺙ', medial: 'ﺜ', final: 'ﺚ' },
37636     1580: { initial: 'ﺟ', isolated: 'ﺝ', medial: 'ﺠ', final: 'ﺞ' },
37637     1581: { initial: 'ﺣ', isolated: 'ﺡ', medial: 'ﺤ', final: 'ﺢ' },
37638     1582: { initial: 'ﺧ', isolated: 'ﺥ', medial: 'ﺨ', final: 'ﺦ' },
37639     1583: { initial: 'ﺩ', isolated: 'ﺩ', medial: '', final: 'ﺪ' },
37640     1584: { initial: 'ﺫ', isolated: 'ﺫ', medial: '', final: 'ﺬ' },
37641     1585: { initial: 'ﺭ', isolated: 'ﺭ', medial: '', final: 'ﺮ' },
37642     1586: { initial: 'ﺯ', isolated: 'ﺯ', medial: '', final: 'ﺰ' },
37643     1688: { initial: 'ﮊ', isolated: 'ﮊ', medial: '', final: 'ﮋ' },
37644     1587: { initial: 'ﺳ', isolated: 'ﺱ', medial: 'ﺴ', final: 'ﺲ' },
37645     1588: { initial: 'ﺷ', isolated: 'ﺵ', medial: 'ﺸ', final: 'ﺶ' },
37646     1589: { initial: 'ﺻ', isolated: 'ﺹ', medial: 'ﺼ', final: 'ﺺ' },
37647     1590: { initial: 'ﺿ', isolated: 'ﺽ', medial: 'ﻀ', final: 'ﺾ' },
37648     1591: { initial: 'ﻃ', isolated: 'ﻁ', medial: 'ﻄ', final: 'ﻂ' },
37649     1592: { initial: 'ﻇ', isolated: 'ﻅ', medial: 'ﻈ', final: 'ﻆ' },
37650     1593: { initial: 'ﻋ', isolated: 'ﻉ', medial: 'ﻌ', final: 'ﻊ' },
37651     1594: { initial: 'ﻏ', isolated: 'ﻍ', medial: 'ﻐ', final: 'ﻎ' },
37652
37653     // 1595 ػ - may be very rare
37654
37655     1601: { initial: 'ﻓ', isolated: 'ﻑ', medial: 'ﻔ', final: 'ﻒ' },
37656     1602: { initial: 'ﻗ', isolated: 'ﻕ', medial: 'ﻘ', final: 'ﻖ' },
37657     1604: { initial: 'ﻟ', isolated: 'ﻝ', medial: 'ﻠ', final: 'ﻞ' },
37658     1605: { initial: 'ﻣ', isolated: 'ﻡ', medial: 'ﻤ', final: 'ﻢ' },
37659     1606: { initial: 'ﻧ', isolated: 'ﻥ', medial: 'ﻨ', final: 'ﻦ' },
37660     1607: { initial: 'ﻫ', isolated: 'ﻩ', medial: 'ﻬ', final: 'ﻪ' },
37661     1608: { initial: 'ﻭ', isolated: 'ﻭ', medial: '', final: 'ﻮ' },
37662
37663     // 1609 ى
37664     1609: { initial: 'ﯨ', isolated: 'ﻯ', medial: 'ﯩ', final: 'ﻰ' },
37665     // 1610 ي
37666     1610: { initial: 'ﻳ', isolated: 'ﻱ', medial: 'ﻴ', final: 'ﻲ' },
37667
37668     // short vowel sounds / tashkil markings
37669
37670     1662: { initial: 'ﭘ', isolated: 'ﭖ', medial: 'ﭙ', final: 'ﭗ' },
37671
37672     1670: { initial: 'ﭼ', isolated: 'ﭺ', medial: 'ﭽ', final: 'ﭻ' },
37673     1603: { initial: 'ﻛ', isolated: 'ﻙ', medial: 'ﻜ', final: 'ﻚ' },
37674     1705: { initial: 'ﻛ', isolated: 'ﮎ', medial: 'ﻜ', final: 'ﮏ' },
37675     1711: { initial: 'ﮔ', isolated: 'ﮒ', medial: 'ﮕ', final: 'ﮓ' },
37676     1740: { initial: 'ﻳ', isolated: 'ﻯ', medial: 'ﻴ', final: 'ﻰ' },
37677     5000: { initial: 'ﻻ', isolated: 'ﻻ', medial: '', final: 'ﻼ' }
37678 };
37679
37680 var rtlRegex = /[\u0590-\u05FF\u0600-\u06FF\u0780-\u07BF]/;
37681
37682 function fixRTLTextForSvg(inputText) {
37683     var context = true;
37684     var ret = '';
37685     var rtlBuffer = [];
37686     var arabicRegex = /[\u0600-\u06FF]/g;
37687     var arabicTashkil = /[\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED]/;
37688     var thaanaVowel = /[\u07A6-\u07B0]/;
37689     var hebrewSign = /[\u0591-\u05bd\u05bf\u05c1-\u05c5\u05c7]/;
37690
37691     if (!arabicRegex.test(inputText)) {
37692         // Hebrew or Thaana RTL script
37693         for (var n = 0; n < inputText.length; n++) {
37694             var c = inputText[n];
37695             if ((thaanaVowel.test(c) || hebrewSign.test(c)) && rtlBuffer.length) {
37696                 rtlBuffer[rtlBuffer.length - 1] += c;
37697             } else if (rtlRegex.test(c)) {
37698                 rtlBuffer.push(c);
37699             } else if (c === ' ' && rtlBuffer.length) {
37700                 // whitespace within RTL text
37701                 rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
37702             } else {
37703                 // non-RTL character
37704                 ret += rtlBuffer.reverse().join('') + c;
37705                 rtlBuffer = [];
37706             }
37707         }
37708     } else {
37709         for (var i = 0, l = inputText.length; i < l; i++) {
37710             var code = inputText[i].charCodeAt(0);
37711             var nextCode = inputText[i + 1] ? inputText[i + 1].charCodeAt(0) : 0;
37712
37713             if (!chars$1[code]) {
37714                 if (code === 32 && rtlBuffer.length) {
37715                     // whitespace
37716                     rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
37717                 } else if (arabicTashkil.test(inputText[i]) && rtlBuffer.length) {
37718                     // tashkil mark
37719                     rtlBuffer[rtlBuffer.length - 1] += inputText[i];
37720                 } else {
37721                     // non-RTL character
37722                     ret += rtlBuffer.reverse().join('') + inputText[i];
37723                     rtlBuffer = [];
37724                 }
37725                 continue;
37726             }
37727             if (context) {
37728                 if (i === l - 1 || nextCode === 32) {
37729                     rtlBuffer.push(chars$1[code].isolated);
37730                 } else {
37731                     // special case for لا
37732                     if (code === 1604 && nextCode === 1575) {
37733                         rtlBuffer.push(chars$1[5000].initial);
37734                         i++;
37735                         context = true;
37736                         continue;
37737                     }
37738                     rtlBuffer.push(chars$1[code].initial);
37739                 }
37740             } else {
37741                 if (i === l - 1 || nextCode === 32){
37742                     rtlBuffer.push(chars$1[code].final);
37743                 } else {
37744                     // special case for ﻼ
37745                     if (code === 1604 && nextCode === 1575){
37746                         rtlBuffer.push(chars$1[5000].final);
37747                         i++;
37748                         context = true;
37749                         continue;
37750                     }
37751                     if (chars$1[code].medial === ''){
37752                         rtlBuffer.push(chars$1[code].final);
37753                     } else {
37754                         rtlBuffer.push(chars$1[code].medial);
37755                     }
37756                 }
37757             }
37758             context = (chars$1[code].medial === '') || nextCode === 32;
37759         }
37760     }
37761     ret += rtlBuffer.reverse().join('');
37762     return ret;
37763 }
37764
37765 function utilTagText(entity) {
37766     return entries(entity.tags).map(function(e) {
37767         return e.key + '=' + e.value;
37768     }).join(', ');
37769 }
37770
37771
37772 function utilEntitySelector(ids) {
37773     return ids.length ? '.' + ids.join(',.') : 'nothing';
37774 }
37775
37776
37777 function utilEntityOrMemberSelector(ids, graph) {
37778     var s = utilEntitySelector(ids);
37779
37780     ids.forEach(function(id) {
37781         var entity = graph.hasEntity(id);
37782         if (entity && entity.type === 'relation') {
37783             entity.members.forEach(function(member) {
37784                 s += ',.' + member.id;
37785             });
37786         }
37787     });
37788
37789     return s;
37790 }
37791
37792
37793 function utilGetAllNodes(ids, graph) {
37794     var seen = {};
37795     var nodes = [];
37796     ids.forEach(getNodes);
37797     return nodes;
37798
37799     function getNodes(id) {
37800         if (seen[id]) return;
37801         seen[id] = true;
37802
37803         var entity = graph.hasEntity(id);
37804         if (!entity) return;
37805
37806         if (entity.type === 'node') {
37807             nodes.push(entity);
37808         } else if (entity.type === 'way') {
37809             entity.nodes.forEach(getNodes);
37810         } else {
37811             entity.members.map(function(member) { return member.id; }).forEach(getNodes);
37812         }
37813     }
37814 }
37815
37816
37817 function utilDisplayName(entity) {
37818     var localizedNameKey = 'name:' + utilDetect().locale.toLowerCase().split('-')[0],
37819         name = entity.tags[localizedNameKey] || entity.tags.name || '',
37820         network = entity.tags.cycle_network || entity.tags.network;
37821
37822     if (!name && entity.tags.ref) {
37823         name = entity.tags.ref;
37824         if (network) {
37825             name = network + ' ' + name;
37826         }
37827     }
37828
37829     return name;
37830 }
37831
37832
37833 function utilDisplayNameForPath(entity) {
37834     var name = utilDisplayName(entity);
37835     var isFirefox = utilDetect().browser.toLowerCase().indexOf('firefox') > -1;
37836
37837     if (!isFirefox && name && rtlRegex.test(name)) {
37838         name = fixRTLTextForSvg(name);
37839     }
37840
37841     return name;
37842 }
37843
37844
37845 function utilDisplayType(id) {
37846     return {
37847         n: t('inspector.node'),
37848         w: t('inspector.way'),
37849         r: t('inspector.relation')
37850     }[id.charAt(0)];
37851 }
37852
37853
37854 function utilStringQs(str) {
37855     return str.split('&').reduce(function(obj, pair){
37856         var parts = pair.split('=');
37857         if (parts.length === 2) {
37858             obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
37859         }
37860         return obj;
37861     }, {});
37862 }
37863
37864
37865 function utilQsString(obj, noencode) {
37866     function softEncode(s) {
37867       // encode everything except special characters used in certain hash parameters:
37868       // "/" in map states, ":", ",", {" and "}" in background
37869       return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
37870     }
37871     return Object.keys(obj).sort().map(function(key) {
37872         return encodeURIComponent(key) + '=' + (
37873             noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
37874     }).join('&');
37875 }
37876
37877
37878 function utilPrefixDOMProperty(property) {
37879     var prefixes = ['webkit', 'ms', 'moz', 'o'],
37880         i = -1,
37881         n = prefixes.length,
37882         s = document.body;
37883
37884     if (property in s)
37885         return property;
37886
37887     property = property.substr(0, 1).toUpperCase() + property.substr(1);
37888
37889     while (++i < n)
37890         if (prefixes[i] + property in s)
37891             return prefixes[i] + property;
37892
37893     return false;
37894 }
37895
37896
37897 function utilPrefixCSSProperty(property) {
37898     var prefixes = ['webkit', 'ms', 'Moz', 'O'],
37899         i = -1,
37900         n = prefixes.length,
37901         s = document.body.style;
37902
37903     if (property.toLowerCase() in s)
37904         return property.toLowerCase();
37905
37906     while (++i < n)
37907         if (prefixes[i] + property in s)
37908             return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
37909
37910     return false;
37911 }
37912
37913
37914 var transformProperty;
37915 function utilSetTransform(el, x, y, scale) {
37916     var prop = transformProperty = transformProperty || utilPrefixCSSProperty('Transform'),
37917         translate = utilDetect().opera ?
37918             'translate('   + x + 'px,' + y + 'px)' :
37919             'translate3d(' + x + 'px,' + y + 'px,0)';
37920     return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
37921 }
37922
37923
37924 // Calculates Levenshtein distance between two strings
37925 // see:  https://en.wikipedia.org/wiki/Levenshtein_distance
37926 // first converts the strings to lowercase and replaces diacritic marks with ascii equivalents.
37927 function utilEditDistance(a, b) {
37928     a = remove$1(a.toLowerCase());
37929     b = remove$1(b.toLowerCase());
37930     if (a.length === 0) return b.length;
37931     if (b.length === 0) return a.length;
37932     var matrix = [];
37933     for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
37934     for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
37935     for (i = 1; i <= b.length; i++) {
37936         for (j = 1; j <= a.length; j++) {
37937             if (b.charAt(i-1) === a.charAt(j-1)) {
37938                 matrix[i][j] = matrix[i-1][j-1];
37939             } else {
37940                 matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
37941                     Math.min(matrix[i][j-1] + 1, // insertion
37942                     matrix[i-1][j] + 1)); // deletion
37943             }
37944         }
37945     }
37946     return matrix[b.length][a.length];
37947 }
37948
37949
37950 // a d3.mouse-alike which
37951 // 1. Only works on HTML elements, not SVG
37952 // 2. Does not cause style recalculation
37953 function utilFastMouse(container) {
37954     var rect = container.getBoundingClientRect(),
37955         rectLeft = rect.left,
37956         rectTop = rect.top,
37957         clientLeft = +container.clientLeft,
37958         clientTop = +container.clientTop;
37959     if (textDirection === 'rtl') {
37960         rectLeft = 0;
37961     }
37962     return function(e) {
37963         return [
37964             e.clientX - rectLeft - clientLeft,
37965             e.clientY - rectTop - clientTop];
37966     };
37967 }
37968
37969
37970 /* eslint-disable no-proto */
37971 var utilGetPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
37972 /* eslint-enable no-proto */
37973
37974
37975 function utilAsyncMap(inputs, func, callback) {
37976     var remaining = inputs.length,
37977         results = [],
37978         errors = [];
37979
37980     inputs.forEach(function(d, i) {
37981         func(d, function done(err, data) {
37982             errors[i] = err;
37983             results[i] = data;
37984             remaining--;
37985             if (!remaining) callback(errors, results);
37986         });
37987     });
37988 }
37989
37990
37991 // wraps an index to an interval [0..length-1]
37992 function utilWrap(index, length) {
37993     if (index < 0)
37994         index += Math.ceil(-index/length)*length;
37995     return index % length;
37996 }
37997
37998
37999 /**
38000  * a replacement for functor
38001  *
38002  * @param {*} value any value
38003  * @returns {Function} a function that returns that value or the value if it's a function
38004  */
38005 function utilFunctor(value) {
38006     if (typeof value === 'function') return value;
38007     return function() {
38008         return value;
38009     };
38010 }
38011
38012
38013 function utilNoAuto(selection$$1) {
38014     return selection$$1
38015         .attr('autocomplete', 'off')
38016         .attr('autocorrect', 'off')
38017         .attr('autocapitalize', 'off')
38018         .attr('spellcheck', 'false');
38019 }
38020
38021 // Like selection.property('value', ...), but avoids no-op value sets,
38022 // which can result in layout/repaint thrashing in some situations.
38023 function utilGetSetValue(selection, value) {
38024     function d3_selection_value(value) {
38025         function valueNull() {
38026             delete this.value;
38027         }
38028
38029         function valueConstant() {
38030             if (this.value !== value) {
38031                 this.value = value;
38032             }
38033         }
38034
38035         function valueFunction() {
38036             var x = value.apply(this, arguments);
38037             if (x == null) {
38038                 delete this.value;
38039             } else if (this.value !== x) {
38040                 this.value = x;
38041             }
38042         }
38043
38044         return value == null
38045             ? valueNull : (typeof value === 'function'
38046             ? valueFunction : valueConstant);
38047     }
38048
38049     if (arguments.length === 1) {
38050         return selection.property('value');
38051     }
38052
38053     return selection.each(d3_selection_value(value));
38054 }
38055
38056 // Copies a variable number of methods from source to target.
38057 function utilRebind(target, source) {
38058     var i = 1, n = arguments.length, method;
38059     while (++i < n) {
38060         target[method = arguments[i]] = d3_rebind(target, source, source[method]);
38061     }
38062     return target;
38063 }
38064
38065 // Method is assumed to be a standard D3 getter-setter:
38066 // If passed with no arguments, gets the value.
38067 // If passed with arguments, sets the value and returns the target.
38068 function d3_rebind(target, source, method) {
38069     return function() {
38070         var value = method.apply(source, arguments);
38071         return value === source ? target : value;
38072     };
38073 }
38074
38075 // A per-domain session mutex backed by a cookie and dead man's
38076 // switch. If the session crashes, the mutex will auto-release
38077 // after 5 seconds.
38078
38079 function utilSessionMutex(name) {
38080     var mutex = {},
38081         intervalID;
38082
38083     function renew() {
38084         var expires = new Date();
38085         expires.setSeconds(expires.getSeconds() + 5);
38086         document.cookie = name + '=1; expires=' + expires.toUTCString();
38087     }
38088
38089     mutex.lock = function() {
38090         if (intervalID) return true;
38091         var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
38092         if (cookie) return false;
38093         renew();
38094         intervalID = window.setInterval(renew, 4000);
38095         return true;
38096     };
38097
38098     mutex.unlock = function() {
38099         if (!intervalID) return;
38100         document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
38101         clearInterval(intervalID);
38102         intervalID = null;
38103     };
38104
38105     mutex.locked = function() {
38106         return !!intervalID;
38107     };
38108
38109     return mutex;
38110 }
38111
38112 function utilSuggestNames(preset, suggestions) {
38113     preset = preset.id.split('/', 2);
38114     var k = preset[0],
38115         v = preset[1];
38116
38117     return function(value, callback) {
38118         var result = [];
38119         if (value && value.length > 2) {
38120             if (suggestions[k] && suggestions[k][v]) {
38121                 for (var sugg in suggestions[k][v]) {
38122                     var dist = utilEditDistance(value, sugg.substring(0, value.length));
38123                     if (dist < 3) {
38124                         result.push({
38125                             title: sugg,
38126                             value: sugg,
38127                             dist: dist
38128                         });
38129                     }
38130                 }
38131             }
38132             result.sort(function(a, b) {
38133                 return a.dist - b.dist;
38134             });
38135         }
38136         result = result.slice(0,3);
38137         callback(result);
38138     };
38139 }
38140
38141 function utilTriggerEvent(target, type) {
38142     target.each(function() {
38143         var evt = document.createEvent('HTMLEvents');
38144         evt.initEvent(type, true, true);
38145         this.dispatchEvent(evt);
38146     });
38147 }
38148
38149 function validationDeprecatedTag() {
38150
38151     var validation = function(changes) {
38152         var warnings = [];
38153         for (var i = 0; i < changes.created.length; i++) {
38154             var change = changes.created[i],
38155                 deprecatedTags = change.deprecatedTags();
38156
38157             if (!lodash.isEmpty(deprecatedTags)) {
38158                 var tags = utilTagText({ tags: deprecatedTags });
38159                 warnings.push({
38160                     id: 'deprecated_tags',
38161                     message: t('validations.deprecated_tags', { tags: tags }),
38162                     entity: change
38163                 });
38164             }
38165         }
38166
38167         return warnings;
38168     };
38169
38170
38171     return validation;
38172 }
38173
38174 function validationDisconnectedHighway() {
38175
38176
38177     function isDisconnectedHighway(entity, graph) {
38178         if (!entity.tags.highway) return false;
38179         if (entity.geometry(graph) !== 'line') return false;
38180
38181         return graph.childNodes(entity)
38182             .every(function(vertex) {
38183                 var parents = graph.parentWays(vertex);
38184                 if (parents.length === 1) {  // standalone vertex
38185                     return true;
38186                 } else {                     // shared vertex
38187                     return !vertex.tags.entrance &&
38188                         parents.filter(function(parent) {
38189                             return parent.tags.highway && parent !== entity;
38190                         }).length === 0;
38191                 }
38192             });
38193     }
38194
38195
38196     var validation = function(changes, graph) {
38197         var warnings = [];
38198         for (var i = 0; i < changes.created.length; i++) {
38199             var entity = changes.created[i];
38200
38201             if (isDisconnectedHighway(entity, graph)) {
38202                 warnings.push({
38203                     id: 'disconnected_highway',
38204                     message: t('validations.disconnected_highway'),
38205                     tooltip: t('validations.disconnected_highway_tooltip'),
38206                     entity: entity
38207                 });
38208             }
38209         }
38210
38211         return warnings;
38212     };
38213
38214
38215     return validation;
38216 }
38217
38218 function validationManyDeletions() {
38219     var threshold = 100;
38220
38221     var validation = function(changes) {
38222         var warnings = [];
38223         if (changes.deleted.length > threshold) {
38224             warnings.push({
38225                 id: 'many_deletions',
38226                 message: t('validations.many_deletions', { n: changes.deleted.length })
38227             });
38228         }
38229
38230         return warnings;
38231     };
38232
38233
38234     return validation;
38235 }
38236
38237 function validationMissingTag() {
38238
38239     // Slightly stricter check than Entity#isUsed (#3091)
38240     function hasTags(entity, graph) {
38241         return lodash.without(Object.keys(entity.tags), 'area', 'name').length > 0 ||
38242             graph.parentRelations(entity).length > 0;
38243     }
38244
38245     var validation = function(changes, graph) {
38246         var types = ['point', 'line', 'area', 'relation'],
38247             warnings = [];
38248
38249         for (var i = 0; i < changes.created.length; i++) {
38250             var change = changes.created[i],
38251                 geometry = change.geometry(graph);
38252
38253             if (types.indexOf(geometry) !== -1 && !hasTags(change, graph)) {
38254                 warnings.push({
38255                     id: 'missing_tag',
38256                     message: t('validations.untagged_' + geometry),
38257                     tooltip: t('validations.untagged_' + geometry + '_tooltip'),
38258                     entity: change
38259                 });
38260             }
38261         }
38262
38263         return warnings;
38264     };
38265
38266
38267     return validation;
38268 }
38269
38270 function validationOldMultipolygon() {
38271
38272
38273     return function validation(changes, graph) {
38274         var warnings = [];
38275         for (var i = 0; i < changes.created.length; i++) {
38276             var entity = changes.created[i];
38277             var parent = osmIsSimpleMultipolygonOuterMember(entity, graph);
38278             if (parent) {
38279                 warnings.push({
38280                     id: 'old_multipolygon',
38281                     message: t('validations.old_multipolygon'),
38282                     tooltip: t('validations.old_multipolygon_tooltip'),
38283                     entity: parent
38284                 });
38285             }
38286         }
38287         return warnings;
38288     };
38289 }
38290
38291 // https://github.com/openstreetmap/josm/blob/mirror/src/org/
38292 // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
38293 function validationTagSuggestsArea() {
38294
38295     function tagSuggestsArea(tags) {
38296         if (lodash.isEmpty(tags)) return false;
38297
38298         var presence = ['landuse', 'amenities', 'tourism', 'shop'];
38299         for (var i = 0; i < presence.length; i++) {
38300             if (tags[presence[i]] !== undefined) {
38301                 return presence[i] + '=' + tags[presence[i]];
38302             }
38303         }
38304
38305         if (tags.building && tags.building === 'yes') return 'building=yes';
38306     }
38307
38308
38309     var validation = function(changes, graph) {
38310         var warnings = [];
38311         for (var i = 0; i < changes.created.length; i++) {
38312             var change = changes.created[i],
38313                 geometry = change.geometry(graph),
38314                 suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
38315
38316             if (suggestion) {
38317                 warnings.push({
38318                     id: 'tag_suggests_area',
38319                     message: t('validations.tag_suggests_area', { tag: suggestion }),
38320                     entity: change
38321                 });
38322             }
38323         }
38324
38325         return warnings;
38326     };
38327
38328
38329     return validation;
38330 }
38331
38332
38333
38334 var Validations = Object.freeze({
38335         validationDeprecatedTag: validationDeprecatedTag,
38336         validationDisconnectedHighway: validationDisconnectedHighway,
38337         validationManyDeletions: validationManyDeletions,
38338         validationMissingTag: validationMissingTag,
38339         validationOldMultipolygon: validationOldMultipolygon,
38340         validationTagSuggestsArea: validationTagSuggestsArea
38341 });
38342
38343 /*
38344     iD.Difference represents the difference between two graphs.
38345     It knows how to calculate the set of entities that were
38346     created, modified, or deleted, and also contains the logic
38347     for recursively extending a difference to the complete set
38348     of entities that will require a redraw, taking into account
38349     child and parent relationships.
38350  */
38351 function coreDifference(base, head) {
38352     var changes = {},
38353         difference = {},
38354         length = 0;
38355
38356
38357     function changed(h, b) {
38358         return h !== b && !lodash.isEqual(lodash.omit(h, 'v'), lodash.omit(b, 'v'));
38359     }
38360
38361
38362     lodash.each(head.entities, function(h, id) {
38363         var b = base.entities[id];
38364         if (changed(h, b)) {
38365             changes[id] = {base: b, head: h};
38366             length++;
38367         }
38368     });
38369
38370
38371     lodash.each(base.entities, function(b, id) {
38372         var h = head.entities[id];
38373         if (!changes[id] && changed(h, b)) {
38374             changes[id] = {base: b, head: h};
38375             length++;
38376         }
38377     });
38378
38379
38380     function addParents(parents, result) {
38381         for (var i = 0; i < parents.length; i++) {
38382             var parent = parents[i];
38383
38384             if (parent.id in result)
38385                 continue;
38386
38387             result[parent.id] = parent;
38388             addParents(head.parentRelations(parent), result);
38389         }
38390     }
38391
38392
38393     difference.length = function() {
38394         return length;
38395     };
38396
38397
38398     difference.changes = function() {
38399         return changes;
38400     };
38401
38402
38403     difference.extantIDs = function() {
38404         var result = [];
38405         lodash.each(changes, function(change, id) {
38406             if (change.head) result.push(id);
38407         });
38408         return result;
38409     };
38410
38411
38412     difference.modified = function() {
38413         var result = [];
38414         lodash.each(changes, function(change) {
38415             if (change.base && change.head) result.push(change.head);
38416         });
38417         return result;
38418     };
38419
38420
38421     difference.created = function() {
38422         var result = [];
38423         lodash.each(changes, function(change) {
38424             if (!change.base && change.head) result.push(change.head);
38425         });
38426         return result;
38427     };
38428
38429
38430     difference.deleted = function() {
38431         var result = [];
38432         lodash.each(changes, function(change) {
38433             if (change.base && !change.head) result.push(change.base);
38434         });
38435         return result;
38436     };
38437
38438
38439     difference.summary = function() {
38440         var relevant = {};
38441
38442         function addEntity(entity, graph, changeType) {
38443             relevant[entity.id] = {
38444                 entity: entity,
38445                 graph: graph,
38446                 changeType: changeType
38447             };
38448         }
38449
38450         function addParents(entity) {
38451             var parents = head.parentWays(entity);
38452             for (var j = parents.length - 1; j >= 0; j--) {
38453                 var parent = parents[j];
38454                 if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
38455             }
38456         }
38457
38458         lodash.each(changes, function(change) {
38459             if (change.head && change.head.geometry(head) !== 'vertex') {
38460                 addEntity(change.head, head, change.base ? 'modified' : 'created');
38461
38462             } else if (change.base && change.base.geometry(base) !== 'vertex') {
38463                 addEntity(change.base, base, 'deleted');
38464
38465             } else if (change.base && change.head) { // modified vertex
38466                 var moved    = !lodash.isEqual(change.base.loc,  change.head.loc),
38467                     retagged = !lodash.isEqual(change.base.tags, change.head.tags);
38468
38469                 if (moved) {
38470                     addParents(change.head);
38471                 }
38472
38473                 if (retagged || (moved && change.head.hasInterestingTags())) {
38474                     addEntity(change.head, head, 'modified');
38475                 }
38476
38477             } else if (change.head && change.head.hasInterestingTags()) { // created vertex
38478                 addEntity(change.head, head, 'created');
38479
38480             } else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
38481                 addEntity(change.base, base, 'deleted');
38482             }
38483         });
38484
38485         return values(relevant);
38486     };
38487
38488
38489     difference.complete = function(extent$$1) {
38490         var result = {}, id, change;
38491
38492         for (id in changes) {
38493             change = changes[id];
38494
38495             var h = change.head,
38496                 b = change.base,
38497                 entity = h || b;
38498
38499             if (extent$$1 &&
38500                 (!h || !h.intersects(extent$$1, head)) &&
38501                 (!b || !b.intersects(extent$$1, base)))
38502                 continue;
38503
38504             result[id] = h;
38505
38506             if (entity.type === 'way') {
38507                 var nh = h ? h.nodes : [],
38508                     nb = b ? b.nodes : [],
38509                     diff, i;
38510
38511                 diff = lodash.difference(nh, nb);
38512                 for (i = 0; i < diff.length; i++) {
38513                     result[diff[i]] = head.hasEntity(diff[i]);
38514                 }
38515
38516                 diff = lodash.difference(nb, nh);
38517                 for (i = 0; i < diff.length; i++) {
38518                     result[diff[i]] = head.hasEntity(diff[i]);
38519                 }
38520             }
38521
38522             addParents(head.parentWays(entity), result);
38523             addParents(head.parentRelations(entity), result);
38524         }
38525
38526         return result;
38527     };
38528
38529
38530     return difference;
38531 }
38532
38533 function coreGraph$$1(other, mutable) {
38534     if (!(this instanceof coreGraph$$1)) return new coreGraph$$1(other, mutable);
38535
38536     if (other instanceof coreGraph$$1) {
38537         var base = other.base();
38538         this.entities = lodash.assign(Object.create(base.entities), other.entities);
38539         this._parentWays = lodash.assign(Object.create(base.parentWays), other._parentWays);
38540         this._parentRels = lodash.assign(Object.create(base.parentRels), other._parentRels);
38541
38542     } else {
38543         this.entities = Object.create({});
38544         this._parentWays = Object.create({});
38545         this._parentRels = Object.create({});
38546         this.rebase(other || [], [this]);
38547     }
38548
38549     this.transients = {};
38550     this._childNodes = {};
38551     this.frozen = !mutable;
38552 }
38553
38554
38555 coreGraph$$1.prototype = {
38556
38557     hasEntity: function(id) {
38558         return this.entities[id];
38559     },
38560
38561
38562     entity: function(id) {
38563         var entity = this.entities[id];
38564         if (!entity) {
38565             throw new Error('entity ' + id + ' not found');
38566         }
38567         return entity;
38568     },
38569
38570
38571     transient: function(entity, key, fn) {
38572         var id = entity.id,
38573             transients = this.transients[id] ||
38574             (this.transients[id] = {});
38575
38576         if (transients[key] !== undefined) {
38577             return transients[key];
38578         }
38579
38580         transients[key] = fn.call(entity);
38581
38582         return transients[key];
38583     },
38584
38585
38586     parentWays: function(entity) {
38587         var parents = this._parentWays[entity.id],
38588             result = [];
38589
38590         if (parents) {
38591             for (var i = 0; i < parents.length; i++) {
38592                 result.push(this.entity(parents[i]));
38593             }
38594         }
38595         return result;
38596     },
38597
38598
38599     isPoi: function(entity) {
38600         var parentWays = this._parentWays[entity.id];
38601         return !parentWays || parentWays.length === 0;
38602     },
38603
38604
38605     isShared: function(entity) {
38606         var parentWays = this._parentWays[entity.id];
38607         return parentWays && parentWays.length > 1;
38608     },
38609
38610
38611     parentRelations: function(entity) {
38612         var parents = this._parentRels[entity.id],
38613             result = [];
38614
38615         if (parents) {
38616             for (var i = 0; i < parents.length; i++) {
38617                 result.push(this.entity(parents[i]));
38618             }
38619         }
38620         return result;
38621     },
38622
38623
38624     childNodes: function(entity) {
38625         if (this._childNodes[entity.id]) return this._childNodes[entity.id];
38626         if (!entity.nodes) return [];
38627
38628         var nodes = [];
38629         for (var i = 0; i < entity.nodes.length; i++) {
38630             nodes[i] = this.entity(entity.nodes[i]);
38631         }
38632
38633         if (debug) Object.freeze(nodes);
38634
38635         this._childNodes[entity.id] = nodes;
38636         return this._childNodes[entity.id];
38637     },
38638
38639
38640     base: function() {
38641         return {
38642             'entities': utilGetPrototypeOf(this.entities),
38643             'parentWays': utilGetPrototypeOf(this._parentWays),
38644             'parentRels': utilGetPrototypeOf(this._parentRels)
38645         };
38646     },
38647
38648
38649     // Unlike other graph methods, rebase mutates in place. This is because it
38650     // is used only during the history operation that merges newly downloaded
38651     // data into each state. To external consumers, it should appear as if the
38652     // graph always contained the newly downloaded data.
38653     rebase: function(entities, stack, force) {
38654         var base = this.base(),
38655             i, j, k, id;
38656
38657         for (i = 0; i < entities.length; i++) {
38658             var entity = entities[i];
38659
38660             if (!entity.visible || (!force && base.entities[entity.id]))
38661                 continue;
38662
38663             // Merging data into the base graph
38664             base.entities[entity.id] = entity;
38665             this._updateCalculated(undefined, entity, base.parentWays, base.parentRels);
38666
38667             // Restore provisionally-deleted nodes that are discovered to have an extant parent
38668             if (entity.type === 'way') {
38669                 for (j = 0; j < entity.nodes.length; j++) {
38670                     id = entity.nodes[j];
38671                     for (k = 1; k < stack.length; k++) {
38672                         var ents = stack[k].entities;
38673                         if (ents.hasOwnProperty(id) && ents[id] === undefined) {
38674                             delete ents[id];
38675                         }
38676                     }
38677                 }
38678             }
38679         }
38680
38681         for (i = 0; i < stack.length; i++) {
38682             stack[i]._updateRebased();
38683         }
38684     },
38685
38686
38687     _updateRebased: function() {
38688         var base = this.base(),
38689             i, k, child, id, keys;
38690
38691         keys = Object.keys(this._parentWays);
38692         for (i = 0; i < keys.length; i++) {
38693             child = keys[i];
38694             if (base.parentWays[child]) {
38695                 for (k = 0; k < base.parentWays[child].length; k++) {
38696                     id = base.parentWays[child][k];
38697                     if (!this.entities.hasOwnProperty(id) && !lodash.includes(this._parentWays[child], id)) {
38698                         this._parentWays[child].push(id);
38699                     }
38700                 }
38701             }
38702         }
38703
38704         keys = Object.keys(this._parentRels);
38705         for (i = 0; i < keys.length; i++) {
38706             child = keys[i];
38707             if (base.parentRels[child]) {
38708                 for (k = 0; k < base.parentRels[child].length; k++) {
38709                     id = base.parentRels[child][k];
38710                     if (!this.entities.hasOwnProperty(id) && !lodash.includes(this._parentRels[child], id)) {
38711                         this._parentRels[child].push(id);
38712                     }
38713                 }
38714             }
38715         }
38716
38717         this.transients = {};
38718
38719         // this._childNodes is not updated, under the assumption that
38720         // ways are always downloaded with their child nodes.
38721     },
38722
38723
38724     // Updates calculated properties (parentWays, parentRels) for the specified change
38725     _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
38726
38727         parentWays = parentWays || this._parentWays;
38728         parentRels = parentRels || this._parentRels;
38729
38730         var type = entity && entity.type || oldentity && oldentity.type,
38731             removed, added, ways, rels, i;
38732
38733
38734         if (type === 'way') {
38735
38736             // Update parentWays
38737             if (oldentity && entity) {
38738                 removed = lodash.difference(oldentity.nodes, entity.nodes);
38739                 added = lodash.difference(entity.nodes, oldentity.nodes);
38740             } else if (oldentity) {
38741                 removed = oldentity.nodes;
38742                 added = [];
38743             } else if (entity) {
38744                 removed = [];
38745                 added = entity.nodes;
38746             }
38747             for (i = 0; i < removed.length; i++) {
38748                 parentWays[removed[i]] = lodash.without(parentWays[removed[i]], oldentity.id);
38749             }
38750             for (i = 0; i < added.length; i++) {
38751                 ways = lodash.without(parentWays[added[i]], entity.id);
38752                 ways.push(entity.id);
38753                 parentWays[added[i]] = ways;
38754             }
38755
38756         } else if (type === 'relation') {
38757
38758             // Update parentRels
38759             if (oldentity && entity) {
38760                 removed = lodash.difference(oldentity.members, entity.members);
38761                 added = lodash.difference(entity.members, oldentity);
38762             } else if (oldentity) {
38763                 removed = oldentity.members;
38764                 added = [];
38765             } else if (entity) {
38766                 removed = [];
38767                 added = entity.members;
38768             }
38769             for (i = 0; i < removed.length; i++) {
38770                 parentRels[removed[i].id] = lodash.without(parentRels[removed[i].id], oldentity.id);
38771             }
38772             for (i = 0; i < added.length; i++) {
38773                 rels = lodash.without(parentRels[added[i].id], entity.id);
38774                 rels.push(entity.id);
38775                 parentRels[added[i].id] = rels;
38776             }
38777         }
38778     },
38779
38780
38781     replace: function(entity) {
38782         if (this.entities[entity.id] === entity)
38783             return this;
38784
38785         return this.update(function() {
38786             this._updateCalculated(this.entities[entity.id], entity);
38787             this.entities[entity.id] = entity;
38788         });
38789     },
38790
38791
38792     remove: function(entity) {
38793         return this.update(function() {
38794             this._updateCalculated(entity, undefined);
38795             this.entities[entity.id] = undefined;
38796         });
38797     },
38798
38799
38800     revert: function(id) {
38801         var baseEntity = this.base().entities[id],
38802             headEntity = this.entities[id];
38803
38804         if (headEntity === baseEntity)
38805             return this;
38806
38807         return this.update(function() {
38808             this._updateCalculated(headEntity, baseEntity);
38809             delete this.entities[id];
38810         });
38811     },
38812
38813
38814     update: function() {
38815         var graph = this.frozen ? coreGraph$$1(this, true) : this;
38816
38817         for (var i = 0; i < arguments.length; i++) {
38818             arguments[i].call(graph, graph);
38819         }
38820
38821         if (this.frozen) graph.frozen = true;
38822
38823         return graph;
38824     },
38825
38826
38827     // Obliterates any existing entities
38828     load: function(entities) {
38829         var base = this.base();
38830         this.entities = Object.create(base.entities);
38831
38832         for (var i in entities) {
38833             this.entities[i] = entities[i];
38834             this._updateCalculated(base.entities[i], this.entities[i]);
38835         }
38836
38837         return this;
38838     }
38839 };
38840
38841 var index$10 = partialSort;
38842
38843 // Floyd-Rivest selection algorithm:
38844 // Rearrange items so that all items in the [left, k] range are smaller than all items in (k, right];
38845 // The k-th element will have the (k - left + 1)th smallest value in [left, right]
38846
38847 function partialSort(arr, k, left, right, compare) {
38848     left = left || 0;
38849     right = right || (arr.length - 1);
38850     compare = compare || defaultCompare;
38851
38852     while (right > left) {
38853         if (right - left > 600) {
38854             var n = right - left + 1;
38855             var m = k - left + 1;
38856             var z = Math.log(n);
38857             var s = 0.5 * Math.exp(2 * z / 3);
38858             var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
38859             var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
38860             var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
38861             partialSort(arr, k, newLeft, newRight, compare);
38862         }
38863
38864         var t = arr[k];
38865         var i = left;
38866         var j = right;
38867
38868         swap(arr, left, k);
38869         if (compare(arr[right], t) > 0) swap(arr, left, right);
38870
38871         while (i < j) {
38872             swap(arr, i, j);
38873             i++;
38874             j--;
38875             while (compare(arr[i], t) < 0) i++;
38876             while (compare(arr[j], t) > 0) j--;
38877         }
38878
38879         if (compare(arr[left], t) === 0) swap(arr, left, j);
38880         else {
38881             j++;
38882             swap(arr, j, right);
38883         }
38884
38885         if (j <= k) left = j + 1;
38886         if (k <= j) right = j - 1;
38887     }
38888 }
38889
38890 function swap(arr, i, j) {
38891     var tmp = arr[i];
38892     arr[i] = arr[j];
38893     arr[j] = tmp;
38894 }
38895
38896 function defaultCompare(a, b) {
38897     return a < b ? -1 : a > b ? 1 : 0;
38898 }
38899
38900 var index$9 = rbush;
38901
38902
38903
38904 function rbush(maxEntries, format) {
38905     if (!(this instanceof rbush)) return new rbush(maxEntries, format);
38906
38907     // max entries in a node is 9 by default; min node fill is 40% for best performance
38908     this._maxEntries = Math.max(4, maxEntries || 9);
38909     this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
38910
38911     if (format) {
38912         this._initFormat(format);
38913     }
38914
38915     this.clear();
38916 }
38917
38918 rbush.prototype = {
38919
38920     all: function () {
38921         return this._all(this.data, []);
38922     },
38923
38924     search: function (bbox) {
38925
38926         var node = this.data,
38927             result = [],
38928             toBBox = this.toBBox;
38929
38930         if (!intersects$1(bbox, node)) return result;
38931
38932         var nodesToSearch = [],
38933             i, len, child, childBBox;
38934
38935         while (node) {
38936             for (i = 0, len = node.children.length; i < len; i++) {
38937
38938                 child = node.children[i];
38939                 childBBox = node.leaf ? toBBox(child) : child;
38940
38941                 if (intersects$1(bbox, childBBox)) {
38942                     if (node.leaf) result.push(child);
38943                     else if (contains$2(bbox, childBBox)) this._all(child, result);
38944                     else nodesToSearch.push(child);
38945                 }
38946             }
38947             node = nodesToSearch.pop();
38948         }
38949
38950         return result;
38951     },
38952
38953     collides: function (bbox) {
38954
38955         var node = this.data,
38956             toBBox = this.toBBox;
38957
38958         if (!intersects$1(bbox, node)) return false;
38959
38960         var nodesToSearch = [],
38961             i, len, child, childBBox;
38962
38963         while (node) {
38964             for (i = 0, len = node.children.length; i < len; i++) {
38965
38966                 child = node.children[i];
38967                 childBBox = node.leaf ? toBBox(child) : child;
38968
38969                 if (intersects$1(bbox, childBBox)) {
38970                     if (node.leaf || contains$2(bbox, childBBox)) return true;
38971                     nodesToSearch.push(child);
38972                 }
38973             }
38974             node = nodesToSearch.pop();
38975         }
38976
38977         return false;
38978     },
38979
38980     load: function (data) {
38981         if (!(data && data.length)) return this;
38982
38983         if (data.length < this._minEntries) {
38984             for (var i = 0, len = data.length; i < len; i++) {
38985                 this.insert(data[i]);
38986             }
38987             return this;
38988         }
38989
38990         // recursively build the tree with the given data from stratch using OMT algorithm
38991         var node = this._build(data.slice(), 0, data.length - 1, 0);
38992
38993         if (!this.data.children.length) {
38994             // save as is if tree is empty
38995             this.data = node;
38996
38997         } else if (this.data.height === node.height) {
38998             // split root if trees have the same height
38999             this._splitRoot(this.data, node);
39000
39001         } else {
39002             if (this.data.height < node.height) {
39003                 // swap trees if inserted one is bigger
39004                 var tmpNode = this.data;
39005                 this.data = node;
39006                 node = tmpNode;
39007             }
39008
39009             // insert the small tree into the large tree at appropriate level
39010             this._insert(node, this.data.height - node.height - 1, true);
39011         }
39012
39013         return this;
39014     },
39015
39016     insert: function (item) {
39017         if (item) this._insert(item, this.data.height - 1);
39018         return this;
39019     },
39020
39021     clear: function () {
39022         this.data = createNode([]);
39023         return this;
39024     },
39025
39026     remove: function (item, equalsFn) {
39027         if (!item) return this;
39028
39029         var node = this.data,
39030             bbox = this.toBBox(item),
39031             path = [],
39032             indexes = [],
39033             i, parent, index, goingUp;
39034
39035         // depth-first iterative tree traversal
39036         while (node || path.length) {
39037
39038             if (!node) { // go up
39039                 node = path.pop();
39040                 parent = path[path.length - 1];
39041                 i = indexes.pop();
39042                 goingUp = true;
39043             }
39044
39045             if (node.leaf) { // check current node
39046                 index = findItem(item, node.children, equalsFn);
39047
39048                 if (index !== -1) {
39049                     // item found, remove the item and condense tree upwards
39050                     node.children.splice(index, 1);
39051                     path.push(node);
39052                     this._condense(path);
39053                     return this;
39054                 }
39055             }
39056
39057             if (!goingUp && !node.leaf && contains$2(node, bbox)) { // go down
39058                 path.push(node);
39059                 indexes.push(i);
39060                 i = 0;
39061                 parent = node;
39062                 node = node.children[0];
39063
39064             } else if (parent) { // go right
39065                 i++;
39066                 node = parent.children[i];
39067                 goingUp = false;
39068
39069             } else node = null; // nothing found
39070         }
39071
39072         return this;
39073     },
39074
39075     toBBox: function (item) { return item; },
39076
39077     compareMinX: compareNodeMinX,
39078     compareMinY: compareNodeMinY,
39079
39080     toJSON: function () { return this.data; },
39081
39082     fromJSON: function (data) {
39083         this.data = data;
39084         return this;
39085     },
39086
39087     _all: function (node, result) {
39088         var nodesToSearch = [];
39089         while (node) {
39090             if (node.leaf) result.push.apply(result, node.children);
39091             else nodesToSearch.push.apply(nodesToSearch, node.children);
39092
39093             node = nodesToSearch.pop();
39094         }
39095         return result;
39096     },
39097
39098     _build: function (items, left, right, height) {
39099
39100         var N = right - left + 1,
39101             M = this._maxEntries,
39102             node;
39103
39104         if (N <= M) {
39105             // reached leaf level; return leaf
39106             node = createNode(items.slice(left, right + 1));
39107             calcBBox(node, this.toBBox);
39108             return node;
39109         }
39110
39111         if (!height) {
39112             // target height of the bulk-loaded tree
39113             height = Math.ceil(Math.log(N) / Math.log(M));
39114
39115             // target number of root entries to maximize storage utilization
39116             M = Math.ceil(N / Math.pow(M, height - 1));
39117         }
39118
39119         node = createNode([]);
39120         node.leaf = false;
39121         node.height = height;
39122
39123         // split the items into M mostly square tiles
39124
39125         var N2 = Math.ceil(N / M),
39126             N1 = N2 * Math.ceil(Math.sqrt(M)),
39127             i, j, right2, right3;
39128
39129         multiSelect(items, left, right, N1, this.compareMinX);
39130
39131         for (i = left; i <= right; i += N1) {
39132
39133             right2 = Math.min(i + N1 - 1, right);
39134
39135             multiSelect(items, i, right2, N2, this.compareMinY);
39136
39137             for (j = i; j <= right2; j += N2) {
39138
39139                 right3 = Math.min(j + N2 - 1, right2);
39140
39141                 // pack each entry recursively
39142                 node.children.push(this._build(items, j, right3, height - 1));
39143             }
39144         }
39145
39146         calcBBox(node, this.toBBox);
39147
39148         return node;
39149     },
39150
39151     _chooseSubtree: function (bbox, node, level, path) {
39152
39153         var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
39154
39155         while (true) {
39156             path.push(node);
39157
39158             if (node.leaf || path.length - 1 === level) break;
39159
39160             minArea = minEnlargement = Infinity;
39161
39162             for (i = 0, len = node.children.length; i < len; i++) {
39163                 child = node.children[i];
39164                 area = bboxArea(child);
39165                 enlargement = enlargedArea(bbox, child) - area;
39166
39167                 // choose entry with the least area enlargement
39168                 if (enlargement < minEnlargement) {
39169                     minEnlargement = enlargement;
39170                     minArea = area < minArea ? area : minArea;
39171                     targetNode = child;
39172
39173                 } else if (enlargement === minEnlargement) {
39174                     // otherwise choose one with the smallest area
39175                     if (area < minArea) {
39176                         minArea = area;
39177                         targetNode = child;
39178                     }
39179                 }
39180             }
39181
39182             node = targetNode || node.children[0];
39183         }
39184
39185         return node;
39186     },
39187
39188     _insert: function (item, level, isNode) {
39189
39190         var toBBox = this.toBBox,
39191             bbox = isNode ? item : toBBox(item),
39192             insertPath = [];
39193
39194         // find the best node for accommodating the item, saving all nodes along the path too
39195         var node = this._chooseSubtree(bbox, this.data, level, insertPath);
39196
39197         // put the item into the node
39198         node.children.push(item);
39199         extend$1(node, bbox);
39200
39201         // split on node overflow; propagate upwards if necessary
39202         while (level >= 0) {
39203             if (insertPath[level].children.length > this._maxEntries) {
39204                 this._split(insertPath, level);
39205                 level--;
39206             } else break;
39207         }
39208
39209         // adjust bboxes along the insertion path
39210         this._adjustParentBBoxes(bbox, insertPath, level);
39211     },
39212
39213     // split overflowed node into two
39214     _split: function (insertPath, level) {
39215
39216         var node = insertPath[level],
39217             M = node.children.length,
39218             m = this._minEntries;
39219
39220         this._chooseSplitAxis(node, m, M);
39221
39222         var splitIndex = this._chooseSplitIndex(node, m, M);
39223
39224         var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
39225         newNode.height = node.height;
39226         newNode.leaf = node.leaf;
39227
39228         calcBBox(node, this.toBBox);
39229         calcBBox(newNode, this.toBBox);
39230
39231         if (level) insertPath[level - 1].children.push(newNode);
39232         else this._splitRoot(node, newNode);
39233     },
39234
39235     _splitRoot: function (node, newNode) {
39236         // split root node
39237         this.data = createNode([node, newNode]);
39238         this.data.height = node.height + 1;
39239         this.data.leaf = false;
39240         calcBBox(this.data, this.toBBox);
39241     },
39242
39243     _chooseSplitIndex: function (node, m, M) {
39244
39245         var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
39246
39247         minOverlap = minArea = Infinity;
39248
39249         for (i = m; i <= M - m; i++) {
39250             bbox1 = distBBox(node, 0, i, this.toBBox);
39251             bbox2 = distBBox(node, i, M, this.toBBox);
39252
39253             overlap = intersectionArea(bbox1, bbox2);
39254             area = bboxArea(bbox1) + bboxArea(bbox2);
39255
39256             // choose distribution with minimum overlap
39257             if (overlap < minOverlap) {
39258                 minOverlap = overlap;
39259                 index = i;
39260
39261                 minArea = area < minArea ? area : minArea;
39262
39263             } else if (overlap === minOverlap) {
39264                 // otherwise choose distribution with minimum area
39265                 if (area < minArea) {
39266                     minArea = area;
39267                     index = i;
39268                 }
39269             }
39270         }
39271
39272         return index;
39273     },
39274
39275     // sorts node children by the best axis for split
39276     _chooseSplitAxis: function (node, m, M) {
39277
39278         var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
39279             compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
39280             xMargin = this._allDistMargin(node, m, M, compareMinX),
39281             yMargin = this._allDistMargin(node, m, M, compareMinY);
39282
39283         // if total distributions margin value is minimal for x, sort by minX,
39284         // otherwise it's already sorted by minY
39285         if (xMargin < yMargin) node.children.sort(compareMinX);
39286     },
39287
39288     // total margin of all possible split distributions where each node is at least m full
39289     _allDistMargin: function (node, m, M, compare) {
39290
39291         node.children.sort(compare);
39292
39293         var toBBox = this.toBBox,
39294             leftBBox = distBBox(node, 0, m, toBBox),
39295             rightBBox = distBBox(node, M - m, M, toBBox),
39296             margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
39297             i, child;
39298
39299         for (i = m; i < M - m; i++) {
39300             child = node.children[i];
39301             extend$1(leftBBox, node.leaf ? toBBox(child) : child);
39302             margin += bboxMargin(leftBBox);
39303         }
39304
39305         for (i = M - m - 1; i >= m; i--) {
39306             child = node.children[i];
39307             extend$1(rightBBox, node.leaf ? toBBox(child) : child);
39308             margin += bboxMargin(rightBBox);
39309         }
39310
39311         return margin;
39312     },
39313
39314     _adjustParentBBoxes: function (bbox, path, level) {
39315         // adjust bboxes along the given tree path
39316         for (var i = level; i >= 0; i--) {
39317             extend$1(path[i], bbox);
39318         }
39319     },
39320
39321     _condense: function (path) {
39322         // go through the path, removing empty nodes and updating bboxes
39323         for (var i = path.length - 1, siblings; i >= 0; i--) {
39324             if (path[i].children.length === 0) {
39325                 if (i > 0) {
39326                     siblings = path[i - 1].children;
39327                     siblings.splice(siblings.indexOf(path[i]), 1);
39328
39329                 } else this.clear();
39330
39331             } else calcBBox(path[i], this.toBBox);
39332         }
39333     },
39334
39335     _initFormat: function (format) {
39336         // data format (minX, minY, maxX, maxY accessors)
39337
39338         // uses eval-type function compilation instead of just accepting a toBBox function
39339         // because the algorithms are very sensitive to sorting functions performance,
39340         // so they should be dead simple and without inner calls
39341
39342         var compareArr = ['return a', ' - b', ';'];
39343
39344         this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
39345         this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
39346
39347         this.toBBox = new Function('a',
39348             'return {minX: a' + format[0] +
39349             ', minY: a' + format[1] +
39350             ', maxX: a' + format[2] +
39351             ', maxY: a' + format[3] + '};');
39352     }
39353 };
39354
39355 function findItem(item, items, equalsFn) {
39356     if (!equalsFn) return items.indexOf(item);
39357
39358     for (var i = 0; i < items.length; i++) {
39359         if (equalsFn(item, items[i])) return i;
39360     }
39361     return -1;
39362 }
39363
39364 // calculate node's bbox from bboxes of its children
39365 function calcBBox(node, toBBox) {
39366     distBBox(node, 0, node.children.length, toBBox, node);
39367 }
39368
39369 // min bounding rectangle of node children from k to p-1
39370 function distBBox(node, k, p, toBBox, destNode) {
39371     if (!destNode) destNode = createNode(null);
39372     destNode.minX = Infinity;
39373     destNode.minY = Infinity;
39374     destNode.maxX = -Infinity;
39375     destNode.maxY = -Infinity;
39376
39377     for (var i = k, child; i < p; i++) {
39378         child = node.children[i];
39379         extend$1(destNode, node.leaf ? toBBox(child) : child);
39380     }
39381
39382     return destNode;
39383 }
39384
39385 function extend$1(a, b) {
39386     a.minX = Math.min(a.minX, b.minX);
39387     a.minY = Math.min(a.minY, b.minY);
39388     a.maxX = Math.max(a.maxX, b.maxX);
39389     a.maxY = Math.max(a.maxY, b.maxY);
39390     return a;
39391 }
39392
39393 function compareNodeMinX(a, b) { return a.minX - b.minX; }
39394 function compareNodeMinY(a, b) { return a.minY - b.minY; }
39395
39396 function bboxArea(a)   { return (a.maxX - a.minX) * (a.maxY - a.minY); }
39397 function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
39398
39399 function enlargedArea(a, b) {
39400     return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
39401            (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
39402 }
39403
39404 function intersectionArea(a, b) {
39405     var minX = Math.max(a.minX, b.minX),
39406         minY = Math.max(a.minY, b.minY),
39407         maxX = Math.min(a.maxX, b.maxX),
39408         maxY = Math.min(a.maxY, b.maxY);
39409
39410     return Math.max(0, maxX - minX) *
39411            Math.max(0, maxY - minY);
39412 }
39413
39414 function contains$2(a, b) {
39415     return a.minX <= b.minX &&
39416            a.minY <= b.minY &&
39417            b.maxX <= a.maxX &&
39418            b.maxY <= a.maxY;
39419 }
39420
39421 function intersects$1(a, b) {
39422     return b.minX <= a.maxX &&
39423            b.minY <= a.maxY &&
39424            b.maxX >= a.minX &&
39425            b.maxY >= a.minY;
39426 }
39427
39428 function createNode(children) {
39429     return {
39430         children: children,
39431         height: 1,
39432         leaf: true,
39433         minX: Infinity,
39434         minY: Infinity,
39435         maxX: -Infinity,
39436         maxY: -Infinity
39437     };
39438 }
39439
39440 // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
39441 // combines selection algorithm with binary divide & conquer approach
39442
39443 function multiSelect(arr, left, right, n, compare) {
39444     var stack = [left, right],
39445         mid;
39446
39447     while (stack.length) {
39448         right = stack.pop();
39449         left = stack.pop();
39450
39451         if (right - left <= n) continue;
39452
39453         mid = left + Math.ceil((right - left) / n / 2) * n;
39454         index$10(arr, mid, left, right, compare);
39455
39456         stack.push(left, mid, mid, right);
39457     }
39458 }
39459
39460 function coreTree(head) {
39461     var rtree = index$9(),
39462         bboxes = {},
39463         tree = {};
39464
39465
39466     function entityBBox(entity) {
39467         var bbox = entity.extent(head).bbox();
39468         bbox.id = entity.id;
39469         bboxes[entity.id] = bbox;
39470         return bbox;
39471     }
39472
39473
39474     function updateParents(entity, insertions, memo) {
39475         head.parentWays(entity).forEach(function(way) {
39476             if (bboxes[way.id]) {
39477                 rtree.remove(bboxes[way.id]);
39478                 insertions[way.id] = way;
39479             }
39480             updateParents(way, insertions, memo);
39481         });
39482
39483         head.parentRelations(entity).forEach(function(relation) {
39484             if (memo[entity.id]) return;
39485             memo[entity.id] = true;
39486             if (bboxes[relation.id]) {
39487                 rtree.remove(bboxes[relation.id]);
39488                 insertions[relation.id] = relation;
39489             }
39490             updateParents(relation, insertions, memo);
39491         });
39492     }
39493
39494
39495     tree.rebase = function(entities, force) {
39496         var insertions = {};
39497
39498         for (var i = 0; i < entities.length; i++) {
39499             var entity = entities[i];
39500
39501             if (!entity.visible)
39502                 continue;
39503
39504             if (head.entities.hasOwnProperty(entity.id) || bboxes[entity.id]) {
39505                 if (!force) {
39506                     continue;
39507                 } else if (bboxes[entity.id]) {
39508                     rtree.remove(bboxes[entity.id]);
39509                 }
39510             }
39511
39512             insertions[entity.id] = entity;
39513             updateParents(entity, insertions, {});
39514         }
39515
39516         rtree.load(lodash.map(insertions, entityBBox));
39517
39518         return tree;
39519     };
39520
39521
39522     tree.intersects = function(extent, graph) {
39523         if (graph !== head) {
39524             var diff = coreDifference(head, graph),
39525                 insertions = {};
39526
39527             head = graph;
39528
39529             diff.deleted().forEach(function(entity) {
39530                 rtree.remove(bboxes[entity.id]);
39531                 delete bboxes[entity.id];
39532             });
39533
39534             diff.modified().forEach(function(entity) {
39535                 rtree.remove(bboxes[entity.id]);
39536                 insertions[entity.id] = entity;
39537                 updateParents(entity, insertions, {});
39538             });
39539
39540             diff.created().forEach(function(entity) {
39541                 insertions[entity.id] = entity;
39542             });
39543
39544             rtree.load(lodash.map(insertions, entityBBox));
39545         }
39546
39547         return rtree.search(extent.bbox()).map(function(bbox) {
39548             return head.entity(bbox.id);
39549         });
39550     };
39551
39552
39553     return tree;
39554 }
39555
39556 /*
39557  * This code is licensed under the MIT license.
39558  *
39559  * Copyright © 2013, iD authors.
39560  *
39561  * Portions copyright © 2011, Keith Cirkel
39562  * See https://github.com/keithamus/jwerty
39563  *
39564  */
39565 function d3keybinding(namespace$$1) {
39566     var bindings = [];
39567
39568     function matches(binding, event$$1) {
39569         for (var p in binding.event) {
39570             if (event$$1[p] !== binding.event[p])
39571                 return false;
39572         }
39573         return true;
39574     }
39575
39576     function testBindings(isCapturing) {
39577         for (var i = 0; i < bindings.length; i++) {
39578             var binding = bindings[i];
39579
39580             if (!!binding.capture === isCapturing && matches(binding, event)) {
39581                 binding.callback();
39582             }
39583         }
39584     }
39585
39586     function capture() {
39587         testBindings(true);
39588     }
39589
39590     function bubble() {
39591         var tagName = select(event.target).node().tagName;
39592         if (tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA') {
39593             return;
39594         }
39595         testBindings(false);
39596     }
39597
39598     function keybinding(selection$$1) {
39599         selection$$1 = selection$$1 || select(document);
39600         selection$$1.on('keydown.capture' + namespace$$1, capture, true);
39601         selection$$1.on('keydown.bubble' + namespace$$1, bubble, false);
39602         return keybinding;
39603     }
39604
39605     keybinding.off = function(selection$$1) {
39606         bindings = [];
39607         selection$$1 = selection$$1 || select(document);
39608         selection$$1.on('keydown.capture' + namespace$$1, null);
39609         selection$$1.on('keydown.bubble' + namespace$$1, null);
39610         return keybinding;
39611     };
39612
39613     keybinding.on = function(codes, callback, capture) {
39614         var arr = [].concat(codes);
39615         for (var i = 0; i < arr.length; i++) {
39616             var code = arr[i];
39617             var binding = {
39618                 event: {
39619                     keyCode: 0,
39620                     shiftKey: false,
39621                     ctrlKey: false,
39622                     altKey: false,
39623                     metaKey: false
39624                 },
39625                 capture: capture,
39626                 callback: callback
39627             };
39628
39629             code = code.toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
39630
39631             for (var j = 0; j < code.length; j++) {
39632                 // Normalise matching errors
39633                 if (code[j] === '++') code[i] = '+';
39634
39635                 if (code[j] in d3keybinding.modifierCodes) {
39636                     binding.event[d3keybinding.modifierProperties[d3keybinding.modifierCodes[code[j]]]] = true;
39637                 } else if (code[j] in d3keybinding.keyCodes) {
39638                     binding.event.keyCode = d3keybinding.keyCodes[code[j]];
39639                 }
39640             }
39641
39642             bindings.push(binding);
39643         }
39644
39645         return keybinding;
39646     };
39647
39648     return keybinding;
39649 }
39650
39651
39652 d3keybinding.modifierCodes = {
39653     // Shift key, ⇧
39654     '⇧': 16, shift: 16,
39655     // CTRL key, on Mac: ⌃
39656     '⌃': 17, ctrl: 17,
39657     // ALT key, on Mac: ⌥ (Alt)
39658     '⌥': 18, alt: 18, option: 18,
39659     // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
39660     '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91
39661 };
39662
39663 d3keybinding.modifierProperties = {
39664     16: 'shiftKey',
39665     17: 'ctrlKey',
39666     18: 'altKey',
39667     91: 'metaKey'
39668 };
39669
39670 d3keybinding.keyCodes = {
39671     // Backspace key, on Mac: ⌫ (Backspace)
39672     '⌫': 8, backspace: 8,
39673     // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
39674     '⇥': 9, '⇆': 9, tab: 9,
39675     // Return key, ↩
39676     '↩': 13, 'return': 13, enter: 13, '⌅': 13,
39677     // Pause/Break key
39678     'pause': 19, 'pause-break': 19,
39679     // Caps Lock key, ⇪
39680     '⇪': 20, caps: 20, 'caps-lock': 20,
39681     // Escape key, on Mac: ⎋, on Windows: Esc
39682     '⎋': 27, escape: 27, esc: 27,
39683     // Space key
39684     space: 32,
39685     // Page-Up key, or pgup, on Mac: ↖
39686     '↖': 33, pgup: 33, 'page-up': 33,
39687     // Page-Down key, or pgdown, on Mac: ↘
39688     '↘': 34, pgdown: 34, 'page-down': 34,
39689     // END key, on Mac: ⇟
39690     '⇟': 35, end: 35,
39691     // HOME key, on Mac: ⇞
39692     '⇞': 36, home: 36,
39693     // Insert key, or ins
39694     ins: 45, insert: 45,
39695     // Delete key, on Mac: ⌦ (Delete)
39696     '⌦': 46, del: 46, 'delete': 46,
39697     // Left Arrow Key, or ←
39698     '←': 37, left: 37, 'arrow-left': 37,
39699     // Up Arrow Key, or ↑
39700     '↑': 38, up: 38, 'arrow-up': 38,
39701     // Right Arrow Key, or →
39702     '→': 39, right: 39, 'arrow-right': 39,
39703     // Up Arrow Key, or ↓
39704     '↓': 40, down: 40, 'arrow-down': 40,
39705     // odities, printing characters that come out wrong:
39706     // Firefox Equals
39707     'ffequals': 61,
39708     // Num-Multiply, or *
39709     '*': 106, star: 106, asterisk: 106, multiply: 106,
39710     // Num-Plus or +
39711     '+': 107, 'plus': 107,
39712     // Num-Subtract, or -
39713     '-': 109, subtract: 109,
39714     // Firefox Plus
39715     'ffplus': 171,
39716     // Firefox Minus
39717     'ffminus': 173,
39718     // Semicolon
39719     ';': 186, semicolon: 186,
39720     // = or equals
39721     '=': 187, 'equals': 187,
39722     // Comma, or ,
39723     ',': 188, comma: 188,
39724     // Dash / Underscore key
39725     'dash': 189,
39726     // Period, or ., or full-stop
39727     '.': 190, period: 190, 'full-stop': 190,
39728     // Slash, or /, or forward-slash
39729     '/': 191, slash: 191, 'forward-slash': 191,
39730     // Tick, or `, or back-quote
39731     '`': 192, tick: 192, 'back-quote': 192,
39732     // Open bracket, or [
39733     '[': 219, 'open-bracket': 219,
39734     // Back slash, or \
39735     '\\': 220, 'back-slash': 220,
39736     // Close backet, or ]
39737     ']': 221, 'close-bracket': 221,
39738     // Apostrophe, or Quote, or '
39739     '\'': 222, quote: 222, apostrophe: 222
39740 };
39741
39742 // NUMPAD 0-9
39743 var i$1 = 95;
39744 var n = 0;
39745 while (++i$1 < 106) {
39746     d3keybinding.keyCodes['num-' + n] = i$1;
39747     ++n;
39748 }
39749
39750 // 0-9
39751 i$1 = 47; n = 0;
39752 while (++i$1 < 58) {
39753     d3keybinding.keyCodes[n] = i$1;
39754     ++n;
39755 }
39756
39757 // F1-F25
39758 i$1 = 111; n = 1;
39759 while (++i$1 < 136) {
39760     d3keybinding.keyCodes['f' + n] = i$1;
39761     ++n;
39762 }
39763
39764 // a-z
39765 i$1 = 64;
39766 while (++i$1 < 91) {
39767     d3keybinding.keyCodes[String.fromCharCode(i$1).toLowerCase()] = i$1;
39768 }
39769
39770 function tooltip() {
39771   var tooltip = function(selection$$1) {
39772       selection$$1.each(setup);
39773     },
39774     animation = utilFunctor(false),
39775     html$$1 = utilFunctor(false),
39776     title = function() {
39777       var title = this.getAttribute('data-original-title');
39778       if (title) {
39779         return title;
39780       } else {
39781         title = this.getAttribute('title');
39782         this.removeAttribute('title');
39783         this.setAttribute('data-original-title', title);
39784       }
39785       return title;
39786     },
39787     over = 'mouseenter.tooltip',
39788     out = 'mouseleave.tooltip',
39789     placement = utilFunctor('top');
39790
39791
39792   tooltip.title = function(_) {
39793     if (arguments.length) {
39794       title = utilFunctor(_);
39795       return tooltip;
39796     } else {
39797       return title;
39798     }
39799   };
39800
39801
39802   tooltip.html = function(_) {
39803     if (arguments.length) {
39804       html$$1 = utilFunctor(_);
39805       return tooltip;
39806     } else {
39807       return html$$1;
39808     }
39809   };
39810
39811
39812   tooltip.placement = function(_) {
39813     if (arguments.length) {
39814       placement = utilFunctor(_);
39815       return tooltip;
39816     } else {
39817       return placement;
39818     }
39819   };
39820
39821
39822   tooltip.show = function(selection$$1) {
39823     selection$$1.each(show);
39824   };
39825
39826
39827   tooltip.hide = function(selection$$1) {
39828     selection$$1.each(hide);
39829   };
39830
39831
39832   tooltip.toggle = function(selection$$1) {
39833     selection$$1.each(toggle);
39834   };
39835
39836
39837   tooltip.destroy = function(selection$$1) {
39838     selection$$1
39839       .on(over, null)
39840       .on(out, null)
39841       .attr('title', function() {
39842         return this.getAttribute('data-original-title') || this.getAttribute('title');
39843       })
39844       .attr('data-original-title', null)
39845       .selectAll('.tooltip')
39846       .remove();
39847   };
39848
39849
39850   function setup() {
39851     var root = select(this),
39852         animate = animation.apply(this, arguments),
39853         tip = root.selectAll('.tooltip').data([0]);
39854
39855     var enter = tip.enter()
39856       .append('div')
39857       .attr('class', 'tooltip');
39858
39859     enter
39860       .append('div')
39861       .attr('class', 'tooltip-arrow');
39862
39863     enter
39864       .append('div')
39865       .attr('class', 'tooltip-inner');
39866
39867     tip = enter
39868       .merge(tip);
39869
39870     if (animate) {
39871       tip.classed('fade', true);
39872     }
39873
39874     var place = placement.apply(this, arguments);
39875     tip.classed(place, true);
39876
39877     root.on(over, show);
39878     root.on(out, hide);
39879   }
39880
39881
39882   function show() {
39883     var root = select(this),
39884       content = title.apply(this, arguments),
39885       tip = root.selectAll('.tooltip')
39886         .classed('in', true),
39887       markup = html$$1.apply(this, arguments);
39888
39889     tip.selectAll('.tooltip-inner')[markup ? 'html' : 'text'](content);
39890     var place = placement.apply(this, arguments),
39891       outer = getPosition(root.node()),
39892       inner = getPosition(tip.node()),
39893       pos;
39894
39895     switch (place) {
39896       case 'top':
39897         pos = {x: outer.x + (outer.w - inner.w) / 2, y: outer.y - inner.h};
39898         break;
39899       case 'right':
39900         pos = {x: outer.x + outer.w, y: outer.y + (outer.h - inner.h) / 2};
39901         break;
39902       case 'left':
39903         pos = {x: outer.x - inner.w, y: outer.y + (outer.h - inner.h) / 2};
39904         break;
39905       case 'bottom':
39906         pos = {x: Math.max(0, outer.x + (outer.w - inner.w) / 2), y: outer.y + outer.h};
39907         break;
39908     }
39909
39910     if (pos) {
39911       tip.style('left', ~~pos.x + 'px').style('top', ~~pos.y + 'px');
39912     } else {
39913       tip.style('left', null).style('top', null);
39914     }
39915
39916     this.tooltipVisible = true;
39917   }
39918
39919
39920   function hide() {
39921     select(this).selectAll('.tooltip')
39922       .classed('in', false);
39923
39924     this.tooltipVisible = false;
39925   }
39926
39927
39928   function toggle() {
39929     if (this.tooltipVisible) {
39930       hide.apply(this, arguments);
39931     } else {
39932       show.apply(this, arguments);
39933     }
39934   }
39935
39936   return tooltip;
39937 }
39938
39939
39940 function getPosition(node) {
39941   var mode = select(node).style('position');
39942   if (mode === 'absolute' || mode === 'static') {
39943     return {
39944       x: node.offsetLeft,
39945       y: node.offsetTop,
39946       w: node.offsetWidth,
39947       h: node.offsetHeight
39948     };
39949   } else {
39950     return {
39951       x: 0,
39952       y: 0,
39953       w: node.offsetWidth,
39954       h: node.offsetHeight
39955     };
39956   }
39957 }
39958
39959 function svgAreas$$1(projection, context) {
39960     // Patterns only work in Firefox when set directly on element.
39961     // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
39962     var patterns = {
39963         beach: 'beach',
39964         cemetery: 'cemetery',
39965         construction: 'construction',
39966         farm: 'farmland',
39967         farmland: 'farmland',
39968         grave_yard: 'cemetery',
39969         meadow: 'meadow',
39970         military: 'construction',
39971         orchard: 'orchard',
39972         sand: 'beach',
39973         scrub: 'scrub',
39974         wetland: 'wetland',
39975     };
39976
39977     var patternKeys = ['landuse', 'natural', 'amenity'];
39978
39979
39980     function setPattern(d) {
39981         for (var i = 0; i < patternKeys.length; i++) {
39982             if (d.tags.building && d.tags.building !== 'no') continue;
39983
39984             if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
39985                 this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
39986                 return;
39987             }
39988         }
39989         this.style.fill = this.style.stroke = '';
39990     }
39991
39992
39993     return function drawAreas(selection$$1, graph, entities, filter) {
39994         var path$$1 = svgPath(projection, graph, true),
39995             areas = {},
39996             multipolygon;
39997
39998         for (var i = 0; i < entities.length; i++) {
39999             var entity = entities[i];
40000             if (entity.geometry(graph) !== 'area') continue;
40001
40002             multipolygon = osmIsSimpleMultipolygonOuterMember(entity, graph);
40003             if (multipolygon) {
40004                 areas[multipolygon.id] = {
40005                     entity: multipolygon.mergeTags(entity.tags),
40006                     area: Math.abs(entity.area(graph))
40007                 };
40008             } else if (!areas[entity.id]) {
40009                 areas[entity.id] = {
40010                     entity: entity,
40011                     area: Math.abs(entity.area(graph))
40012                 };
40013             }
40014         }
40015
40016         areas = values(areas).filter(function hasPath(a) { return path$$1(a.entity); });
40017         areas.sort(function areaSort(a, b) { return b.area - a.area; });
40018         areas = lodash.map(areas, 'entity');
40019
40020         var strokes = areas.filter(function(area$$1) {
40021             return area$$1.type === 'way';
40022         });
40023
40024         var data = {
40025             clip: areas,
40026             shadow: strokes,
40027             stroke: strokes,
40028             fill: areas
40029         };
40030
40031         var clipPaths = context.surface().selectAll('defs').selectAll('.clipPath')
40032            .filter(filter)
40033            .data(data.clip, osmEntity$$1.key);
40034
40035         clipPaths.exit()
40036            .remove();
40037
40038         var clipPathsEnter = clipPaths.enter()
40039            .append('clipPath')
40040            .attr('class', 'clipPath')
40041            .attr('id', function(entity) { return entity.id + '-clippath'; });
40042
40043         clipPathsEnter
40044            .append('path');
40045
40046         clipPaths.merge(clipPathsEnter)
40047            .selectAll('path')
40048            .attr('d', path$$1);
40049
40050
40051         var layer = selection$$1.selectAll('.layer-areas');
40052
40053         var areagroup = layer
40054             .selectAll('g.areagroup')
40055             .data(['fill', 'shadow', 'stroke']);
40056
40057         areagroup = areagroup.enter()
40058             .append('g')
40059             .attr('class', function(d) { return 'areagroup area-' + d; })
40060             .merge(areagroup);
40061
40062         var paths = areagroup
40063             .selectAll('path')
40064             .filter(filter)
40065             .data(function(layer) { return data[layer]; }, osmEntity$$1.key);
40066
40067         paths.exit()
40068             .remove();
40069
40070         var fills = selection$$1.selectAll('.area-fill path.area').nodes();
40071
40072         var bisect$$1 = bisector(function(node) {
40073             return -node.__data__.area(graph);
40074         }).left;
40075
40076         function sortedByArea(entity) {
40077             if (this._parent.__data__ === 'fill') {
40078                 return fills[bisect$$1(fills, -entity.area(graph))];
40079             }
40080         }
40081
40082         paths = paths.enter()
40083             .insert('path', sortedByArea)
40084             .merge(paths)
40085             .each(function(entity) {
40086                 var layer = this.parentNode.__data__;
40087
40088                 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
40089
40090                 if (layer === 'fill') {
40091                     this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
40092                     setPattern.apply(this, arguments);
40093                 }
40094             })
40095             .call(svgTagClasses())
40096             .attr('d', path$$1);
40097     };
40098 }
40099
40100 function svgDebug(projection, context) {
40101
40102     function multipolygons(imagery) {
40103         return imagery.map(function(data$$1) {
40104             return {
40105                 type: 'MultiPolygon',
40106                 coordinates: [ data$$1.polygon ]
40107             };
40108         });
40109     }
40110
40111     function drawDebug(selection$$1) {
40112         var showsTile = context.getDebug('tile'),
40113             showsCollision = context.getDebug('collision'),
40114             showsImagery = context.getDebug('imagery'),
40115             showsImperial = context.getDebug('imperial'),
40116             showsDriveLeft = context.getDebug('driveLeft'),
40117             path$$1 = index$4(projection);
40118
40119
40120         var debugData = [];
40121         if (showsTile) {
40122             debugData.push({ class: 'red', label: 'tile' });
40123         }
40124         if (showsCollision) {
40125             debugData.push({ class: 'yellow', label: 'collision' });
40126         }
40127         if (showsImagery) {
40128             debugData.push({ class: 'orange', label: 'imagery' });
40129         }
40130         if (showsImperial) {
40131             debugData.push({ class: 'cyan', label: 'imperial' });
40132         }
40133         if (showsDriveLeft) {
40134             debugData.push({ class: 'green', label: 'driveLeft' });
40135         }
40136
40137
40138         var legend = select('#content')
40139             .selectAll('.debug-legend')
40140             .data(debugData.length ? [0] : []);
40141
40142         legend.exit()
40143             .remove();
40144
40145         legend = legend.enter()
40146             .append('div')
40147             .attr('class', 'fillD debug-legend')
40148             .merge(legend);
40149
40150
40151         var legendItems = legend.selectAll('.debug-legend-item')
40152             .data(debugData, function(d) { return d.label; });
40153
40154         legendItems.exit()
40155             .remove();
40156
40157         legendItems.enter()
40158             .append('span')
40159             .attr('class', function(d) { return 'debug-legend-item ' + d.class; })
40160             .text(function(d) { return d.label; });
40161
40162
40163         var layer = selection$$1.selectAll('.layer-debug')
40164             .data(showsImagery || showsImperial || showsDriveLeft ? [0] : []);
40165
40166         layer.exit()
40167             .remove();
40168
40169         layer = layer.enter()
40170             .append('g')
40171             .attr('class', 'layer-debug')
40172             .merge(layer);
40173
40174
40175         var extent$$1 = context.map().extent(),
40176             dataImagery = data.imagery || [],
40177             availableImagery = showsImagery && multipolygons(dataImagery.filter(function(source) {
40178                 if (!source.polygon) return false;
40179                 return source.polygon.some(function(polygon) {
40180                     return geoPolygonIntersectsPolygon(polygon, extent$$1, true);
40181                 });
40182             }));
40183
40184         var imagery = layer.selectAll('path.debug-imagery')
40185             .data(showsImagery ? availableImagery : []);
40186
40187         imagery.exit()
40188             .remove();
40189
40190         imagery.enter()
40191             .append('path')
40192             .attr('class', 'debug-imagery debug orange');
40193
40194
40195         var imperial = layer
40196             .selectAll('path.debug-imperial')
40197             .data(showsImperial ? [dataImperial] : []);
40198
40199         imperial.exit()
40200             .remove();
40201
40202         imperial.enter()
40203             .append('path')
40204             .attr('class', 'debug-imperial debug cyan');
40205
40206
40207         var driveLeft = layer
40208             .selectAll('path.debug-drive-left')
40209             .data(showsDriveLeft ? [dataDriveLeft] : []);
40210
40211         driveLeft.exit()
40212             .remove();
40213
40214         driveLeft.enter()
40215             .append('path')
40216             .attr('class', 'debug-drive-left debug green');
40217
40218
40219         // update
40220         layer.selectAll('path')
40221             .attr('d', path$$1);
40222     }
40223
40224
40225     // This looks strange because `enabled` methods on other layers are
40226     // chainable getter/setters, and this one is just a getter.
40227     drawDebug.enabled = function() {
40228         if (!arguments.length) {
40229             return context.getDebug('tile') ||
40230                 context.getDebug('collision') ||
40231                 context.getDebug('imagery') ||
40232                 context.getDebug('imperial') ||
40233                 context.getDebug('driveLeft');
40234         } else {
40235             return this;
40236         }
40237     };
40238
40239
40240     return drawDebug;
40241 }
40242
40243 /*
40244     A standalone SVG element that contains only a `defs` sub-element. To be
40245     used once globally, since defs IDs must be unique within a document.
40246 */
40247 function svgDefs(context) {
40248
40249     function SVGSpriteDefinition(id, href) {
40250         return function(defs) {
40251             request(href)
40252                 .mimeType('image/svg+xml')
40253                 .response(function(xhr) { return xhr.responseXML; })
40254                 .get(function(err, svg) {
40255                     if (err) return;
40256                     defs.node().appendChild(
40257                         select(svg.documentElement).attr('id', id).node()
40258                     );
40259                 });
40260         };
40261     }
40262
40263
40264     return function drawDefs(selection$$1) {
40265         var defs = selection$$1.append('defs');
40266
40267         // marker
40268         defs.append('marker')
40269             .attr('id', 'oneway-marker')
40270             .attr('viewBox', '0 0 10 10')
40271             .attr('refY', 2.5)
40272             .attr('refX', 5)
40273             .attr('markerWidth', 2)
40274             .attr('markerHeight', 2)
40275             .attr('markerUnits', 'strokeWidth')
40276             .attr('orient', 'auto')
40277
40278             .append('path')
40279             .attr('class', 'oneway')
40280             .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')
40281             .attr('stroke', 'none')
40282             .attr('fill', '#000')
40283             .attr('opacity', '0.75');
40284
40285         // patterns
40286         var patterns = defs.selectAll('pattern')
40287             .data([
40288                 // pattern name, pattern image name
40289                 ['wetland', 'wetland'],
40290                 ['construction', 'construction'],
40291                 ['cemetery', 'cemetery'],
40292                 ['orchard', 'orchard'],
40293                 ['farmland', 'farmland'],
40294                 ['beach', 'dots'],
40295                 ['scrub', 'dots'],
40296                 ['meadow', 'dots']
40297             ])
40298             .enter()
40299             .append('pattern')
40300             .attr('id', function (d) {
40301                 return 'pattern-' + d[0];
40302             })
40303             .attr('width', 32)
40304             .attr('height', 32)
40305             .attr('patternUnits', 'userSpaceOnUse');
40306
40307         patterns.append('rect')
40308             .attr('x', 0)
40309             .attr('y', 0)
40310             .attr('width', 32)
40311             .attr('height', 32)
40312             .attr('class', function (d) {
40313                     return 'pattern-color-' + d[0];
40314             });
40315
40316         patterns.append('image')
40317             .attr('x', 0)
40318             .attr('y', 0)
40319             .attr('width', 32)
40320             .attr('height', 32)
40321             .attr('xlink:href', function (d) {
40322                 return context.imagePath('pattern/' + d[1] + '.png');
40323             });
40324
40325         // clip paths
40326         defs.selectAll()
40327             .data([12, 18, 20, 32, 45])
40328             .enter()
40329             .append('clipPath')
40330             .attr('id', function (d) {
40331                 return 'clip-square-' + d;
40332             })
40333             .append('rect')
40334             .attr('x', 0)
40335             .attr('y', 0)
40336             .attr('width', function (d) {
40337                 return d;
40338             })
40339             .attr('height', function (d) {
40340                 return d;
40341             });
40342
40343         defs.call(SVGSpriteDefinition(
40344             'iD-sprite',
40345             context.imagePath('iD-sprite.svg')));
40346
40347         defs.call(SVGSpriteDefinition(
40348             'maki-sprite',
40349             context.imagePath('maki-sprite.svg')));
40350     };
40351 }
40352
40353 //[4]           NameStartChar      ::=          ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
40354 //[4a]          NameChar           ::=          NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
40355 //[5]           Name       ::=          NameStartChar (NameChar)*
40356 var nameStartChar = /[A-Z_a-z\xC0-\xD6\xD8-\xF6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/;//\u10000-\uEFFFF
40357 var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
40358 var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$');
40359 //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
40360 //var handlers = 'resolveEntity,getExternalSubset,characters,endDocument,endElement,endPrefixMapping,ignorableWhitespace,processingInstruction,setDocumentLocator,skippedEntity,startDocument,startElement,startPrefixMapping,notationDecl,unparsedEntityDecl,error,fatalError,warning,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,comment,endCDATA,endDTD,endEntity,startCDATA,startDTD,startEntity'.split(',')
40361
40362 //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
40363 //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
40364 var S_TAG = 0;//tag name offerring
40365 var S_ATTR = 1;//attr name offerring 
40366 var S_ATTR_SPACE=2;//attr name end and space offer
40367 var S_EQ = 3;//=space?
40368 var S_ATTR_NOQUOT_VALUE = 4;//attr value(no quot value only)
40369 var S_ATTR_END = 5;//attr value end and no space(quot end)
40370 var S_TAG_SPACE = 6;//(attr value end || tag end ) && (space offer)
40371 var S_TAG_CLOSE = 7;//closed el<el />
40372
40373 function XMLReader(){
40374         
40375 }
40376
40377 XMLReader.prototype = {
40378         parse:function(source,defaultNSMap,entityMap){
40379                 var domBuilder = this.domBuilder;
40380                 domBuilder.startDocument();
40381                 _copy(defaultNSMap ,defaultNSMap = {});
40382                 parse(source,defaultNSMap,entityMap,
40383                                 domBuilder,this.errorHandler);
40384                 domBuilder.endDocument();
40385         }
40386 };
40387 function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
40388         function fixedFromCharCode(code) {
40389                 // String.prototype.fromCharCode does not supports
40390                 // > 2 bytes unicode chars directly
40391                 if (code > 0xffff) {
40392                         code -= 0x10000;
40393                         var surrogate1 = 0xd800 + (code >> 10)
40394                                 , surrogate2 = 0xdc00 + (code & 0x3ff);
40395
40396                         return String.fromCharCode(surrogate1, surrogate2);
40397                 } else {
40398                         return String.fromCharCode(code);
40399                 }
40400         }
40401         function entityReplacer(a){
40402                 var k = a.slice(1,-1);
40403                 if(k in entityMap){
40404                         return entityMap[k]; 
40405                 }else if(k.charAt(0) === '#'){
40406                         return fixedFromCharCode(parseInt(k.substr(1).replace('x','0x')))
40407                 }else{
40408                         errorHandler.error('entity not found:'+a);
40409                         return a;
40410                 }
40411         }
40412         function appendText(end){//has some bugs
40413                 if(end>start){
40414                         var xt = source.substring(start,end).replace(/&#?\w+;/g,entityReplacer);
40415                         locator&&position(start);
40416                         domBuilder.characters(xt,0,end-start);
40417                         start = end;
40418                 }
40419         }
40420         function position(p,m){
40421                 while(p>=lineEnd && (m = linePattern.exec(source))){
40422                         lineStart = m.index;
40423                         lineEnd = lineStart + m[0].length;
40424                         locator.lineNumber++;
40425                         //console.log('line++:',locator,startPos,endPos)
40426                 }
40427                 locator.columnNumber = p-lineStart+1;
40428         }
40429         var lineStart = 0;
40430         var lineEnd = 0;
40431         var linePattern = /.*(?:\r\n?|\n)|.*$/g;
40432         var locator = domBuilder.locator;
40433         
40434         var parseStack = [{currentNSMap:defaultNSMapCopy}];
40435         var closeMap = {};
40436         var start = 0;
40437         while(true){
40438                 try{
40439                         var tagStart = source.indexOf('<',start);
40440                         if(tagStart<0){
40441                                 if(!source.substr(start).match(/^\s*$/)){
40442                                         var doc = domBuilder.doc;
40443                                 var text = doc.createTextNode(source.substr(start));
40444                                 doc.appendChild(text);
40445                                 domBuilder.currentElement = text;
40446                                 }
40447                                 return;
40448                         }
40449                         if(tagStart>start){
40450                                 appendText(tagStart);
40451                         }
40452                         switch(source.charAt(tagStart+1)){
40453                         case '/':
40454                                 var end = source.indexOf('>',tagStart+3);
40455                                 var tagName = source.substring(tagStart+2,end);
40456                                 var config = parseStack.pop();
40457                                 if(end<0){
40458                                         
40459                                 tagName = source.substring(tagStart+2).replace(/[\s<].*/,'');
40460                                 //console.error('#@@@@@@'+tagName)
40461                                 errorHandler.error("end tag name: "+tagName+' is not complete:'+config.tagName);
40462                                 end = tagStart+1+tagName.length;
40463                         }else if(tagName.match(/\s</)){
40464                                 tagName = tagName.replace(/[\s<].*/,'');
40465                                 errorHandler.error("end tag name: "+tagName+' maybe not complete');
40466                                 end = tagStart+1+tagName.length;
40467                                 }
40468                                 //console.error(parseStack.length,parseStack)
40469                                 //console.error(config);
40470                                 var localNSMap = config.localNSMap;
40471                                 var endMatch = config.tagName == tagName;
40472                                 var endIgnoreCaseMach = endMatch || config.tagName&&config.tagName.toLowerCase() == tagName.toLowerCase();
40473                         if(endIgnoreCaseMach){
40474                                 domBuilder.endElement(config.uri,config.localName,tagName);
40475                                         if(localNSMap){
40476                                                 for(var prefix in localNSMap){
40477                                                         domBuilder.endPrefixMapping(prefix) ;
40478                                                 }
40479                                         }
40480                                         if(!endMatch){
40481                                 errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName );
40482                                         }
40483                         }else{
40484                                 parseStack.push(config);
40485                         }
40486                                 
40487                                 end++;
40488                                 break;
40489                                 // end elment
40490                         case '?':// <?...?>
40491                                 locator&&position(tagStart);
40492                                 end = parseInstruction(source,tagStart,domBuilder);
40493                                 break;
40494                         case '!':// <!doctype,<![CDATA,<!--
40495                                 locator&&position(tagStart);
40496                                 end = parseDCC(source,tagStart,domBuilder,errorHandler);
40497                                 break;
40498                         default:
40499                                 locator&&position(tagStart);
40500                                 var el = new ElementAttributes();
40501                                 var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
40502                                 //elStartEnd
40503                                 var end = parseElementStartPart(source,tagStart,el,currentNSMap,entityReplacer,errorHandler);
40504                                 var len = el.length;
40505                                 
40506                                 
40507                                 if(!el.closed && fixSelfClosed(source,end,el.tagName,closeMap)){
40508                                         el.closed = true;
40509                                         if(!entityMap.nbsp){
40510                                                 errorHandler.warning('unclosed xml attribute');
40511                                         }
40512                                 }
40513                                 if(locator && len){
40514                                         var locator2 = copyLocator(locator,{});
40515                                         //try{//attribute position fixed
40516                                         for(var i = 0;i<len;i++){
40517                                                 var a = el[i];
40518                                                 position(a.offset);
40519                                                 a.locator = copyLocator(locator,{});
40520                                         }
40521                                         //}catch(e){console.error('@@@@@'+e)}
40522                                         domBuilder.locator = locator2;
40523                                         if(appendElement(el,domBuilder,currentNSMap)){
40524                                                 parseStack.push(el);
40525                                         }
40526                                         domBuilder.locator = locator;
40527                                 }else{
40528                                         if(appendElement(el,domBuilder,currentNSMap)){
40529                                                 parseStack.push(el);
40530                                         }
40531                                 }
40532                                 
40533                                 
40534                                 
40535                                 if(el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed){
40536                                         end = parseHtmlSpecialContent(source,end,el.tagName,entityReplacer,domBuilder);
40537                                 }else{
40538                                         end++;
40539                                 }
40540                         }
40541                 }catch(e){
40542                         errorHandler.error('element parse error: '+e);
40543                         //errorHandler.error('element parse error: '+e);
40544                         end = -1;
40545                         //throw e;
40546                 }
40547                 if(end>start){
40548                         start = end;
40549                 }else{
40550                         //TODO: 这里有可能sax回退,有位置错误风险
40551                         appendText(Math.max(tagStart,start)+1);
40552                 }
40553         }
40554 }
40555 function copyLocator(f,t){
40556         t.lineNumber = f.lineNumber;
40557         t.columnNumber = f.columnNumber;
40558         return t;
40559 }
40560
40561 /**
40562  * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
40563  * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
40564  */
40565 function parseElementStartPart(source,start,el,currentNSMap,entityReplacer,errorHandler){
40566         var attrName;
40567         var value;
40568         var p = ++start;
40569         var s = S_TAG;//status
40570         while(true){
40571                 var c = source.charAt(p);
40572                 switch(c){
40573                 case '=':
40574                         if(s === S_ATTR){//attrName
40575                                 attrName = source.slice(start,p);
40576                                 s = S_EQ;
40577                         }else if(s === S_ATTR_SPACE){
40578                                 s = S_EQ;
40579                         }else{
40580                                 //fatalError: equal must after attrName or space after attrName
40581                                 throw new Error('attribute equal must after attrName');
40582                         }
40583                         break;
40584                 case '\'':
40585                 case '"':
40586                         if(s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
40587                                 ){//equal
40588                                 if(s === S_ATTR){
40589                                         errorHandler.warning('attribute value must after "="');
40590                                         attrName = source.slice(start,p);
40591                                 }
40592                                 start = p+1;
40593                                 p = source.indexOf(c,start);
40594                                 if(p>0){
40595                                         value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
40596                                         el.add(attrName,value,start-1);
40597                                         s = S_ATTR_END;
40598                                 }else{
40599                                         //fatalError: no end quot match
40600                                         throw new Error('attribute value no end \''+c+'\' match');
40601                                 }
40602                         }else if(s == S_ATTR_NOQUOT_VALUE){
40603                                 value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
40604                                 //console.log(attrName,value,start,p)
40605                                 el.add(attrName,value,start);
40606                                 //console.dir(el)
40607                                 errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!');
40608                                 start = p+1;
40609                                 s = S_ATTR_END;
40610                         }else{
40611                                 //fatalError: no equal before
40612                                 throw new Error('attribute value must after "="');
40613                         }
40614                         break;
40615                 case '/':
40616                         switch(s){
40617                         case S_TAG:
40618                                 el.setTagName(source.slice(start,p));
40619                         case S_ATTR_END:
40620                         case S_TAG_SPACE:
40621                         case S_TAG_CLOSE:
40622                                 s =S_TAG_CLOSE;
40623                                 el.closed = true;
40624                         case S_ATTR_NOQUOT_VALUE:
40625                         case S_ATTR:
40626                         case S_ATTR_SPACE:
40627                                 break;
40628                         //case S_EQ:
40629                         default:
40630                                 throw new Error("attribute invalid close char('/')")
40631                         }
40632                         break;
40633                 case ''://end document
40634                         //throw new Error('unexpected end of input')
40635                         errorHandler.error('unexpected end of input');
40636                         if(s == S_TAG){
40637                                 el.setTagName(source.slice(start,p));
40638                         }
40639                         return p;
40640                 case '>':
40641                         switch(s){
40642                         case S_TAG:
40643                                 el.setTagName(source.slice(start,p));
40644                         case S_ATTR_END:
40645                         case S_TAG_SPACE:
40646                         case S_TAG_CLOSE:
40647                                 break;//normal
40648                         case S_ATTR_NOQUOT_VALUE://Compatible state
40649                         case S_ATTR:
40650                                 value = source.slice(start,p);
40651                                 if(value.slice(-1) === '/'){
40652                                         el.closed  = true;
40653                                         value = value.slice(0,-1);
40654                                 }
40655                         case S_ATTR_SPACE:
40656                                 if(s === S_ATTR_SPACE){
40657                                         value = attrName;
40658                                 }
40659                                 if(s == S_ATTR_NOQUOT_VALUE){
40660                                         errorHandler.warning('attribute "'+value+'" missed quot(")!!');
40661                                         el.add(attrName,value.replace(/&#?\w+;/g,entityReplacer),start);
40662                                 }else{
40663                                         if(currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !value.match(/^(?:disabled|checked|selected)$/i)){
40664                                                 errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!');
40665                                         }
40666                                         el.add(value,value,start);
40667                                 }
40668                                 break;
40669                         case S_EQ:
40670                                 throw new Error('attribute value missed!!');
40671                         }
40672 //                      console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
40673                         return p;
40674                 /*xml space '\x20' | #x9 | #xD | #xA; */
40675                 case '\u0080':
40676                         c = ' ';
40677                 default:
40678                         if(c<= ' '){//space
40679                                 switch(s){
40680                                 case S_TAG:
40681                                         el.setTagName(source.slice(start,p));//tagName
40682                                         s = S_TAG_SPACE;
40683                                         break;
40684                                 case S_ATTR:
40685                                         attrName = source.slice(start,p);
40686                                         s = S_ATTR_SPACE;
40687                                         break;
40688                                 case S_ATTR_NOQUOT_VALUE:
40689                                         var value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
40690                                         errorHandler.warning('attribute "'+value+'" missed quot(")!!');
40691                                         el.add(attrName,value,start);
40692                                 case S_ATTR_END:
40693                                         s = S_TAG_SPACE;
40694                                         break;
40695                                 //case S_TAG_SPACE:
40696                                 //case S_EQ:
40697                                 //case S_ATTR_SPACE:
40698                                 //      void();break;
40699                                 //case S_TAG_CLOSE:
40700                                         //ignore warning
40701                                 }
40702                         }else{//not space
40703 //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
40704 //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
40705                                 switch(s){
40706                                 //case S_TAG:void();break;
40707                                 //case S_ATTR:void();break;
40708                                 //case S_ATTR_NOQUOT_VALUE:void();break;
40709                                 case S_ATTR_SPACE:
40710                                         var tagName =  el.tagName;
40711                                         if(currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !attrName.match(/^(?:disabled|checked|selected)$/i)){
40712                                                 errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead2!!');
40713                                         }
40714                                         el.add(attrName,attrName,start);
40715                                         start = p;
40716                                         s = S_ATTR;
40717                                         break;
40718                                 case S_ATTR_END:
40719                                         errorHandler.warning('attribute space is required"'+attrName+'"!!');
40720                                 case S_TAG_SPACE:
40721                                         s = S_ATTR;
40722                                         start = p;
40723                                         break;
40724                                 case S_EQ:
40725                                         s = S_ATTR_NOQUOT_VALUE;
40726                                         start = p;
40727                                         break;
40728                                 case S_TAG_CLOSE:
40729                                         throw new Error("elements closed character '/' and '>' must be connected to");
40730                                 }
40731                         }
40732                 }//end outer switch
40733                 //console.log('p++',p)
40734                 p++;
40735         }
40736 }
40737 /**
40738  * @return true if has new namespace define
40739  */
40740 function appendElement(el,domBuilder,currentNSMap){
40741         var tagName = el.tagName;
40742         var localNSMap = null;
40743         //var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
40744         var i = el.length;
40745         while(i--){
40746                 var a = el[i];
40747                 var qName = a.qName;
40748                 var value = a.value;
40749                 var nsp = qName.indexOf(':');
40750                 if(nsp>0){
40751                         var prefix = a.prefix = qName.slice(0,nsp);
40752                         var localName = qName.slice(nsp+1);
40753                         var nsPrefix = prefix === 'xmlns' && localName;
40754                 }else{
40755                         localName = qName;
40756                         prefix = null;
40757                         nsPrefix = qName === 'xmlns' && '';
40758                 }
40759                 //can not set prefix,because prefix !== ''
40760                 a.localName = localName ;
40761                 //prefix == null for no ns prefix attribute 
40762                 if(nsPrefix !== false){//hack!!
40763                         if(localNSMap == null){
40764                                 localNSMap = {};
40765                                 //console.log(currentNSMap,0)
40766                                 _copy(currentNSMap,currentNSMap={});
40767                                 //console.log(currentNSMap,1)
40768                         }
40769                         currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
40770                         a.uri = 'http://www.w3.org/2000/xmlns/';
40771                         domBuilder.startPrefixMapping(nsPrefix, value); 
40772                 }
40773         }
40774         var i = el.length;
40775         while(i--){
40776                 a = el[i];
40777                 var prefix = a.prefix;
40778                 if(prefix){//no prefix attribute has no namespace
40779                         if(prefix === 'xml'){
40780                                 a.uri = 'http://www.w3.org/XML/1998/namespace';
40781                         }if(prefix !== 'xmlns'){
40782                                 a.uri = currentNSMap[prefix || ''];
40783                                 
40784                                 //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
40785                         }
40786                 }
40787         }
40788         var nsp = tagName.indexOf(':');
40789         if(nsp>0){
40790                 prefix = el.prefix = tagName.slice(0,nsp);
40791                 localName = el.localName = tagName.slice(nsp+1);
40792         }else{
40793                 prefix = null;//important!!
40794                 localName = el.localName = tagName;
40795         }
40796         //no prefix element has default namespace
40797         var ns = el.uri = currentNSMap[prefix || ''];
40798         domBuilder.startElement(ns,localName,tagName,el);
40799         //endPrefixMapping and startPrefixMapping have not any help for dom builder
40800         //localNSMap = null
40801         if(el.closed){
40802                 domBuilder.endElement(ns,localName,tagName);
40803                 if(localNSMap){
40804                         for(prefix in localNSMap){
40805                                 domBuilder.endPrefixMapping(prefix); 
40806                         }
40807                 }
40808         }else{
40809                 el.currentNSMap = currentNSMap;
40810                 el.localNSMap = localNSMap;
40811                 //parseStack.push(el);
40812                 return true;
40813         }
40814 }
40815 function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){
40816         if(/^(?:script|textarea)$/i.test(tagName)){
40817                 var elEndStart =  source.indexOf('</'+tagName+'>',elStartEnd);
40818                 var text = source.substring(elStartEnd+1,elEndStart);
40819                 if(/[&<]/.test(text)){
40820                         if(/^script$/i.test(tagName)){
40821                                 //if(!/\]\]>/.test(text)){
40822                                         //lexHandler.startCDATA();
40823                                         domBuilder.characters(text,0,text.length);
40824                                         //lexHandler.endCDATA();
40825                                         return elEndStart;
40826                                 //}
40827                         }//}else{//text area
40828                                 text = text.replace(/&#?\w+;/g,entityReplacer);
40829                                 domBuilder.characters(text,0,text.length);
40830                                 return elEndStart;
40831                         //}
40832                         
40833                 }
40834         }
40835         return elStartEnd+1;
40836 }
40837 function fixSelfClosed(source,elStartEnd,tagName,closeMap){
40838         //if(tagName in closeMap){
40839         var pos = closeMap[tagName];
40840         if(pos == null){
40841                 //console.log(tagName)
40842                 pos =  source.lastIndexOf('</'+tagName+'>');
40843                 if(pos<elStartEnd){//忘记闭合
40844                         pos = source.lastIndexOf('</'+tagName);
40845                 }
40846                 closeMap[tagName] =pos;
40847         }
40848         return pos<elStartEnd;
40849         //} 
40850 }
40851 function _copy(source,target){
40852         for(var n in source){target[n] = source[n];}
40853 }
40854 function parseDCC(source,start,domBuilder,errorHandler){//sure start with '<!'
40855         var next= source.charAt(start+2);
40856         switch(next){
40857         case '-':
40858                 if(source.charAt(start + 3) === '-'){
40859                         var end = source.indexOf('-->',start+4);
40860                         //append comment source.substring(4,end)//<!--
40861                         if(end>start){
40862                                 domBuilder.comment(source,start+4,end-start-4);
40863                                 return end+3;
40864                         }else{
40865                                 errorHandler.error("Unclosed comment");
40866                                 return -1;
40867                         }
40868                 }else{
40869                         //error
40870                         return -1;
40871                 }
40872         default:
40873                 if(source.substr(start+3,6) == 'CDATA['){
40874                         var end = source.indexOf(']]>',start+9);
40875                         domBuilder.startCDATA();
40876                         domBuilder.characters(source,start+9,end-start-9);
40877                         domBuilder.endCDATA(); 
40878                         return end+3;
40879                 }
40880                 //<!DOCTYPE
40881                 //startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId) 
40882                 var matchs = split(source,start);
40883                 var len = matchs.length;
40884                 if(len>1 && /!doctype/i.test(matchs[0][0])){
40885                         var name = matchs[1][0];
40886                         var pubid = len>3 && /^public$/i.test(matchs[2][0]) && matchs[3][0];
40887                         var sysid = len>4 && matchs[4][0];
40888                         var lastMatch = matchs[len-1];
40889                         domBuilder.startDTD(name,pubid && pubid.replace(/^(['"])(.*?)\1$/,'$2'),
40890                                         sysid && sysid.replace(/^(['"])(.*?)\1$/,'$2'));
40891                         domBuilder.endDTD();
40892                         
40893                         return lastMatch.index+lastMatch[0].length
40894                 }
40895         }
40896         return -1;
40897 }
40898
40899
40900
40901 function parseInstruction(source,start,domBuilder){
40902         var end = source.indexOf('?>',start);
40903         if(end){
40904                 var match = source.substring(start,end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
40905                 if(match){
40906                         var len = match[0].length;
40907                         domBuilder.processingInstruction(match[1], match[2]) ;
40908                         return end+2;
40909                 }else{//error
40910                         return -1;
40911                 }
40912         }
40913         return -1;
40914 }
40915
40916 /**
40917  * @param source
40918  */
40919 function ElementAttributes(source){
40920         
40921 }
40922 ElementAttributes.prototype = {
40923         setTagName:function(tagName){
40924                 if(!tagNamePattern.test(tagName)){
40925                         throw new Error('invalid tagName:'+tagName)
40926                 }
40927                 this.tagName = tagName;
40928         },
40929         add:function(qName,value,offset){
40930                 if(!tagNamePattern.test(qName)){
40931                         throw new Error('invalid attribute:'+qName)
40932                 }
40933                 this[this.length++] = {qName:qName,value:value,offset:offset};
40934         },
40935         length:0,
40936         getLocalName:function(i){return this[i].localName},
40937         getLocator:function(i){return this[i].locator},
40938         getQName:function(i){return this[i].qName},
40939         getURI:function(i){return this[i].uri},
40940         getValue:function(i){return this[i].value}
40941 //      ,getIndex:function(uri, localName)){
40942 //              if(localName){
40943 //                      
40944 //              }else{
40945 //                      var qName = uri
40946 //              }
40947 //      },
40948 //      getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
40949 //      getType:function(uri,localName){}
40950 //      getType:function(i){},
40951 };
40952
40953
40954
40955
40956 function _set_proto_(thiz,parent){
40957         thiz.__proto__ = parent;
40958         return thiz;
40959 }
40960 if(!(_set_proto_({},_set_proto_.prototype) instanceof _set_proto_)){
40961         _set_proto_ = function(thiz,parent){
40962                 function p(){}
40963                 p.prototype = parent;
40964                 p = new p();
40965                 for(parent in thiz){
40966                         p[parent] = thiz[parent];
40967                 }
40968                 return p;
40969         };
40970 }
40971
40972 function split(source,start){
40973         var match;
40974         var buf = [];
40975         var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
40976         reg.lastIndex = start;
40977         reg.exec(source);//skip <
40978         while(match = reg.exec(source)){
40979                 buf.push(match);
40980                 if(match[1])return buf;
40981         }
40982 }
40983
40984 var XMLReader_1 = XMLReader;
40985
40986 var sax = {
40987         XMLReader: XMLReader_1
40988 };
40989
40990 /*
40991  * DOM Level 2
40992  * Object DOMException
40993  * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
40994  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
40995  */
40996
40997 function copy$1(src,dest){
40998         for(var p in src){
40999                 dest[p] = src[p];
41000         }
41001 }
41002 /**
41003 ^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));?
41004 ^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));?
41005  */
41006 function _extends(Class,Super){
41007         var pt = Class.prototype;
41008         if(Object.create){
41009                 var ppt = Object.create(Super.prototype);
41010                 pt.__proto__ = ppt;
41011         }
41012         if(!(pt instanceof Super)){
41013                 function t(){}
41014                 t.prototype = Super.prototype;
41015                 t = new t();
41016                 copy$1(pt,t);
41017                 Class.prototype = pt = t;
41018         }
41019         if(pt.constructor != Class){
41020                 if(typeof Class != 'function'){
41021                         console.error("unknow Class:"+Class);
41022                 }
41023                 pt.constructor = Class;
41024         }
41025 }
41026 var htmlns = 'http://www.w3.org/1999/xhtml';
41027 // Node Types
41028 var NodeType = {};
41029 var ELEMENT_NODE                = NodeType.ELEMENT_NODE                = 1;
41030 var ATTRIBUTE_NODE              = NodeType.ATTRIBUTE_NODE              = 2;
41031 var TEXT_NODE                   = NodeType.TEXT_NODE                   = 3;
41032 var CDATA_SECTION_NODE          = NodeType.CDATA_SECTION_NODE          = 4;
41033 var ENTITY_REFERENCE_NODE       = NodeType.ENTITY_REFERENCE_NODE       = 5;
41034 var ENTITY_NODE                 = NodeType.ENTITY_NODE                 = 6;
41035 var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
41036 var COMMENT_NODE                = NodeType.COMMENT_NODE                = 8;
41037 var DOCUMENT_NODE               = NodeType.DOCUMENT_NODE               = 9;
41038 var DOCUMENT_TYPE_NODE          = NodeType.DOCUMENT_TYPE_NODE          = 10;
41039 var DOCUMENT_FRAGMENT_NODE      = NodeType.DOCUMENT_FRAGMENT_NODE      = 11;
41040 var NOTATION_NODE               = NodeType.NOTATION_NODE               = 12;
41041
41042 // ExceptionCode
41043 var ExceptionCode = {};
41044 var ExceptionMessage = {};
41045 var INDEX_SIZE_ERR              = ExceptionCode.INDEX_SIZE_ERR              = ((ExceptionMessage[1]="Index size error"),1);
41046 var DOMSTRING_SIZE_ERR          = ExceptionCode.DOMSTRING_SIZE_ERR          = ((ExceptionMessage[2]="DOMString size error"),2);
41047 var HIERARCHY_REQUEST_ERR       = ExceptionCode.HIERARCHY_REQUEST_ERR       = ((ExceptionMessage[3]="Hierarchy request error"),3);
41048 var WRONG_DOCUMENT_ERR          = ExceptionCode.WRONG_DOCUMENT_ERR          = ((ExceptionMessage[4]="Wrong document"),4);
41049 var INVALID_CHARACTER_ERR       = ExceptionCode.INVALID_CHARACTER_ERR       = ((ExceptionMessage[5]="Invalid character"),5);
41050 var NO_DATA_ALLOWED_ERR         = ExceptionCode.NO_DATA_ALLOWED_ERR         = ((ExceptionMessage[6]="No data allowed"),6);
41051 var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = ((ExceptionMessage[7]="No modification allowed"),7);
41052 var NOT_FOUND_ERR               = ExceptionCode.NOT_FOUND_ERR               = ((ExceptionMessage[8]="Not found"),8);
41053 var NOT_SUPPORTED_ERR           = ExceptionCode.NOT_SUPPORTED_ERR           = ((ExceptionMessage[9]="Not supported"),9);
41054 var INUSE_ATTRIBUTE_ERR         = ExceptionCode.INUSE_ATTRIBUTE_ERR         = ((ExceptionMessage[10]="Attribute in use"),10);
41055 //level2
41056 var INVALID_STATE_ERR           = ExceptionCode.INVALID_STATE_ERR               = ((ExceptionMessage[11]="Invalid state"),11);
41057 var SYNTAX_ERR                  = ExceptionCode.SYNTAX_ERR                      = ((ExceptionMessage[12]="Syntax error"),12);
41058 var INVALID_MODIFICATION_ERR    = ExceptionCode.INVALID_MODIFICATION_ERR        = ((ExceptionMessage[13]="Invalid modification"),13);
41059 var NAMESPACE_ERR               = ExceptionCode.NAMESPACE_ERR                   = ((ExceptionMessage[14]="Invalid namespace"),14);
41060 var INVALID_ACCESS_ERR          = ExceptionCode.INVALID_ACCESS_ERR              = ((ExceptionMessage[15]="Invalid access"),15);
41061
41062
41063 function DOMException(code, message) {
41064         if(message instanceof Error){
41065                 var error = message;
41066         }else{
41067                 error = this;
41068                 Error.call(this, ExceptionMessage[code]);
41069                 this.message = ExceptionMessage[code];
41070                 if(Error.captureStackTrace) Error.captureStackTrace(this, DOMException);
41071         }
41072         error.code = code;
41073         if(message) this.message = this.message + ": " + message;
41074         return error;
41075 }
41076 DOMException.prototype = Error.prototype;
41077 copy$1(ExceptionCode,DOMException);
41078 /**
41079  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
41080  * The NodeList interface provides the abstraction of an ordered collection of nodes, without defining or constraining how this collection is implemented. NodeList objects in the DOM are live.
41081  * The items in the NodeList are accessible via an integral index, starting from 0.
41082  */
41083 function NodeList() {
41084 }
41085 NodeList.prototype = {
41086         /**
41087          * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
41088          * @standard level1
41089          */
41090         length:0, 
41091         /**
41092          * Returns the indexth item in the collection. If index is greater than or equal to the number of nodes in the list, this returns null.
41093          * @standard level1
41094          * @param index  unsigned long 
41095          *   Index into the collection.
41096          * @return Node
41097          *      The node at the indexth position in the NodeList, or null if that is not a valid index. 
41098          */
41099         item: function(index) {
41100                 return this[index] || null;
41101         },
41102         toString:function(isHTML,nodeFilter){
41103                 for(var buf = [], i = 0;i<this.length;i++){
41104                         serializeToString(this[i],buf,isHTML,nodeFilter);
41105                 }
41106                 return buf.join('');
41107         }
41108 };
41109 function LiveNodeList(node,refresh){
41110         this._node = node;
41111         this._refresh = refresh;
41112         _updateLiveList(this);
41113 }
41114 function _updateLiveList(list){
41115         var inc = list._node._inc || list._node.ownerDocument._inc;
41116         if(list._inc != inc){
41117                 var ls = list._refresh(list._node);
41118                 //console.log(ls.length)
41119                 __set__(list,'length',ls.length);
41120                 copy$1(ls,list);
41121                 list._inc = inc;
41122         }
41123 }
41124 LiveNodeList.prototype.item = function(i){
41125         _updateLiveList(this);
41126         return this[i];
41127 };
41128
41129 _extends(LiveNodeList,NodeList);
41130 /**
41131  * 
41132  * Objects implementing the NamedNodeMap interface are used to represent collections of nodes that can be accessed by name. Note that NamedNodeMap does not inherit from NodeList; NamedNodeMaps are not maintained in any particular order. Objects contained in an object implementing NamedNodeMap may also be accessed by an ordinal index, but this is simply to allow convenient enumeration of the contents of a NamedNodeMap, and does not imply that the DOM specifies an order to these Nodes.
41133  * NamedNodeMap objects in the DOM are live.
41134  * used for attributes or DocumentType entities 
41135  */
41136 function NamedNodeMap() {
41137 }
41138
41139 function _findNodeIndex(list,node){
41140         var i = list.length;
41141         while(i--){
41142                 if(list[i] === node){return i}
41143         }
41144 }
41145
41146 function _addNamedNode(el,list,newAttr,oldAttr){
41147         if(oldAttr){
41148                 list[_findNodeIndex(list,oldAttr)] = newAttr;
41149         }else{
41150                 list[list.length++] = newAttr;
41151         }
41152         if(el){
41153                 newAttr.ownerElement = el;
41154                 var doc = el.ownerDocument;
41155                 if(doc){
41156                         oldAttr && _onRemoveAttribute(doc,el,oldAttr);
41157                         _onAddAttribute(doc,el,newAttr);
41158                 }
41159         }
41160 }
41161 function _removeNamedNode(el,list,attr){
41162         //console.log('remove attr:'+attr)
41163         var i = _findNodeIndex(list,attr);
41164         if(i>=0){
41165                 var lastIndex = list.length-1;
41166                 while(i<lastIndex){
41167                         list[i] = list[++i];
41168                 }
41169                 list.length = lastIndex;
41170                 if(el){
41171                         var doc = el.ownerDocument;
41172                         if(doc){
41173                                 _onRemoveAttribute(doc,el,attr);
41174                                 attr.ownerElement = null;
41175                         }
41176                 }
41177         }else{
41178                 throw DOMException(NOT_FOUND_ERR,new Error(el.tagName+'@'+attr))
41179         }
41180 }
41181 NamedNodeMap.prototype = {
41182         length:0,
41183         item:NodeList.prototype.item,
41184         getNamedItem: function(key) {
41185 //              if(key.indexOf(':')>0 || key == 'xmlns'){
41186 //                      return null;
41187 //              }
41188                 //console.log()
41189                 var i = this.length;
41190                 while(i--){
41191                         var attr = this[i];
41192                         //console.log(attr.nodeName,key)
41193                         if(attr.nodeName == key){
41194                                 return attr;
41195                         }
41196                 }
41197         },
41198         setNamedItem: function(attr) {
41199                 var el = attr.ownerElement;
41200                 if(el && el!=this._ownerElement){
41201                         throw new DOMException(INUSE_ATTRIBUTE_ERR);
41202                 }
41203                 var oldAttr = this.getNamedItem(attr.nodeName);
41204                 _addNamedNode(this._ownerElement,this,attr,oldAttr);
41205                 return oldAttr;
41206         },
41207         /* returns Node */
41208         setNamedItemNS: function(attr) {// raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR
41209                 var el = attr.ownerElement, oldAttr;
41210                 if(el && el!=this._ownerElement){
41211                         throw new DOMException(INUSE_ATTRIBUTE_ERR);
41212                 }
41213                 oldAttr = this.getNamedItemNS(attr.namespaceURI,attr.localName);
41214                 _addNamedNode(this._ownerElement,this,attr,oldAttr);
41215                 return oldAttr;
41216         },
41217
41218         /* returns Node */
41219         removeNamedItem: function(key) {
41220                 var attr = this.getNamedItem(key);
41221                 _removeNamedNode(this._ownerElement,this,attr);
41222                 return attr;
41223                 
41224                 
41225         },// raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR
41226         
41227         //for level2
41228         removeNamedItemNS:function(namespaceURI,localName){
41229                 var attr = this.getNamedItemNS(namespaceURI,localName);
41230                 _removeNamedNode(this._ownerElement,this,attr);
41231                 return attr;
41232         },
41233         getNamedItemNS: function(namespaceURI, localName) {
41234                 var i = this.length;
41235                 while(i--){
41236                         var node = this[i];
41237                         if(node.localName == localName && node.namespaceURI == namespaceURI){
41238                                 return node;
41239                         }
41240                 }
41241                 return null;
41242         }
41243 };
41244 /**
41245  * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490
41246  */
41247 function DOMImplementation(/* Object */ features) {
41248         this._features = {};
41249         if (features) {
41250                 for (var feature in features) {
41251                          this._features = features[feature];
41252                 }
41253         }
41254 }
41255
41256 DOMImplementation.prototype = {
41257         hasFeature: function(/* string */ feature, /* string */ version) {
41258                 var versions = this._features[feature.toLowerCase()];
41259                 if (versions && (!version || version in versions)) {
41260                         return true;
41261                 } else {
41262                         return false;
41263                 }
41264         },
41265         // Introduced in DOM Level 2:
41266         createDocument:function(namespaceURI,  qualifiedName, doctype){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR,WRONG_DOCUMENT_ERR
41267                 var doc = new Document();
41268                 doc.implementation = this;
41269                 doc.childNodes = new NodeList();
41270                 doc.doctype = doctype;
41271                 if(doctype){
41272                         doc.appendChild(doctype);
41273                 }
41274                 if(qualifiedName){
41275                         var root = doc.createElementNS(namespaceURI,qualifiedName);
41276                         doc.appendChild(root);
41277                 }
41278                 return doc;
41279         },
41280         // Introduced in DOM Level 2:
41281         createDocumentType:function(qualifiedName, publicId, systemId){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR
41282                 var node = new DocumentType();
41283                 node.name = qualifiedName;
41284                 node.nodeName = qualifiedName;
41285                 node.publicId = publicId;
41286                 node.systemId = systemId;
41287                 // Introduced in DOM Level 2:
41288                 //readonly attribute DOMString        internalSubset;
41289                 
41290                 //TODO:..
41291                 //  readonly attribute NamedNodeMap     entities;
41292                 //  readonly attribute NamedNodeMap     notations;
41293                 return node;
41294         }
41295 };
41296
41297
41298 /**
41299  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
41300  */
41301
41302 function Node$3() {
41303 }
41304
41305 Node$3.prototype = {
41306         firstChild : null,
41307         lastChild : null,
41308         previousSibling : null,
41309         nextSibling : null,
41310         attributes : null,
41311         parentNode : null,
41312         childNodes : null,
41313         ownerDocument : null,
41314         nodeValue : null,
41315         namespaceURI : null,
41316         prefix : null,
41317         localName : null,
41318         // Modified in DOM Level 2:
41319         insertBefore:function(newChild, refChild){//raises 
41320                 return _insertBefore(this,newChild,refChild);
41321         },
41322         replaceChild:function(newChild, oldChild){//raises 
41323                 this.insertBefore(newChild,oldChild);
41324                 if(oldChild){
41325                         this.removeChild(oldChild);
41326                 }
41327         },
41328         removeChild:function(oldChild){
41329                 return _removeChild(this,oldChild);
41330         },
41331         appendChild:function(newChild){
41332                 return this.insertBefore(newChild,null);
41333         },
41334         hasChildNodes:function(){
41335                 return this.firstChild != null;
41336         },
41337         cloneNode:function(deep){
41338                 return cloneNode(this.ownerDocument||this,this,deep);
41339         },
41340         // Modified in DOM Level 2:
41341         normalize:function(){
41342                 var child = this.firstChild;
41343                 while(child){
41344                         var next = child.nextSibling;
41345                         if(next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE){
41346                                 this.removeChild(next);
41347                                 child.appendData(next.data);
41348                         }else{
41349                                 child.normalize();
41350                                 child = next;
41351                         }
41352                 }
41353         },
41354         // Introduced in DOM Level 2:
41355         isSupported:function(feature, version){
41356                 return this.ownerDocument.implementation.hasFeature(feature,version);
41357         },
41358     // Introduced in DOM Level 2:
41359     hasAttributes:function(){
41360         return this.attributes.length>0;
41361     },
41362     lookupPrefix:function(namespaceURI){
41363         var el = this;
41364         while(el){
41365                 var map = el._nsMap;
41366                 //console.dir(map)
41367                 if(map){
41368                         for(var n in map){
41369                                 if(map[n] == namespaceURI){
41370                                         return n;
41371                                 }
41372                         }
41373                 }
41374                 el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;
41375         }
41376         return null;
41377     },
41378     // Introduced in DOM Level 3:
41379     lookupNamespaceURI:function(prefix){
41380         var el = this;
41381         while(el){
41382                 var map = el._nsMap;
41383                 //console.dir(map)
41384                 if(map){
41385                         if(prefix in map){
41386                                 return map[prefix] ;
41387                         }
41388                 }
41389                 el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;
41390         }
41391         return null;
41392     },
41393     // Introduced in DOM Level 3:
41394     isDefaultNamespace:function(namespaceURI){
41395         var prefix = this.lookupPrefix(namespaceURI);
41396         return prefix == null;
41397     }
41398 };
41399
41400
41401 function _xmlEncoder(c){
41402         return c == '<' && '&lt;' ||
41403          c == '>' && '&gt;' ||
41404          c == '&' && '&amp;' ||
41405          c == '"' && '&quot;' ||
41406          '&#'+c.charCodeAt()+';'
41407 }
41408
41409
41410 copy$1(NodeType,Node$3);
41411 copy$1(NodeType,Node$3.prototype);
41412
41413 /**
41414  * @param callback return true for continue,false for break
41415  * @return boolean true: break visit;
41416  */
41417 function _visitNode(node,callback){
41418         if(callback(node)){
41419                 return true;
41420         }
41421         if(node = node.firstChild){
41422                 do{
41423                         if(_visitNode(node,callback)){return true}
41424         }while(node=node.nextSibling)
41425     }
41426 }
41427
41428
41429
41430 function Document(){
41431 }
41432 function _onAddAttribute(doc,el,newAttr){
41433         doc && doc._inc++;
41434         var ns = newAttr.namespaceURI;
41435         if(ns == 'http://www.w3.org/2000/xmlns/'){
41436                 //update namespace
41437                 el._nsMap[newAttr.prefix?newAttr.localName:''] = newAttr.value;
41438         }
41439 }
41440 function _onRemoveAttribute(doc,el,newAttr,remove){
41441         doc && doc._inc++;
41442         var ns = newAttr.namespaceURI;
41443         if(ns == 'http://www.w3.org/2000/xmlns/'){
41444                 //update namespace
41445                 delete el._nsMap[newAttr.prefix?newAttr.localName:''];
41446         }
41447 }
41448 function _onUpdateChild(doc,el,newChild){
41449         if(doc && doc._inc){
41450                 doc._inc++;
41451                 //update childNodes
41452                 var cs = el.childNodes;
41453                 if(newChild){
41454                         cs[cs.length++] = newChild;
41455                 }else{
41456                         //console.log(1)
41457                         var child = el.firstChild;
41458                         var i = 0;
41459                         while(child){
41460                                 cs[i++] = child;
41461                                 child =child.nextSibling;
41462                         }
41463                         cs.length = i;
41464                 }
41465         }
41466 }
41467
41468 /**
41469  * attributes;
41470  * children;
41471  * 
41472  * writeable properties:
41473  * nodeValue,Attr:value,CharacterData:data
41474  * prefix
41475  */
41476 function _removeChild(parentNode,child){
41477         var previous = child.previousSibling;
41478         var next = child.nextSibling;
41479         if(previous){
41480                 previous.nextSibling = next;
41481         }else{
41482                 parentNode.firstChild = next;
41483         }
41484         if(next){
41485                 next.previousSibling = previous;
41486         }else{
41487                 parentNode.lastChild = previous;
41488         }
41489         _onUpdateChild(parentNode.ownerDocument,parentNode);
41490         return child;
41491 }
41492 /**
41493  * preformance key(refChild == null)
41494  */
41495 function _insertBefore(parentNode,newChild,nextChild){
41496         var cp = newChild.parentNode;
41497         if(cp){
41498                 cp.removeChild(newChild);//remove and update
41499         }
41500         if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
41501                 var newFirst = newChild.firstChild;
41502                 if (newFirst == null) {
41503                         return newChild;
41504                 }
41505                 var newLast = newChild.lastChild;
41506         }else{
41507                 newFirst = newLast = newChild;
41508         }
41509         var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
41510
41511         newFirst.previousSibling = pre;
41512         newLast.nextSibling = nextChild;
41513         
41514         
41515         if(pre){
41516                 pre.nextSibling = newFirst;
41517         }else{
41518                 parentNode.firstChild = newFirst;
41519         }
41520         if(nextChild == null){
41521                 parentNode.lastChild = newLast;
41522         }else{
41523                 nextChild.previousSibling = newLast;
41524         }
41525         do{
41526                 newFirst.parentNode = parentNode;
41527         }while(newFirst !== newLast && (newFirst= newFirst.nextSibling))
41528         _onUpdateChild(parentNode.ownerDocument||parentNode,parentNode);
41529         //console.log(parentNode.lastChild.nextSibling == null)
41530         if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
41531                 newChild.firstChild = newChild.lastChild = null;
41532         }
41533         return newChild;
41534 }
41535 function _appendSingleChild(parentNode,newChild){
41536         var cp = newChild.parentNode;
41537         if(cp){
41538                 var pre = parentNode.lastChild;
41539                 cp.removeChild(newChild);//remove and update
41540                 var pre = parentNode.lastChild;
41541         }
41542         var pre = parentNode.lastChild;
41543         newChild.parentNode = parentNode;
41544         newChild.previousSibling = pre;
41545         newChild.nextSibling = null;
41546         if(pre){
41547                 pre.nextSibling = newChild;
41548         }else{
41549                 parentNode.firstChild = newChild;
41550         }
41551         parentNode.lastChild = newChild;
41552         _onUpdateChild(parentNode.ownerDocument,parentNode,newChild);
41553         return newChild;
41554         //console.log("__aa",parentNode.lastChild.nextSibling == null)
41555 }
41556 Document.prototype = {
41557         //implementation : null,
41558         nodeName :  '#document',
41559         nodeType :  DOCUMENT_NODE,
41560         doctype :  null,
41561         documentElement :  null,
41562         _inc : 1,
41563         
41564         insertBefore :  function(newChild, refChild){//raises 
41565                 if(newChild.nodeType == DOCUMENT_FRAGMENT_NODE){
41566                         var child = newChild.firstChild;
41567                         while(child){
41568                                 var next = child.nextSibling;
41569                                 this.insertBefore(child,refChild);
41570                                 child = next;
41571                         }
41572                         return newChild;
41573                 }
41574                 if(this.documentElement == null && newChild.nodeType == ELEMENT_NODE){
41575                         this.documentElement = newChild;
41576                 }
41577                 
41578                 return _insertBefore(this,newChild,refChild),(newChild.ownerDocument = this),newChild;
41579         },
41580         removeChild :  function(oldChild){
41581                 if(this.documentElement == oldChild){
41582                         this.documentElement = null;
41583                 }
41584                 return _removeChild(this,oldChild);
41585         },
41586         // Introduced in DOM Level 2:
41587         importNode : function(importedNode,deep){
41588                 return importNode(this,importedNode,deep);
41589         },
41590         // Introduced in DOM Level 2:
41591         getElementById :        function(id){
41592                 var rtv = null;
41593                 _visitNode(this.documentElement,function(node){
41594                         if(node.nodeType == ELEMENT_NODE){
41595                                 if(node.getAttribute('id') == id){
41596                                         rtv = node;
41597                                         return true;
41598                                 }
41599                         }
41600                 });
41601                 return rtv;
41602         },
41603         
41604         //document factory method:
41605         createElement : function(tagName){
41606                 var node = new Element();
41607                 node.ownerDocument = this;
41608                 node.nodeName = tagName;
41609                 node.tagName = tagName;
41610                 node.childNodes = new NodeList();
41611                 var attrs       = node.attributes = new NamedNodeMap();
41612                 attrs._ownerElement = node;
41613                 return node;
41614         },
41615         createDocumentFragment :        function(){
41616                 var node = new DocumentFragment();
41617                 node.ownerDocument = this;
41618                 node.childNodes = new NodeList();
41619                 return node;
41620         },
41621         createTextNode :        function(data){
41622                 var node = new Text();
41623                 node.ownerDocument = this;
41624                 node.appendData(data);
41625                 return node;
41626         },
41627         createComment : function(data){
41628                 var node = new Comment();
41629                 node.ownerDocument = this;
41630                 node.appendData(data);
41631                 return node;
41632         },
41633         createCDATASection :    function(data){
41634                 var node = new CDATASection();
41635                 node.ownerDocument = this;
41636                 node.appendData(data);
41637                 return node;
41638         },
41639         createProcessingInstruction :   function(target,data){
41640                 var node = new ProcessingInstruction();
41641                 node.ownerDocument = this;
41642                 node.tagName = node.target = target;
41643                 node.nodeValue= node.data = data;
41644                 return node;
41645         },
41646         createAttribute :       function(name){
41647                 var node = new Attr();
41648                 node.ownerDocument      = this;
41649                 node.name = name;
41650                 node.nodeName   = name;
41651                 node.localName = name;
41652                 node.specified = true;
41653                 return node;
41654         },
41655         createEntityReference : function(name){
41656                 var node = new EntityReference();
41657                 node.ownerDocument      = this;
41658                 node.nodeName   = name;
41659                 return node;
41660         },
41661         // Introduced in DOM Level 2:
41662         createElementNS :       function(namespaceURI,qualifiedName){
41663                 var node = new Element();
41664                 var pl = qualifiedName.split(':');
41665                 var attrs       = node.attributes = new NamedNodeMap();
41666                 node.childNodes = new NodeList();
41667                 node.ownerDocument = this;
41668                 node.nodeName = qualifiedName;
41669                 node.tagName = qualifiedName;
41670                 node.namespaceURI = namespaceURI;
41671                 if(pl.length == 2){
41672                         node.prefix = pl[0];
41673                         node.localName = pl[1];
41674                 }else{
41675                         //el.prefix = null;
41676                         node.localName = qualifiedName;
41677                 }
41678                 attrs._ownerElement = node;
41679                 return node;
41680         },
41681         // Introduced in DOM Level 2:
41682         createAttributeNS :     function(namespaceURI,qualifiedName){
41683                 var node = new Attr();
41684                 var pl = qualifiedName.split(':');
41685                 node.ownerDocument = this;
41686                 node.nodeName = qualifiedName;
41687                 node.name = qualifiedName;
41688                 node.namespaceURI = namespaceURI;
41689                 node.specified = true;
41690                 if(pl.length == 2){
41691                         node.prefix = pl[0];
41692                         node.localName = pl[1];
41693                 }else{
41694                         //el.prefix = null;
41695                         node.localName = qualifiedName;
41696                 }
41697                 return node;
41698         }
41699 };
41700 _extends(Document,Node$3);
41701
41702
41703 function Element() {
41704         this._nsMap = {};
41705 }
41706 Element.prototype = {
41707         nodeType : ELEMENT_NODE,
41708         hasAttribute : function(name){
41709                 return this.getAttributeNode(name)!=null;
41710         },
41711         getAttribute : function(name){
41712                 var attr = this.getAttributeNode(name);
41713                 return attr && attr.value || '';
41714         },
41715         getAttributeNode : function(name){
41716                 return this.attributes.getNamedItem(name);
41717         },
41718         setAttribute : function(name, value){
41719                 var attr = this.ownerDocument.createAttribute(name);
41720                 attr.value = attr.nodeValue = "" + value;
41721                 this.setAttributeNode(attr);
41722         },
41723         removeAttribute : function(name){
41724                 var attr = this.getAttributeNode(name);
41725                 attr && this.removeAttributeNode(attr);
41726         },
41727         
41728         //four real opeartion method
41729         appendChild:function(newChild){
41730                 if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
41731                         return this.insertBefore(newChild,null);
41732                 }else{
41733                         return _appendSingleChild(this,newChild);
41734                 }
41735         },
41736         setAttributeNode : function(newAttr){
41737                 return this.attributes.setNamedItem(newAttr);
41738         },
41739         setAttributeNodeNS : function(newAttr){
41740                 return this.attributes.setNamedItemNS(newAttr);
41741         },
41742         removeAttributeNode : function(oldAttr){
41743                 //console.log(this == oldAttr.ownerElement)
41744                 return this.attributes.removeNamedItem(oldAttr.nodeName);
41745         },
41746         //get real attribute name,and remove it by removeAttributeNode
41747         removeAttributeNS : function(namespaceURI, localName){
41748                 var old = this.getAttributeNodeNS(namespaceURI, localName);
41749                 old && this.removeAttributeNode(old);
41750         },
41751         
41752         hasAttributeNS : function(namespaceURI, localName){
41753                 return this.getAttributeNodeNS(namespaceURI, localName)!=null;
41754         },
41755         getAttributeNS : function(namespaceURI, localName){
41756                 var attr = this.getAttributeNodeNS(namespaceURI, localName);
41757                 return attr && attr.value || '';
41758         },
41759         setAttributeNS : function(namespaceURI, qualifiedName, value){
41760                 var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
41761                 attr.value = attr.nodeValue = "" + value;
41762                 this.setAttributeNode(attr);
41763         },
41764         getAttributeNodeNS : function(namespaceURI, localName){
41765                 return this.attributes.getNamedItemNS(namespaceURI, localName);
41766         },
41767         
41768         getElementsByTagName : function(tagName){
41769                 return new LiveNodeList(this,function(base){
41770                         var ls = [];
41771                         _visitNode(base,function(node){
41772                                 if(node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)){
41773                                         ls.push(node);
41774                                 }
41775                         });
41776                         return ls;
41777                 });
41778         },
41779         getElementsByTagNameNS : function(namespaceURI, localName){
41780                 return new LiveNodeList(this,function(base){
41781                         var ls = [];
41782                         _visitNode(base,function(node){
41783                                 if(node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)){
41784                                         ls.push(node);
41785                                 }
41786                         });
41787                         return ls;
41788                         
41789                 });
41790         }
41791 };
41792 Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
41793 Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;
41794
41795
41796 _extends(Element,Node$3);
41797 function Attr() {
41798 }
41799 Attr.prototype.nodeType = ATTRIBUTE_NODE;
41800 _extends(Attr,Node$3);
41801
41802
41803 function CharacterData() {
41804 }
41805 CharacterData.prototype = {
41806         data : '',
41807         substringData : function(offset, count) {
41808                 return this.data.substring(offset, offset+count);
41809         },
41810         appendData: function(text) {
41811                 text = this.data+text;
41812                 this.nodeValue = this.data = text;
41813                 this.length = text.length;
41814         },
41815         insertData: function(offset,text) {
41816                 this.replaceData(offset,0,text);
41817         
41818         },
41819         appendChild:function(newChild){
41820                 throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR])
41821         },
41822         deleteData: function(offset, count) {
41823                 this.replaceData(offset,count,"");
41824         },
41825         replaceData: function(offset, count, text) {
41826                 var start = this.data.substring(0,offset);
41827                 var end = this.data.substring(offset+count);
41828                 text = start + text + end;
41829                 this.nodeValue = this.data = text;
41830                 this.length = text.length;
41831         }
41832 };
41833 _extends(CharacterData,Node$3);
41834 function Text() {
41835 }
41836 Text.prototype = {
41837         nodeName : "#text",
41838         nodeType : TEXT_NODE,
41839         splitText : function(offset) {
41840                 var text = this.data;
41841                 var newText = text.substring(offset);
41842                 text = text.substring(0, offset);
41843                 this.data = this.nodeValue = text;
41844                 this.length = text.length;
41845                 var newNode = this.ownerDocument.createTextNode(newText);
41846                 if(this.parentNode){
41847                         this.parentNode.insertBefore(newNode, this.nextSibling);
41848                 }
41849                 return newNode;
41850         }
41851 };
41852 _extends(Text,CharacterData);
41853 function Comment() {
41854 }
41855 Comment.prototype = {
41856         nodeName : "#comment",
41857         nodeType : COMMENT_NODE
41858 };
41859 _extends(Comment,CharacterData);
41860
41861 function CDATASection() {
41862 }
41863 CDATASection.prototype = {
41864         nodeName : "#cdata-section",
41865         nodeType : CDATA_SECTION_NODE
41866 };
41867 _extends(CDATASection,CharacterData);
41868
41869
41870 function DocumentType() {
41871 }
41872 DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
41873 _extends(DocumentType,Node$3);
41874
41875 function Notation() {
41876 }
41877 Notation.prototype.nodeType = NOTATION_NODE;
41878 _extends(Notation,Node$3);
41879
41880 function Entity() {
41881 }
41882 Entity.prototype.nodeType = ENTITY_NODE;
41883 _extends(Entity,Node$3);
41884
41885 function EntityReference() {
41886 }
41887 EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
41888 _extends(EntityReference,Node$3);
41889
41890 function DocumentFragment() {
41891 }
41892 DocumentFragment.prototype.nodeName =   "#document-fragment";
41893 DocumentFragment.prototype.nodeType =   DOCUMENT_FRAGMENT_NODE;
41894 _extends(DocumentFragment,Node$3);
41895
41896
41897 function ProcessingInstruction() {
41898 }
41899 ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
41900 _extends(ProcessingInstruction,Node$3);
41901 function XMLSerializer$1(){}
41902 XMLSerializer$1.prototype.serializeToString = function(node,isHtml,nodeFilter){
41903         return nodeSerializeToString.call(node,isHtml,nodeFilter);
41904 };
41905 Node$3.prototype.toString = nodeSerializeToString;
41906 function nodeSerializeToString(isHtml,nodeFilter){
41907         var buf = [];
41908         var refNode = this.nodeType == 9?this.documentElement:this;
41909         var prefix = refNode.prefix;
41910         var uri = refNode.namespaceURI;
41911         
41912         if(uri && prefix == null){
41913                 //console.log(prefix)
41914                 var prefix = refNode.lookupPrefix(uri);
41915                 if(prefix == null){
41916                         //isHTML = true;
41917                         var visibleNamespaces=[
41918                         {namespace:uri,prefix:null}
41919                         //{namespace:uri,prefix:''}
41920                         ];
41921                 }
41922         }
41923         serializeToString(this,buf,isHtml,nodeFilter,visibleNamespaces);
41924         //console.log('###',this.nodeType,uri,prefix,buf.join(''))
41925         return buf.join('');
41926 }
41927 function needNamespaceDefine(node,isHTML, visibleNamespaces) {
41928         var prefix = node.prefix||'';
41929         var uri = node.namespaceURI;
41930         if (!prefix && !uri){
41931                 return false;
41932         }
41933         if (prefix === "xml" && uri === "http://www.w3.org/XML/1998/namespace" 
41934                 || uri == 'http://www.w3.org/2000/xmlns/'){
41935                 return false;
41936         }
41937         
41938         var i = visibleNamespaces.length; 
41939         //console.log('@@@@',node.tagName,prefix,uri,visibleNamespaces)
41940         while (i--) {
41941                 var ns = visibleNamespaces[i];
41942                 // get namespace prefix
41943                 //console.log(node.nodeType,node.tagName,ns.prefix,prefix)
41944                 if (ns.prefix == prefix){
41945                         return ns.namespace != uri;
41946                 }
41947         }
41948         //console.log(isHTML,uri,prefix=='')
41949         //if(isHTML && prefix ==null && uri == 'http://www.w3.org/1999/xhtml'){
41950         //      return false;
41951         //}
41952         //node.flag = '11111'
41953         //console.error(3,true,node.flag,node.prefix,node.namespaceURI)
41954         return true;
41955 }
41956 function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
41957         if(nodeFilter){
41958                 node = nodeFilter(node);
41959                 if(node){
41960                         if(typeof node == 'string'){
41961                                 buf.push(node);
41962                                 return;
41963                         }
41964                 }else{
41965                         return;
41966                 }
41967                 //buf.sort.apply(attrs, attributeSorter);
41968         }
41969         switch(node.nodeType){
41970         case ELEMENT_NODE:
41971                 if (!visibleNamespaces) visibleNamespaces = [];
41972                 var startVisibleNamespaces = visibleNamespaces.length;
41973                 var attrs = node.attributes;
41974                 var len = attrs.length;
41975                 var child = node.firstChild;
41976                 var nodeName = node.tagName;
41977                 
41978                 isHTML =  (htmlns === node.namespaceURI) ||isHTML; 
41979                 buf.push('<',nodeName);
41980                 
41981                 
41982                 
41983                 for(var i=0;i<len;i++){
41984                         // add namespaces for attributes
41985                         var attr = attrs.item(i);
41986                         if (attr.prefix == 'xmlns') {
41987                                 visibleNamespaces.push({ prefix: attr.localName, namespace: attr.value });
41988                         }else if(attr.nodeName == 'xmlns'){
41989                                 visibleNamespaces.push({ prefix: '', namespace: attr.value });
41990                         }
41991                 }
41992                 for(var i=0;i<len;i++){
41993                         var attr = attrs.item(i);
41994                         if (needNamespaceDefine(attr,isHTML, visibleNamespaces)) {
41995                                 var prefix = attr.prefix||'';
41996                                 var uri = attr.namespaceURI;
41997                                 var ns = prefix ? ' xmlns:' + prefix : " xmlns";
41998                                 buf.push(ns, '="' , uri , '"');
41999                                 visibleNamespaces.push({ prefix: prefix, namespace:uri });
42000                         }
42001                         serializeToString(attr,buf,isHTML,nodeFilter,visibleNamespaces);
42002                 }
42003                 // add namespace for current node               
42004                 if (needNamespaceDefine(node,isHTML, visibleNamespaces)) {
42005                         var prefix = node.prefix||'';
42006                         var uri = node.namespaceURI;
42007                         var ns = prefix ? ' xmlns:' + prefix : " xmlns";
42008                         buf.push(ns, '="' , uri , '"');
42009                         visibleNamespaces.push({ prefix: prefix, namespace:uri });
42010                 }
42011                 
42012                 if(child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)){
42013                         buf.push('>');
42014                         //if is cdata child node
42015                         if(isHTML && /^script$/i.test(nodeName)){
42016                                 while(child){
42017                                         if(child.data){
42018                                                 buf.push(child.data);
42019                                         }else{
42020                                                 serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces);
42021                                         }
42022                                         child = child.nextSibling;
42023                                 }
42024                         }else
42025                         {
42026                                 while(child){
42027                                         serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces);
42028                                         child = child.nextSibling;
42029                                 }
42030                         }
42031                         buf.push('</',nodeName,'>');
42032                 }else{
42033                         buf.push('/>');
42034                 }
42035                 // remove added visible namespaces
42036                 //visibleNamespaces.length = startVisibleNamespaces;
42037                 return;
42038         case DOCUMENT_NODE:
42039         case DOCUMENT_FRAGMENT_NODE:
42040                 var child = node.firstChild;
42041                 while(child){
42042                         serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces);
42043                         child = child.nextSibling;
42044                 }
42045                 return;
42046         case ATTRIBUTE_NODE:
42047                 return buf.push(' ',node.name,'="',node.value.replace(/[<&"]/g,_xmlEncoder),'"');
42048         case TEXT_NODE:
42049                 return buf.push(node.data.replace(/[<&]/g,_xmlEncoder));
42050         case CDATA_SECTION_NODE:
42051                 return buf.push( '<![CDATA[',node.data,']]>');
42052         case COMMENT_NODE:
42053                 return buf.push( "<!--",node.data,"-->");
42054         case DOCUMENT_TYPE_NODE:
42055                 var pubid = node.publicId;
42056                 var sysid = node.systemId;
42057                 buf.push('<!DOCTYPE ',node.name);
42058                 if(pubid){
42059                         buf.push(' PUBLIC "',pubid);
42060                         if (sysid && sysid!='.') {
42061                                 buf.push( '" "',sysid);
42062                         }
42063                         buf.push('">');
42064                 }else if(sysid && sysid!='.'){
42065                         buf.push(' SYSTEM "',sysid,'">');
42066                 }else{
42067                         var sub = node.internalSubset;
42068                         if(sub){
42069                                 buf.push(" [",sub,"]");
42070                         }
42071                         buf.push(">");
42072                 }
42073                 return;
42074         case PROCESSING_INSTRUCTION_NODE:
42075                 return buf.push( "<?",node.target," ",node.data,"?>");
42076         case ENTITY_REFERENCE_NODE:
42077                 return buf.push( '&',node.nodeName,';');
42078         //case ENTITY_NODE:
42079         //case NOTATION_NODE:
42080         default:
42081                 buf.push('??',node.nodeName);
42082         }
42083 }
42084 function importNode(doc,node,deep){
42085         var node2;
42086         switch (node.nodeType) {
42087         case ELEMENT_NODE:
42088                 node2 = node.cloneNode(false);
42089                 node2.ownerDocument = doc;
42090                 //var attrs = node2.attributes;
42091                 //var len = attrs.length;
42092                 //for(var i=0;i<len;i++){
42093                         //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
42094                 //}
42095         case DOCUMENT_FRAGMENT_NODE:
42096                 break;
42097         case ATTRIBUTE_NODE:
42098                 deep = true;
42099                 break;
42100         //case ENTITY_REFERENCE_NODE:
42101         //case PROCESSING_INSTRUCTION_NODE:
42102         ////case TEXT_NODE:
42103         //case CDATA_SECTION_NODE:
42104         //case COMMENT_NODE:
42105         //      deep = false;
42106         //      break;
42107         //case DOCUMENT_NODE:
42108         //case DOCUMENT_TYPE_NODE:
42109         //cannot be imported.
42110         //case ENTITY_NODE:
42111         //case NOTATION_NODE:
42112         //can not hit in level3
42113         //default:throw e;
42114         }
42115         if(!node2){
42116                 node2 = node.cloneNode(false);//false
42117         }
42118         node2.ownerDocument = doc;
42119         node2.parentNode = null;
42120         if(deep){
42121                 var child = node.firstChild;
42122                 while(child){
42123                         node2.appendChild(importNode(doc,child,deep));
42124                         child = child.nextSibling;
42125                 }
42126         }
42127         return node2;
42128 }
42129 //
42130 //var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,
42131 //                                      attributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};
42132 function cloneNode(doc,node,deep){
42133         var node2 = new node.constructor();
42134         for(var n in node){
42135                 var v = node[n];
42136                 if(typeof v != 'object' ){
42137                         if(v != node2[n]){
42138                                 node2[n] = v;
42139                         }
42140                 }
42141         }
42142         if(node.childNodes){
42143                 node2.childNodes = new NodeList();
42144         }
42145         node2.ownerDocument = doc;
42146         switch (node2.nodeType) {
42147         case ELEMENT_NODE:
42148                 var attrs       = node.attributes;
42149                 var attrs2      = node2.attributes = new NamedNodeMap();
42150                 var len = attrs.length;
42151                 attrs2._ownerElement = node2;
42152                 for(var i=0;i<len;i++){
42153                         node2.setAttributeNode(cloneNode(doc,attrs.item(i),true));
42154                 }
42155                 break;;
42156         case ATTRIBUTE_NODE:
42157                 deep = true;
42158         }
42159         if(deep){
42160                 var child = node.firstChild;
42161                 while(child){
42162                         node2.appendChild(cloneNode(doc,child,deep));
42163                         child = child.nextSibling;
42164                 }
42165         }
42166         return node2;
42167 }
42168
42169 function __set__(object,key,value){
42170         object[key] = value;
42171 }
42172 //do dynamic
42173 try{
42174         if(Object.defineProperty){
42175                 Object.defineProperty(LiveNodeList.prototype,'length',{
42176                         get:function(){
42177                                 _updateLiveList(this);
42178                                 return this.$$length;
42179                         }
42180                 });
42181                 Object.defineProperty(Node$3.prototype,'textContent',{
42182                         get:function(){
42183                                 return getTextContent(this);
42184                         },
42185                         set:function(data){
42186                                 switch(this.nodeType){
42187                                 case ELEMENT_NODE:
42188                                 case DOCUMENT_FRAGMENT_NODE:
42189                                         while(this.firstChild){
42190                                                 this.removeChild(this.firstChild);
42191                                         }
42192                                         if(data || String(data)){
42193                                                 this.appendChild(this.ownerDocument.createTextNode(data));
42194                                         }
42195                                         break;
42196                                 default:
42197                                         //TODO:
42198                                         this.data = data;
42199                                         this.value = data;
42200                                         this.nodeValue = data;
42201                                 }
42202                         }
42203                 });
42204                 
42205                 function getTextContent(node){
42206                         switch(node.nodeType){
42207                         case ELEMENT_NODE:
42208                         case DOCUMENT_FRAGMENT_NODE:
42209                                 var buf = [];
42210                                 node = node.firstChild;
42211                                 while(node){
42212                                         if(node.nodeType!==7 && node.nodeType !==8){
42213                                                 buf.push(getTextContent(node));
42214                                         }
42215                                         node = node.nextSibling;
42216                                 }
42217                                 return buf.join('');
42218                         default:
42219                                 return node.nodeValue;
42220                         }
42221                 }
42222                 __set__ = function(object,key,value){
42223                         //console.log(value)
42224                         object['$$'+key] = value;
42225                 };
42226         }
42227 }catch(e){//ie8
42228 }
42229
42230 //if(typeof require == 'function'){
42231         var DOMImplementation_1 = DOMImplementation;
42232         var XMLSerializer_1 = XMLSerializer$1;
42233 //}
42234
42235 var dom = {
42236         DOMImplementation: DOMImplementation_1,
42237         XMLSerializer: XMLSerializer_1
42238 };
42239
42240 var domParser = createCommonjsModule(function (module, exports) {
42241 function DOMParser(options){
42242         this.options = options ||{locator:{}};
42243         
42244 }
42245 DOMParser.prototype.parseFromString = function(source,mimeType){
42246         var options = this.options;
42247         var sax$$1 =  new XMLReader();
42248         var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler
42249         var errorHandler = options.errorHandler;
42250         var locator = options.locator;
42251         var defaultNSMap = options.xmlns||{};
42252         var entityMap = {'lt':'<','gt':'>','amp':'&','quot':'"','apos':"'"};
42253         if(locator){
42254                 domBuilder.setDocumentLocator(locator);
42255         }
42256         
42257         sax$$1.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator);
42258         sax$$1.domBuilder = options.domBuilder || domBuilder;
42259         if(/\/x?html?$/.test(mimeType)){
42260                 entityMap.nbsp = '\xa0';
42261                 entityMap.copy = '\xa9';
42262                 defaultNSMap['']= 'http://www.w3.org/1999/xhtml';
42263         }
42264         defaultNSMap.xml = defaultNSMap.xml || 'http://www.w3.org/XML/1998/namespace';
42265         if(source){
42266                 sax$$1.parse(source,defaultNSMap,entityMap);
42267         }else{
42268                 sax$$1.errorHandler.error("invalid doc source");
42269         }
42270         return domBuilder.doc;
42271 };
42272 function buildErrorHandler(errorImpl,domBuilder,locator){
42273         if(!errorImpl){
42274                 if(domBuilder instanceof DOMHandler){
42275                         return domBuilder;
42276                 }
42277                 errorImpl = domBuilder ;
42278         }
42279         var errorHandler = {};
42280         var isCallback = errorImpl instanceof Function;
42281         locator = locator||{};
42282         function build(key){
42283                 var fn = errorImpl[key];
42284                 if(!fn && isCallback){
42285                         fn = errorImpl.length == 2?function(msg){errorImpl(key,msg);}:errorImpl;
42286                 }
42287                 errorHandler[key] = fn && function(msg){
42288                         fn('[xmldom '+key+']\t'+msg+_locator(locator));
42289                 }||function(){};
42290         }
42291         build('warning');
42292         build('error');
42293         build('fatalError');
42294         return errorHandler;
42295 }
42296
42297 //console.log('#\n\n\n\n\n\n\n####')
42298 /**
42299  * +ContentHandler+ErrorHandler
42300  * +LexicalHandler+EntityResolver2
42301  * -DeclHandler-DTDHandler 
42302  * 
42303  * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
42304  * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
42305  * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
42306  */
42307 function DOMHandler() {
42308     this.cdata = false;
42309 }
42310 function position(locator,node){
42311         node.lineNumber = locator.lineNumber;
42312         node.columnNumber = locator.columnNumber;
42313 }
42314 /**
42315  * @see org.xml.sax.ContentHandler#startDocument
42316  * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
42317  */ 
42318 DOMHandler.prototype = {
42319         startDocument : function() {
42320         this.doc = new DOMImplementation().createDocument(null, null, null);
42321         if (this.locator) {
42322                 this.doc.documentURI = this.locator.systemId;
42323         }
42324         },
42325         startElement:function(namespaceURI, localName, qName, attrs) {
42326                 var doc = this.doc;
42327             var el = doc.createElementNS(namespaceURI, qName||localName);
42328             var len = attrs.length;
42329             appendElement(this, el);
42330             this.currentElement = el;
42331             
42332                 this.locator && position(this.locator,el);
42333             for (var i = 0 ; i < len; i++) {
42334                 var namespaceURI = attrs.getURI(i);
42335                 var value = attrs.getValue(i);
42336                 var qName = attrs.getQName(i);
42337                         var attr = doc.createAttributeNS(namespaceURI, qName);
42338                         this.locator &&position(attrs.getLocator(i),attr);
42339                         attr.value = attr.nodeValue = value;
42340                         el.setAttributeNode(attr);
42341             }
42342         },
42343         endElement:function(namespaceURI, localName, qName) {
42344                 var current = this.currentElement;
42345                 var tagName = current.tagName;
42346                 this.currentElement = current.parentNode;
42347         },
42348         startPrefixMapping:function(prefix, uri) {
42349         },
42350         endPrefixMapping:function(prefix) {
42351         },
42352         processingInstruction:function(target, data) {
42353             var ins = this.doc.createProcessingInstruction(target, data);
42354             this.locator && position(this.locator,ins);
42355             appendElement(this, ins);
42356         },
42357         ignorableWhitespace:function(ch, start, length) {
42358         },
42359         characters:function(chars, start, length) {
42360                 chars = _toString.apply(this,arguments);
42361                 //console.log(chars)
42362                 if(chars){
42363                         if (this.cdata) {
42364                                 var charNode = this.doc.createCDATASection(chars);
42365                         } else {
42366                                 var charNode = this.doc.createTextNode(chars);
42367                         }
42368                         if(this.currentElement){
42369                                 this.currentElement.appendChild(charNode);
42370                         }else if(/^\s*$/.test(chars)){
42371                                 this.doc.appendChild(charNode);
42372                                 //process xml
42373                         }
42374                         this.locator && position(this.locator,charNode);
42375                 }
42376         },
42377         skippedEntity:function(name) {
42378         },
42379         endDocument:function() {
42380                 this.doc.normalize();
42381         },
42382         setDocumentLocator:function (locator) {
42383             if(this.locator = locator){// && !('lineNumber' in locator)){
42384                 locator.lineNumber = 0;
42385             }
42386         },
42387         //LexicalHandler
42388         comment:function(chars, start, length) {
42389                 chars = _toString.apply(this,arguments);
42390             var comm = this.doc.createComment(chars);
42391             this.locator && position(this.locator,comm);
42392             appendElement(this, comm);
42393         },
42394         
42395         startCDATA:function() {
42396             //used in characters() methods
42397             this.cdata = true;
42398         },
42399         endCDATA:function() {
42400             this.cdata = false;
42401         },
42402         
42403         startDTD:function(name, publicId, systemId) {
42404                 var impl = this.doc.implementation;
42405             if (impl && impl.createDocumentType) {
42406                 var dt = impl.createDocumentType(name, publicId, systemId);
42407                 this.locator && position(this.locator,dt);
42408                 appendElement(this, dt);
42409             }
42410         },
42411         /**
42412          * @see org.xml.sax.ErrorHandler
42413          * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
42414          */
42415         warning:function(error) {
42416                 console.warn('[xmldom warning]\t'+error,_locator(this.locator));
42417         },
42418         error:function(error) {
42419                 console.error('[xmldom error]\t'+error,_locator(this.locator));
42420         },
42421         fatalError:function(error) {
42422                 console.error('[xmldom fatalError]\t'+error,_locator(this.locator));
42423             throw error;
42424         }
42425 };
42426 function _locator(l){
42427         if(l){
42428                 return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']'
42429         }
42430 }
42431 function _toString(chars,start,length){
42432         if(typeof chars == 'string'){
42433                 return chars.substr(start,length)
42434         }else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
42435                 if(chars.length >= start+length || start){
42436                         return new java.lang.String(chars,start,length)+'';
42437                 }
42438                 return chars;
42439         }
42440 }
42441
42442 /*
42443  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
42444  * used method of org.xml.sax.ext.LexicalHandler:
42445  *  #comment(chars, start, length)
42446  *  #startCDATA()
42447  *  #endCDATA()
42448  *  #startDTD(name, publicId, systemId)
42449  *
42450  *
42451  * IGNORED method of org.xml.sax.ext.LexicalHandler:
42452  *  #endDTD()
42453  *  #startEntity(name)
42454  *  #endEntity(name)
42455  *
42456  *
42457  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
42458  * IGNORED method of org.xml.sax.ext.DeclHandler
42459  *      #attributeDecl(eName, aName, type, mode, value)
42460  *  #elementDecl(name, model)
42461  *  #externalEntityDecl(name, publicId, systemId)
42462  *  #internalEntityDecl(name, value)
42463  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
42464  * IGNORED method of org.xml.sax.EntityResolver2
42465  *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
42466  *  #resolveEntity(publicId, systemId)
42467  *  #getExternalSubset(name, baseURI)
42468  * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
42469  * IGNORED method of org.xml.sax.DTDHandler
42470  *  #notationDecl(name, publicId, systemId) {};
42471  *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
42472  */
42473 "endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){
42474         DOMHandler.prototype[key] = function(){return null};
42475 });
42476
42477 /* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */
42478 function appendElement (hander,node) {
42479     if (!hander.currentElement) {
42480         hander.doc.appendChild(node);
42481     } else {
42482         hander.currentElement.appendChild(node);
42483     }
42484 }//appendChild and setAttributeNS are preformance key
42485
42486 //if(typeof require == 'function'){
42487         var XMLReader = sax.XMLReader;
42488         var DOMImplementation = exports.DOMImplementation = dom.DOMImplementation;
42489         exports.XMLSerializer = dom.XMLSerializer ;
42490         exports.DOMParser = DOMParser;
42491 //}
42492 });
42493
42494 var togeojson = createCommonjsModule(function (module, exports) {
42495 var toGeoJSON = (function() {
42496     'use strict';
42497
42498     var removeSpace = /\s*/g,
42499         trimSpace = /^\s*|\s*$/g,
42500         splitSpace = /\s+/;
42501     // generate a short, numeric hash of a string
42502     function okhash(x) {
42503         if (!x || !x.length) return 0;
42504         for (var i = 0, h = 0; i < x.length; i++) {
42505             h = ((h << 5) - h) + x.charCodeAt(i) | 0;
42506         } return h;
42507     }
42508     // all Y children of X
42509     function get(x, y) { return x.getElementsByTagName(y); }
42510     function attr(x, y) { return x.getAttribute(y); }
42511     function attrf(x, y) { return parseFloat(attr(x, y)); }
42512     // one Y child of X, if any, otherwise null
42513     function get1(x, y) { var n = get(x, y); return n.length ? n[0] : null; }
42514     // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
42515     function norm(el) { if (el.normalize) { el.normalize(); } return el; }
42516     // cast array x into numbers
42517     function numarray(x) {
42518         for (var j = 0, o = []; j < x.length; j++) { o[j] = parseFloat(x[j]); }
42519         return o;
42520     }
42521     // get the content of a text node, if any
42522     function nodeVal(x) {
42523         if (x) { norm(x); }
42524         return (x && x.textContent) || '';
42525     }
42526     // get the contents of multiple text nodes, if present
42527     function getMulti(x, ys) {
42528         var o = {}, n, k;
42529         for (k = 0; k < ys.length; k++) {
42530             n = get1(x, ys[k]);
42531             if (n) o[ys[k]] = nodeVal(n);
42532         }
42533         return o;
42534     }
42535     // add properties of Y to X, overwriting if present in both
42536     function extend(x, y) { for (var k in y) x[k] = y[k]; }
42537     // get one coordinate from a coordinate array, if any
42538     function coord1(v) { return numarray(v.replace(removeSpace, '').split(',')); }
42539     // get all coordinates from a coordinate array as [[],[]]
42540     function coord(v) {
42541         var coords = v.replace(trimSpace, '').split(splitSpace),
42542             o = [];
42543         for (var i = 0; i < coords.length; i++) {
42544             o.push(coord1(coords[i]));
42545         }
42546         return o;
42547     }
42548     function coordPair(x) {
42549         var ll = [attrf(x, 'lon'), attrf(x, 'lat')],
42550             ele = get1(x, 'ele'),
42551             // handle namespaced attribute in browser
42552             heartRate = get1(x, 'gpxtpx:hr') || get1(x, 'hr'),
42553             time = get1(x, 'time'),
42554             e;
42555         if (ele) {
42556             e = parseFloat(nodeVal(ele));
42557             if (!isNaN(e)) {
42558                 ll.push(e);
42559             }
42560         }
42561         return {
42562             coordinates: ll,
42563             time: time ? nodeVal(time) : null,
42564             heartRate: heartRate ? parseFloat(nodeVal(heartRate)) : null
42565         };
42566     }
42567
42568     // create a new feature collection parent object
42569     function fc() {
42570         return {
42571             type: 'FeatureCollection',
42572             features: []
42573         };
42574     }
42575
42576     var serializer;
42577     if (typeof XMLSerializer !== 'undefined') {
42578         /* istanbul ignore next */
42579         serializer = new XMLSerializer();
42580     // only require xmldom in a node environment
42581     } else if ('object' === 'object' && typeof process === 'object' && !process.browser) {
42582         serializer = new (domParser.XMLSerializer)();
42583     }
42584     function xml2str(str) {
42585         // IE9 will create a new XMLSerializer but it'll crash immediately.
42586         // This line is ignored because we don't run coverage tests in IE9
42587         /* istanbul ignore next */
42588         if (str.xml !== undefined) return str.xml;
42589         return serializer.serializeToString(str);
42590     }
42591
42592     var t = {
42593         kml: function(doc) {
42594
42595             var gj = fc(),
42596                 // styleindex keeps track of hashed styles in order to match features
42597                 styleIndex = {}, styleByHash = {},
42598                 // stylemapindex keeps track of style maps to expose in properties
42599                 styleMapIndex = {},
42600                 // atomic geospatial types supported by KML - MultiGeometry is
42601                 // handled separately
42602                 geotypes = ['Polygon', 'LineString', 'Point', 'Track', 'gx:Track'],
42603                 // all root placemarks in the file
42604                 placemarks = get(doc, 'Placemark'),
42605                 styles = get(doc, 'Style'),
42606                 styleMaps = get(doc, 'StyleMap');
42607
42608             for (var k = 0; k < styles.length; k++) {
42609                 var hash = okhash(xml2str(styles[k])).toString(16);
42610                 styleIndex['#' + attr(styles[k], 'id')] = hash;
42611                 styleByHash[hash] = styles[k];
42612             }
42613             for (var l = 0; l < styleMaps.length; l++) {
42614                 styleIndex['#' + attr(styleMaps[l], 'id')] = okhash(xml2str(styleMaps[l])).toString(16);
42615                 var pairs = get(styleMaps[l], 'Pair');
42616                 var pairsMap = {};
42617                 for (var m = 0; m < pairs.length; m++) {
42618                     pairsMap[nodeVal(get1(pairs[m], 'key'))] = nodeVal(get1(pairs[m], 'styleUrl'));
42619                 }
42620                 styleMapIndex['#' + attr(styleMaps[l], 'id')] = pairsMap;
42621
42622             }
42623             for (var j = 0; j < placemarks.length; j++) {
42624                 gj.features = gj.features.concat(getPlacemark(placemarks[j]));
42625             }
42626             function kmlColor(v) {
42627                 var color, opacity;
42628                 v = v || '';
42629                 if (v.substr(0, 1) === '#') { v = v.substr(1); }
42630                 if (v.length === 6 || v.length === 3) { color = v; }
42631                 if (v.length === 8) {
42632                     opacity = parseInt(v.substr(0, 2), 16) / 255;
42633                     color = '#' + v.substr(6, 2) +
42634                         v.substr(4, 2) +
42635                         v.substr(2, 2);
42636                 }
42637                 return [color, isNaN(opacity) ? undefined : opacity];
42638             }
42639             function gxCoord(v) { return numarray(v.split(' ')); }
42640             function gxCoords(root) {
42641                 var elems = get(root, 'coord', 'gx'), coords = [], times = [];
42642                 if (elems.length === 0) elems = get(root, 'gx:coord');
42643                 for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i])));
42644                 var timeElems = get(root, 'when');
42645                 for (var j = 0; j < timeElems.length; j++) times.push(nodeVal(timeElems[j]));
42646                 return {
42647                     coords: coords,
42648                     times: times
42649                 };
42650             }
42651             function getGeometry(root) {
42652                 var geomNode, geomNodes, i, j, k, geoms = [], coordTimes = [];
42653                 if (get1(root, 'MultiGeometry')) { return getGeometry(get1(root, 'MultiGeometry')); }
42654                 if (get1(root, 'MultiTrack')) { return getGeometry(get1(root, 'MultiTrack')); }
42655                 if (get1(root, 'gx:MultiTrack')) { return getGeometry(get1(root, 'gx:MultiTrack')); }
42656                 for (i = 0; i < geotypes.length; i++) {
42657                     geomNodes = get(root, geotypes[i]);
42658                     if (geomNodes) {
42659                         for (j = 0; j < geomNodes.length; j++) {
42660                             geomNode = geomNodes[j];
42661                             if (geotypes[i] === 'Point') {
42662                                 geoms.push({
42663                                     type: 'Point',
42664                                     coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
42665                                 });
42666                             } else if (geotypes[i] === 'LineString') {
42667                                 geoms.push({
42668                                     type: 'LineString',
42669                                     coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
42670                                 });
42671                             } else if (geotypes[i] === 'Polygon') {
42672                                 var rings = get(geomNode, 'LinearRing'),
42673                                     coords = [];
42674                                 for (k = 0; k < rings.length; k++) {
42675                                     coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
42676                                 }
42677                                 geoms.push({
42678                                     type: 'Polygon',
42679                                     coordinates: coords
42680                                 });
42681                             } else if (geotypes[i] === 'Track' ||
42682                                 geotypes[i] === 'gx:Track') {
42683                                 var track = gxCoords(geomNode);
42684                                 geoms.push({
42685                                     type: 'LineString',
42686                                     coordinates: track.coords
42687                                 });
42688                                 if (track.times.length) coordTimes.push(track.times);
42689                             }
42690                         }
42691                     }
42692                 }
42693                 return {
42694                     geoms: geoms,
42695                     coordTimes: coordTimes
42696                 };
42697             }
42698             function getPlacemark(root) {
42699                 var geomsAndTimes = getGeometry(root), i, properties = {},
42700                     name = nodeVal(get1(root, 'name')),
42701                     address = nodeVal(get1(root, 'address')),
42702                     styleUrl = nodeVal(get1(root, 'styleUrl')),
42703                     description = nodeVal(get1(root, 'description')),
42704                     timeSpan = get1(root, 'TimeSpan'),
42705                     timeStamp = get1(root, 'TimeStamp'),
42706                     extendedData = get1(root, 'ExtendedData'),
42707                     lineStyle = get1(root, 'LineStyle'),
42708                     polyStyle = get1(root, 'PolyStyle'),
42709                     visibility = get1(root, 'visibility');
42710
42711                 if (!geomsAndTimes.geoms.length) return [];
42712                 if (name) properties.name = name;
42713                 if (address) properties.address = address;
42714                 if (styleUrl) {
42715                     if (styleUrl[0] !== '#') {
42716                         styleUrl = '#' + styleUrl;
42717                     }
42718
42719                     properties.styleUrl = styleUrl;
42720                     if (styleIndex[styleUrl]) {
42721                         properties.styleHash = styleIndex[styleUrl];
42722                     }
42723                     if (styleMapIndex[styleUrl]) {
42724                         properties.styleMapHash = styleMapIndex[styleUrl];
42725                         properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal];
42726                     }
42727                     // Try to populate the lineStyle or polyStyle since we got the style hash
42728                     var style = styleByHash[properties.styleHash];
42729                     if (style) {
42730                         if (!lineStyle) lineStyle = get1(style, 'LineStyle');
42731                         if (!polyStyle) polyStyle = get1(style, 'PolyStyle');
42732                     }
42733                 }
42734                 if (description) properties.description = description;
42735                 if (timeSpan) {
42736                     var begin = nodeVal(get1(timeSpan, 'begin'));
42737                     var end = nodeVal(get1(timeSpan, 'end'));
42738                     properties.timespan = { begin: begin, end: end };
42739                 }
42740                 if (timeStamp) {
42741                     properties.timestamp = nodeVal(get1(timeStamp, 'when'));
42742                 }
42743                 if (lineStyle) {
42744                     var linestyles = kmlColor(nodeVal(get1(lineStyle, 'color'))),
42745                         color = linestyles[0],
42746                         opacity = linestyles[1],
42747                         width = parseFloat(nodeVal(get1(lineStyle, 'width')));
42748                     if (color) properties.stroke = color;
42749                     if (!isNaN(opacity)) properties['stroke-opacity'] = opacity;
42750                     if (!isNaN(width)) properties['stroke-width'] = width;
42751                 }
42752                 if (polyStyle) {
42753                     var polystyles = kmlColor(nodeVal(get1(polyStyle, 'color'))),
42754                         pcolor = polystyles[0],
42755                         popacity = polystyles[1],
42756                         fill = nodeVal(get1(polyStyle, 'fill')),
42757                         outline = nodeVal(get1(polyStyle, 'outline'));
42758                     if (pcolor) properties.fill = pcolor;
42759                     if (!isNaN(popacity)) properties['fill-opacity'] = popacity;
42760                     if (fill) properties['fill-opacity'] = fill === '1' ? properties['fill-opacity'] || 1 : 0;
42761                     if (outline) properties['stroke-opacity'] = outline === '1' ? properties['stroke-opacity'] || 1 : 0;
42762                 }
42763                 if (extendedData) {
42764                     var datas = get(extendedData, 'Data'),
42765                         simpleDatas = get(extendedData, 'SimpleData');
42766
42767                     for (i = 0; i < datas.length; i++) {
42768                         properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
42769                     }
42770                     for (i = 0; i < simpleDatas.length; i++) {
42771                         properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
42772                     }
42773                 }
42774                 if (visibility) {
42775                     properties.visibility = nodeVal(visibility);
42776                 }
42777                 if (geomsAndTimes.coordTimes.length) {
42778                     properties.coordTimes = (geomsAndTimes.coordTimes.length === 1) ?
42779                         geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes;
42780                 }
42781                 var feature = {
42782                     type: 'Feature',
42783                     geometry: (geomsAndTimes.geoms.length === 1) ? geomsAndTimes.geoms[0] : {
42784                         type: 'GeometryCollection',
42785                         geometries: geomsAndTimes.geoms
42786                     },
42787                     properties: properties
42788                 };
42789                 if (attr(root, 'id')) feature.id = attr(root, 'id');
42790                 return [feature];
42791             }
42792             return gj;
42793         },
42794         gpx: function(doc) {
42795             var i,
42796                 tracks = get(doc, 'trk'),
42797                 routes = get(doc, 'rte'),
42798                 waypoints = get(doc, 'wpt'),
42799                 // a feature collection
42800                 gj = fc(),
42801                 feature;
42802             for (i = 0; i < tracks.length; i++) {
42803                 feature = getTrack(tracks[i]);
42804                 if (feature) gj.features.push(feature);
42805             }
42806             for (i = 0; i < routes.length; i++) {
42807                 feature = getRoute(routes[i]);
42808                 if (feature) gj.features.push(feature);
42809             }
42810             for (i = 0; i < waypoints.length; i++) {
42811                 gj.features.push(getPoint(waypoints[i]));
42812             }
42813             function getPoints(node, pointname) {
42814                 var pts = get(node, pointname),
42815                     line = [],
42816                     times = [],
42817                     heartRates = [],
42818                     l = pts.length;
42819                 if (l < 2) return {};  // Invalid line in GeoJSON
42820                 for (var i = 0; i < l; i++) {
42821                     var c = coordPair(pts[i]);
42822                     line.push(c.coordinates);
42823                     if (c.time) times.push(c.time);
42824                     if (c.heartRate) heartRates.push(c.heartRate);
42825                 }
42826                 return {
42827                     line: line,
42828                     times: times,
42829                     heartRates: heartRates
42830                 };
42831             }
42832             function getTrack(node) {
42833                 var segments = get(node, 'trkseg'),
42834                     track = [],
42835                     times = [],
42836                     heartRates = [],
42837                     line;
42838                 for (var i = 0; i < segments.length; i++) {
42839                     line = getPoints(segments[i], 'trkpt');
42840                     if (line) {
42841                         if (line.line) track.push(line.line);
42842                         if (line.times && line.times.length) times.push(line.times);
42843                         if (line.heartRates && line.heartRates.length) heartRates.push(line.heartRates);
42844                     }
42845                 }
42846                 if (track.length === 0) return;
42847                 var properties = getProperties(node);
42848                 extend(properties, getLineStyle(get1(node, 'extensions')));
42849                 if (times.length) properties.coordTimes = track.length === 1 ? times[0] : times;
42850                 if (heartRates.length) properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
42851                 return {
42852                     type: 'Feature',
42853                     properties: properties,
42854                     geometry: {
42855                         type: track.length === 1 ? 'LineString' : 'MultiLineString',
42856                         coordinates: track.length === 1 ? track[0] : track
42857                     }
42858                 };
42859             }
42860             function getRoute(node) {
42861                 var line = getPoints(node, 'rtept');
42862                 if (!line.line) return;
42863                 var prop = getProperties(node);
42864                 extend(prop, getLineStyle(get1(node, 'extensions')));
42865                 var routeObj = {
42866                     type: 'Feature',
42867                     properties: prop,
42868                     geometry: {
42869                         type: 'LineString',
42870                         coordinates: line.line
42871                     }
42872                 };
42873                 return routeObj;
42874             }
42875             function getPoint(node) {
42876                 var prop = getProperties(node);
42877                 extend(prop, getMulti(node, ['sym']));
42878                 return {
42879                     type: 'Feature',
42880                     properties: prop,
42881                     geometry: {
42882                         type: 'Point',
42883                         coordinates: coordPair(node).coordinates
42884                     }
42885                 };
42886             }
42887             function getLineStyle(extensions) {
42888                 var style = {};
42889                 if (extensions) {
42890                     var lineStyle = get1(extensions, 'line');
42891                     if (lineStyle) {
42892                         var color = nodeVal(get1(lineStyle, 'color')),
42893                             opacity = parseFloat(nodeVal(get1(lineStyle, 'opacity'))),
42894                             width = parseFloat(nodeVal(get1(lineStyle, 'width')));
42895                         if (color) style.stroke = color;
42896                         if (!isNaN(opacity)) style['stroke-opacity'] = opacity;
42897                         // GPX width is in mm, convert to px with 96 px per inch
42898                         if (!isNaN(width)) style['stroke-width'] = width * 96 / 25.4;
42899                     }
42900                 }
42901                 return style;
42902             }
42903             function getProperties(node) {
42904                 var prop = getMulti(node, ['name', 'cmt', 'desc', 'type', 'time', 'keywords']),
42905                     links = get(node, 'link');
42906                 if (links.length) prop.links = [];
42907                 for (var i = 0, link; i < links.length; i++) {
42908                     link = { href: attr(links[i], 'href') };
42909                     extend(link, getMulti(links[i], ['text', 'type']));
42910                     prop.links.push(link);
42911                 }
42912                 return prop;
42913             }
42914             return gj;
42915         }
42916     };
42917     return t;
42918 })();
42919
42920 module.exports = toGeoJSON;
42921 });
42922
42923 function svgGpx(projection, context, dispatch$$1) {
42924     var showLabels = true,
42925         detected = utilDetect(),
42926         layer;
42927
42928
42929     function init() {
42930         if (svgGpx.initialized) return;  // run once
42931
42932         svgGpx.geojson = {};
42933         svgGpx.enabled = true;
42934
42935         function over() {
42936             event.stopPropagation();
42937             event.preventDefault();
42938             event.dataTransfer.dropEffect = 'copy';
42939         }
42940
42941         select('body')
42942             .attr('dropzone', 'copy')
42943             .on('drop.localgpx', function() {
42944                 event.stopPropagation();
42945                 event.preventDefault();
42946                 if (!detected.filedrop) return;
42947                 drawGpx.files(event.dataTransfer.files);
42948             })
42949             .on('dragenter.localgpx', over)
42950             .on('dragexit.localgpx', over)
42951             .on('dragover.localgpx', over);
42952
42953         svgGpx.initialized = true;
42954     }
42955
42956
42957     function drawGpx(selection$$1) {
42958         var geojson = svgGpx.geojson,
42959             enabled = svgGpx.enabled;
42960
42961         layer = selection$$1.selectAll('.layer-gpx')
42962             .data(enabled ? [0] : []);
42963
42964         layer.exit()
42965             .remove();
42966
42967         layer = layer.enter()
42968             .append('g')
42969             .attr('class', 'layer-gpx')
42970             .merge(layer);
42971
42972
42973         var paths = layer
42974             .selectAll('path')
42975             .data([geojson]);
42976
42977         paths.exit()
42978             .remove();
42979
42980         paths = paths.enter()
42981             .append('path')
42982             .attr('class', 'gpx')
42983             .merge(paths);
42984
42985
42986         var path$$1 = index$4(projection);
42987
42988         paths
42989             .attr('d', path$$1);
42990
42991
42992         var labels = layer.selectAll('text')
42993             .data(showLabels && geojson.features ? geojson.features : []);
42994
42995         labels.exit()
42996             .remove();
42997
42998         labels = labels.enter()
42999             .append('text')
43000             .attr('class', 'gpx')
43001             .merge(labels);
43002
43003         labels
43004             .text(function(d) {
43005                 return d.properties.desc || d.properties.name;
43006             })
43007             .attr('x', function(d) {
43008                 var centroid = path$$1.centroid(d);
43009                 return centroid[0] + 7;
43010             })
43011             .attr('y', function(d) {
43012                 var centroid = path$$1.centroid(d);
43013                 return centroid[1];
43014             });
43015
43016     }
43017
43018
43019     function toDom(x) {
43020         return (new DOMParser()).parseFromString(x, 'text/xml');
43021     }
43022
43023
43024     function getExtension(fileName) {
43025         if (lodash.isUndefined(fileName)) {
43026             return '';
43027         }
43028
43029         var lastDotIndex = fileName.lastIndexOf('.');
43030         if (lastDotIndex < 0) {
43031             return '';
43032         }
43033
43034         return fileName.substr(lastDotIndex);
43035     }
43036
43037
43038     function parseSaveAndZoom(extension, data) {
43039         switch (extension) {
43040             default:
43041                 drawGpx.geojson(togeojson.gpx(toDom(data))).fitZoom();
43042                 break;
43043             case '.kml':
43044                 drawGpx.geojson(togeojson.kml(toDom(data))).fitZoom();
43045                 break;
43046             case '.geojson':
43047             case '.json':
43048                 drawGpx.geojson(JSON.parse(data)).fitZoom();
43049                 break;
43050         }
43051     }
43052
43053
43054     drawGpx.showLabels = function(_) {
43055         if (!arguments.length) return showLabels;
43056         showLabels = _;
43057         return this;
43058     };
43059
43060
43061     drawGpx.enabled = function(_) {
43062         if (!arguments.length) return svgGpx.enabled;
43063         svgGpx.enabled = _;
43064         dispatch$$1.call('change');
43065         return this;
43066     };
43067
43068
43069     drawGpx.hasGpx = function() {
43070         var geojson = svgGpx.geojson;
43071         return (!(lodash.isEmpty(geojson) || lodash.isEmpty(geojson.features)));
43072     };
43073
43074
43075     drawGpx.geojson = function(gj) {
43076         if (!arguments.length) return svgGpx.geojson;
43077         if (lodash.isEmpty(gj) || lodash.isEmpty(gj.features)) return this;
43078         svgGpx.geojson = gj;
43079         dispatch$$1.call('change');
43080         return this;
43081     };
43082
43083
43084     drawGpx.url = function(url) {
43085         text(url, function(err, data) {
43086             if (!err) {
43087                 var extension = getExtension(url);
43088                 parseSaveAndZoom(extension, data);
43089             }
43090         });
43091         return this;
43092     };
43093
43094
43095     drawGpx.files = function(fileList) {
43096         if (!fileList.length) return this;
43097         var f = fileList[0],
43098             reader = new FileReader();
43099
43100         reader.onload = (function(file) {
43101             var extension = getExtension(file.name);
43102
43103             return function (e) {
43104                 parseSaveAndZoom(extension, e.target.result);
43105             };
43106         })(f);
43107
43108         reader.readAsText(f);
43109         return this;
43110     };
43111
43112
43113     drawGpx.fitZoom = function() {
43114         if (!this.hasGpx()) return this;
43115         var geojson = svgGpx.geojson;
43116
43117         var map$$1 = context.map(),
43118             viewport = map$$1.trimmedExtent().polygon(),
43119             coords = lodash.reduce(geojson.features, function(coords, feature) {
43120                 var c = feature.geometry.coordinates;
43121
43122                 /* eslint-disable no-fallthrough */
43123                 switch (feature.geometry.type) {
43124                     case 'Point':
43125                         c = [c];
43126                     case 'MultiPoint':
43127                     case 'LineString':
43128                         break;
43129
43130                     case 'MultiPolygon':
43131                         c = lodash.flatten(c);
43132                     case 'Polygon':
43133                     case 'MultiLineString':
43134                         c = lodash.flatten(c);
43135                         break;
43136                 }
43137                 /* eslint-enable no-fallthrough */
43138
43139                 return lodash.union(coords, c);
43140             }, []);
43141
43142         if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
43143             var extent$$1 = geoExtent$$1(bounds({ type: 'LineString', coordinates: coords }));
43144             map$$1.centerZoom(extent$$1.center(), map$$1.trimmedExtentZoom(extent$$1));
43145         }
43146
43147         return this;
43148     };
43149
43150
43151     init();
43152     return drawGpx;
43153 }
43154
43155 function svgIcon(name, svgklass, useklass) {
43156     return function drawIcon(selection) {
43157         selection.selectAll('svg')
43158             .data([0])
43159             .enter()
43160             .append('svg')
43161             .attr('class', 'icon ' + (svgklass || ''))
43162             .append('use')
43163             .attr('xlink:href', name)
43164             .attr('class', useklass);
43165     };
43166 }
43167
43168 function svgLabels(projection, context) {
43169     var path$$1 = index$4(projection),
43170         detected = utilDetect(),
43171         baselineHack = (detected.ie || detected.browser.toLowerCase() === 'edge'),
43172         rdrawn = index$9(),
43173         rskipped = index$9(),
43174         textWidthCache = {},
43175         entitybboxes = {};
43176
43177     // Listed from highest to lowest priority
43178     var labelStack = [
43179         ['line', 'aeroway', '*', 12],
43180         ['line', 'highway', 'motorway', 12],
43181         ['line', 'highway', 'trunk', 12],
43182         ['line', 'highway', 'primary', 12],
43183         ['line', 'highway', 'secondary', 12],
43184         ['line', 'highway', 'tertiary', 12],
43185         ['line', 'highway', '*', 12],
43186         ['line', 'railway', '*', 12],
43187         ['line', 'waterway', '*', 12],
43188         ['area', 'aeroway', '*', 12],
43189         ['area', 'amenity', '*', 12],
43190         ['area', 'building', '*', 12],
43191         ['area', 'historic', '*', 12],
43192         ['area', 'leisure', '*', 12],
43193         ['area', 'man_made', '*', 12],
43194         ['area', 'natural', '*', 12],
43195         ['area', 'shop', '*', 12],
43196         ['area', 'tourism', '*', 12],
43197         ['area', 'camp_site', '*', 12],
43198         ['point', 'aeroway', '*', 10],
43199         ['point', 'amenity', '*', 10],
43200         ['point', 'building', '*', 10],
43201         ['point', 'historic', '*', 10],
43202         ['point', 'leisure', '*', 10],
43203         ['point', 'man_made', '*', 10],
43204         ['point', 'natural', '*', 10],
43205         ['point', 'shop', '*', 10],
43206         ['point', 'tourism', '*', 10],
43207         ['point', 'camp_site', '*', 10],
43208         ['line', 'name', '*', 12],
43209         ['area', 'name', '*', 12],
43210         ['point', 'name', '*', 10]
43211     ];
43212
43213
43214     function blacklisted(preset) {
43215         var noIcons = ['building', 'landuse', 'natural'];
43216         return lodash.some(noIcons, function(s) {
43217             return preset.id.indexOf(s) >= 0;
43218         });
43219     }
43220
43221
43222     function get(array, prop) {
43223         return function(d, i) { return array[i][prop]; };
43224     }
43225
43226
43227     function textWidth(text$$1, size, elem) {
43228         var c = textWidthCache[size];
43229         if (!c) c = textWidthCache[size] = {};
43230
43231         if (c[text$$1]) {
43232             return c[text$$1];
43233
43234         } else if (elem) {
43235             c[text$$1] = elem.getComputedTextLength();
43236             return c[text$$1];
43237
43238         } else {
43239             var str = encodeURIComponent(text$$1).match(/%[CDEFcdef]/g);
43240             if (str === null) {
43241                 return size / 3 * 2 * text$$1.length;
43242             } else {
43243                 return size / 3 * (2 * text$$1.length + str.length);
43244             }
43245         }
43246     }
43247
43248
43249     function drawLinePaths(selection$$1, entities, filter, classes, labels) {
43250         var paths = selection$$1.selectAll('path')
43251             .filter(filter)
43252             .data(entities, osmEntity$$1.key);
43253
43254         paths.exit()
43255             .remove();
43256
43257         paths.enter()
43258             .append('path')
43259             .style('stroke-width', get(labels, 'font-size'))
43260             .attr('id', function(d) { return 'labelpath-' + d.id; })
43261             .attr('class', classes)
43262             .merge(paths)
43263             .attr('d', get(labels, 'lineString'));
43264     }
43265
43266
43267     function drawLineLabels(selection$$1, entities, filter, classes, labels) {
43268         var texts = selection$$1.selectAll('text.' + classes)
43269             .filter(filter)
43270             .data(entities, osmEntity$$1.key);
43271
43272         texts.exit()
43273             .remove();
43274
43275         texts.enter()
43276             .append('text')
43277             .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; })
43278             .attr('dy', baselineHack ? '0.35em' : null)
43279             .append('textPath')
43280             .attr('class', 'textpath');
43281
43282         texts = selection$$1.selectAll('text.' + classes);
43283
43284         texts.selectAll('.textpath')
43285             .filter(filter)
43286             .data(entities, osmEntity$$1.key)
43287             .attr('startOffset', '50%')
43288             .attr('xlink:href', function(d) { return '#labelpath-' + d.id; })
43289             .text(utilDisplayNameForPath);
43290     }
43291
43292
43293     function drawPointLabels(selection$$1, entities, filter, classes, labels) {
43294         var texts = selection$$1.selectAll('text.' + classes)
43295             .filter(filter)
43296             .data(entities, osmEntity$$1.key);
43297
43298         texts.exit()
43299             .remove();
43300
43301         texts = texts.enter()
43302             .append('text')
43303             .attr('class', function(d, i) {
43304                 return classes + ' ' + labels[i].classes + ' ' + d.id;
43305             })
43306             .merge(texts);
43307
43308         texts
43309             .attr('x', get(labels, 'x'))
43310             .attr('y', get(labels, 'y'))
43311             .style('text-anchor', get(labels, 'textAnchor'))
43312             .text(utilDisplayName)
43313             .each(function(d, i) {
43314                 textWidth(utilDisplayName(d), labels[i].height, this);
43315             });
43316     }
43317
43318
43319     function drawAreaLabels(selection$$1, entities, filter, classes, labels) {
43320         entities = entities.filter(hasText);
43321         labels = labels.filter(hasText);
43322         drawPointLabels(selection$$1, entities, filter, classes, labels);
43323
43324         function hasText(d, i) {
43325             return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
43326         }
43327     }
43328
43329
43330     function drawAreaIcons(selection$$1, entities, filter, classes, labels) {
43331         var icons = selection$$1.selectAll('use.' + classes)
43332             .filter(filter)
43333             .data(entities, osmEntity$$1.key);
43334
43335         icons.exit()
43336             .remove();
43337
43338         icons = icons.enter()
43339             .append('use')
43340             .attr('class', 'icon ' + classes)
43341             .attr('width', '17px')
43342             .attr('height', '17px')
43343             .merge(icons);
43344
43345         icons
43346             .attr('transform', get(labels, 'transform'))
43347             .attr('xlink:href', function(d) {
43348                 var preset = context.presets().match(d, context.graph()),
43349                     picon = preset && preset.icon;
43350
43351                 if (!picon)
43352                     return '';
43353                 else {
43354                     var isMaki = dataFeatureIcons.indexOf(picon) !== -1;
43355                     return '#' + picon + (isMaki ? '-15' : '');
43356                 }
43357             });
43358     }
43359
43360
43361     function drawCollisionBoxes(selection$$1, rtree, which) {
43362         var showDebug = context.getDebug('collision'),
43363             classes = 'debug ' + which + ' ' +
43364                 (which === 'debug-skipped' ? 'orange' : 'yellow');
43365
43366         var debug = selection$$1.selectAll('.layer-label-debug')
43367                 .data(showDebug ? [true] : []);
43368
43369         debug.exit()
43370             .remove();
43371
43372         debug = debug.enter()
43373             .append('g')
43374             .attr('class', 'layer-label-debug')
43375             .merge(debug);
43376
43377         if (showDebug) {
43378             var gj = rtree.all().map(function(d) {
43379                 return { type: 'Polygon', coordinates: [[
43380                     [d.minX, d.minY],
43381                     [d.maxX, d.minY],
43382                     [d.maxX, d.maxY],
43383                     [d.minX, d.maxY],
43384                     [d.minX, d.minY]
43385                 ]]};
43386             });
43387
43388             var debugboxes = debug.selectAll('.' + which)
43389                 .data(gj);
43390
43391             debugboxes.exit()
43392                 .remove();
43393
43394             debugboxes = debugboxes.enter()
43395                 .append('path')
43396                 .attr('class', classes)
43397                 .merge(debugboxes);
43398
43399             debugboxes
43400                 .attr('d', index$4());
43401         }
43402     }
43403
43404
43405     function drawLabels(selection$$1, graph, entities, filter, dimensions, fullRedraw) {
43406         var lowZoom = context.surface().classed('low-zoom');
43407
43408         var labelable = [], i, j, k, entity, geometry;
43409         for (i = 0; i < labelStack.length; i++) {
43410             labelable.push([]);
43411         }
43412
43413         if (fullRedraw) {
43414             rdrawn.clear();
43415             rskipped.clear();
43416             entitybboxes = {};
43417         } else {
43418             for (i = 0; i < entities.length; i++) {
43419                 entity = entities[i];
43420                 var toRemove = []
43421                     .concat(entitybboxes[entity.id] || [])
43422                     .concat(entitybboxes[entity.id + 'I'] || []);
43423
43424                 for (j = 0; j < toRemove.length; j++) {
43425                     rdrawn.remove(toRemove[j]);
43426                     rskipped.remove(toRemove[j]);
43427                 }
43428             }
43429         }
43430
43431         // Split entities into groups specified by labelStack
43432         for (i = 0; i < entities.length; i++) {
43433             entity = entities[i];
43434             geometry = entity.geometry(graph);
43435             if (geometry === 'vertex') { geometry = 'point'; }  // treat vertex like point
43436
43437             var preset = geometry === 'area' && context.presets().match(entity, graph),
43438                 icon = preset && !blacklisted(preset) && preset.icon;
43439
43440             if (!icon && !utilDisplayName(entity))
43441                 continue;
43442
43443             for (k = 0; k < labelStack.length; k++) {
43444                 var matchGeom = labelStack[k][0],
43445                     matchKey = labelStack[k][1],
43446                     matchVal = labelStack[k][2],
43447                     hasVal = entity.tags[matchKey];
43448
43449                 if (geometry === matchGeom && hasVal && (matchVal === '*' || matchVal === hasVal)) {
43450                     labelable[k].push(entity);
43451                     break;
43452                 }
43453             }
43454         }
43455
43456         var positions = {
43457             point: [],
43458             line: [],
43459             area: []
43460         };
43461
43462         var labelled = {
43463             point: [],
43464             line: [],
43465             area: []
43466         };
43467
43468         // Try and find a valid label for labellable entities
43469         for (k = 0; k < labelable.length; k++) {
43470             var fontSize = labelStack[k][3];
43471             for (i = 0; i < labelable[k].length; i++) {
43472                 entity = labelable[k][i];
43473                 geometry = entity.geometry(graph);
43474
43475                 var getName = (geometry === 'line') ? utilDisplayNameForPath : utilDisplayName,
43476                     name = getName(entity),
43477                     width = name && textWidth(name, fontSize),
43478                     p;
43479
43480                 if (geometry === 'point') {
43481                     p = getPointLabel(entity, width, fontSize, geometry);
43482                 } else if (geometry === 'vertex' && !lowZoom) {
43483                     // don't label vertices at low zoom because they don't have icons
43484                     p = getPointLabel(entity, width, fontSize, geometry);
43485                 } else if (geometry === 'line') {
43486                     p = getLineLabel(entity, width, fontSize);
43487                 } else if (geometry === 'area') {
43488                     p = getAreaLabel(entity, width, fontSize);
43489                 }
43490
43491                 if (p) {
43492                     if (geometry === 'vertex') { geometry = 'point'; }  // treat vertex like point
43493                     p.classes = geometry + ' tag-' + labelStack[k][1];
43494                     positions[geometry].push(p);
43495                     labelled[geometry].push(entity);
43496                 }
43497             }
43498         }
43499
43500
43501         function getPointLabel(entity, width, height, geometry) {
43502             var y = (geometry === 'point' ? -12 : 0),
43503                 pointOffsets = {
43504                     ltr: [15, y, 'start'],
43505                     rtl: [-15, y, 'end']
43506                 };
43507
43508             var coord = projection(entity.loc),
43509                 margin = 2,
43510                 offset = pointOffsets[textDirection],
43511                 p = {
43512                     height: height,
43513                     width: width,
43514                     x: coord[0] + offset[0],
43515                     y: coord[1] + offset[1],
43516                     textAnchor: offset[2]
43517                 },
43518                 bbox;
43519
43520             if (textDirection === 'rtl') {
43521                 bbox = {
43522                     minX: p.x - width - margin,
43523                     minY: p.y - (height / 2) - margin,
43524                     maxX: p.x + margin,
43525                     maxY: p.y + (height / 2) + margin
43526                 };
43527             } else {
43528                 bbox = {
43529                     minX: p.x - margin,
43530                     minY: p.y - (height / 2) - margin,
43531                     maxX: p.x + width + margin,
43532                     maxY: p.y + (height / 2) + margin
43533                 };
43534             }
43535
43536             if (tryInsert([bbox], entity.id, true)) {
43537                 return p;
43538             }
43539         }
43540
43541
43542         function getLineLabel(entity, width, height) {
43543             var viewport = geoExtent$$1(context.projection.clipExtent()).polygon(),
43544                 nodes = lodash.map(graph.childNodes(entity), 'loc').map(projection),
43545                 length = geoPathLength(nodes);
43546
43547             if (length < width + 20) return;
43548
43549             // % along the line to attempt to place the label
43550             var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70,
43551                                25, 75, 20, 80, 15, 95, 10, 90, 5, 95];
43552             var margin = 3;
43553
43554             for (var i = 0; i < lineOffsets.length; i++) {
43555                 var offset = lineOffsets[i],
43556                     middle = offset / 100 * length,
43557                     start = middle - width / 2;
43558
43559                 if (start < 0 || start + width > length) continue;
43560
43561                 // generate subpath and ignore paths that are invalid or don't cross viewport.
43562                 var sub = subpath(nodes, start, start + width);
43563                 if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
43564                     continue;
43565                 }
43566
43567                 var isReverse = reverse(sub);
43568                 if (isReverse) {
43569                     sub = sub.reverse();
43570                 }
43571
43572                 var bboxes = [],
43573                     boxsize = (height + 2) / 2;
43574
43575                 for (var j = 0; j < sub.length - 1; j++) {
43576                     var a = sub[j];
43577                     var b = sub[j + 1];
43578                     var num = Math.max(1, Math.floor(geoEuclideanDistance(a, b) / boxsize / 2));
43579
43580                     for (var box = 0; box < num; box++) {
43581                         var p = geoInterp(a, b, box / num);
43582                         var x0 = p[0] - boxsize - margin;
43583                         var y0 = p[1] - boxsize - margin;
43584                         var x1 = p[0] + boxsize + margin;
43585                         var y1 = p[1] + boxsize + margin;
43586
43587                         bboxes.push({
43588                             minX: Math.min(x0, x1),
43589                             minY: Math.min(y0, y1),
43590                             maxX: Math.max(x0, x1),
43591                             maxY: Math.max(y0, y1)
43592                         });
43593                     }
43594                 }
43595
43596                 if (tryInsert(bboxes, entity.id, false)) {
43597                     return {
43598                         'font-size': height + 2,
43599                         lineString: lineString(sub),
43600                         startOffset: offset + '%'
43601                     };
43602                 }
43603             }
43604
43605             function reverse(p) {
43606                 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
43607                 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > -Math.PI/2);
43608             }
43609
43610             function lineString(nodes) {
43611                 return 'M' + nodes.join('L');
43612             }
43613
43614             function subpath(nodes, from, to) {
43615                 var sofar = 0,
43616                     start, end, i0, i1;
43617
43618                 for (var i = 0; i < nodes.length - 1; i++) {
43619                     var a = nodes[i],
43620                         b = nodes[i + 1];
43621                     var current = geoEuclideanDistance(a, b);
43622                     var portion;
43623                     if (!start && sofar + current >= from) {
43624                         portion = (from - sofar) / current;
43625                         start = [
43626                             a[0] + portion * (b[0] - a[0]),
43627                             a[1] + portion * (b[1] - a[1])
43628                         ];
43629                         i0 = i + 1;
43630                     }
43631                     if (!end && sofar + current >= to) {
43632                         portion = (to - sofar) / current;
43633                         end = [
43634                             a[0] + portion * (b[0] - a[0]),
43635                             a[1] + portion * (b[1] - a[1])
43636                         ];
43637                         i1 = i + 1;
43638                     }
43639                     sofar += current;
43640                 }
43641
43642                 var ret = nodes.slice(i0, i1);
43643                 ret.unshift(start);
43644                 ret.push(end);
43645                 return ret;
43646             }
43647         }
43648
43649
43650         function getAreaLabel(entity, width, height) {
43651             var centroid = path$$1.centroid(entity.asGeoJSON(graph, true)),
43652                 extent$$1 = entity.extent(graph),
43653                 entitywidth = projection(extent$$1[1])[0] - projection(extent$$1[0])[0];
43654
43655             if (isNaN(centroid[0]) || entitywidth < 20) return;
43656
43657             var iconSize = 20,
43658                 iconX = centroid[0] - (iconSize / 2),
43659                 iconY = centroid[1] - (iconSize / 2),
43660                 margin = 2,
43661                 textOffset = iconSize + margin,
43662                 p = { transform: 'translate(' + iconX + ',' + iconY + ')' };
43663
43664             var bbox = {
43665                 minX: iconX,
43666                 minY: iconY,
43667                 maxX: iconX + iconSize,
43668                 maxY: iconY + iconSize
43669             };
43670
43671             // try to add icon
43672             if (tryInsert([bbox], entity.id + 'I', true)) {
43673                 if (width && entitywidth >= width + 20) {
43674                     var labelX = centroid[0],
43675                         labelY = centroid[1] + textOffset;
43676
43677                     bbox = {
43678                         minX: labelX - (width / 2) - margin,
43679                         minY: labelY - (height / 2) - margin,
43680                         maxX: labelX + (width / 2) + margin,
43681                         maxY: labelY + (height / 2) + margin
43682                     };
43683
43684                     // try to add label
43685                     if (tryInsert([bbox], entity.id, true)) {
43686                         p.x = labelX;
43687                         p.y = labelY;
43688                         p.textAnchor = 'middle';
43689                         p.height = height;
43690                     }
43691                 }
43692
43693                 return p;
43694             }
43695         }
43696
43697
43698         function tryInsert(bboxes, id, saveSkipped) {
43699             var skipped = false,
43700                 bbox;
43701
43702             for (var i = 0; i < bboxes.length; i++) {
43703                 bbox = bboxes[i];
43704                 bbox.id = id;
43705
43706                 // Check that label is visible
43707                 if (bbox.minX < 0 || bbox.minY < 0 || bbox.maxX > dimensions[0] || bbox.maxY > dimensions[1]) {
43708                     skipped = true;
43709                     break;
43710                 }
43711                 if (rdrawn.collides(bbox)) {
43712                     skipped = true;
43713                     break;
43714                 }
43715             }
43716
43717             entitybboxes[id] = bboxes;
43718
43719             if (skipped) {
43720                 if (saveSkipped) {
43721                     rskipped.load(bboxes);
43722                 }
43723             } else {
43724                 rdrawn.load(bboxes);
43725             }
43726
43727             return !skipped;
43728         }
43729
43730
43731         var label = selection$$1.selectAll('.layer-label'),
43732             halo = selection$$1.selectAll('.layer-halo');
43733
43734         // points
43735         drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
43736         drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
43737
43738         // lines
43739         drawLinePaths(halo, labelled.line, filter, '', positions.line);
43740         drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
43741         drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
43742
43743         // areas
43744         drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
43745         drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
43746         drawAreaIcons(label, labelled.area, filter, 'areaicon', positions.area);
43747         drawAreaIcons(halo, labelled.area, filter, 'areaicon-halo', positions.area);
43748
43749         // debug
43750         drawCollisionBoxes(label, rskipped, 'debug-skipped');
43751         drawCollisionBoxes(label, rdrawn, 'debug-drawn');
43752
43753         selection$$1.call(filterLabels);
43754     }
43755
43756
43757     function filterLabels(selection$$1) {
43758         var layers = selection$$1
43759             .selectAll('.layer-label, .layer-halo');
43760
43761         layers.selectAll('.proximate')
43762             .classed('proximate', false);
43763
43764         var mouse$$1 = context.mouse(),
43765             graph = context.graph(),
43766             selectedIDs = context.selectedIDs(),
43767             ids = [],
43768             pad, bbox;
43769
43770         // hide labels near the mouse
43771         if (mouse$$1) {
43772             pad = 20;
43773             bbox = { minX: mouse$$1[0] - pad, minY: mouse$$1[1] - pad, maxX: mouse$$1[0] + pad, maxY: mouse$$1[1] + pad };
43774             ids.push.apply(ids, lodash.map(rdrawn.search(bbox), 'id'));
43775         }
43776
43777         // hide labels along selected ways, or near selected vertices
43778         for (var i = 0; i < selectedIDs.length; i++) {
43779             var entity = graph.hasEntity(selectedIDs[i]);
43780             if (!entity) continue;
43781             var geometry = entity.geometry(graph);
43782
43783             if (geometry === 'line') {
43784                 ids.push(selectedIDs[i]);
43785             } else if (geometry === 'vertex') {
43786                 var point = context.projection(entity.loc);
43787                 pad = 10;
43788                 bbox = { minX: point[0] - pad, minY: point[1] - pad, maxX: point[0] + pad, maxY: point[1] + pad };
43789                 ids.push.apply(ids, lodash.map(rdrawn.search(bbox), 'id'));
43790             }
43791         }
43792
43793         layers.selectAll(utilEntitySelector(ids))
43794             .classed('proximate', true);
43795     }
43796
43797
43798     var throttleFilterLabels = lodash.throttle(filterLabels, 100);
43799
43800
43801     drawLabels.observe = function(selection$$1) {
43802         var listener = function() { throttleFilterLabels(selection$$1); };
43803         selection$$1.on('mousemove.hidelabels', listener);
43804         context.on('enter.hidelabels', listener);
43805     };
43806
43807
43808     drawLabels.off = function(selection$$1) {
43809         throttleFilterLabels.cancel();
43810         selection$$1.on('mousemove.hidelabels', null);
43811         context.on('enter.hidelabels', null);
43812     };
43813
43814
43815     return drawLabels;
43816 }
43817
43818 function refresh(selection, node) {
43819     var cr = node.getBoundingClientRect();
43820     var prop = [cr.width, cr.height];
43821     selection.property('__dimensions__', prop);
43822     return prop;
43823 }
43824
43825 function utilGetDimensions(selection, force) {
43826     if (!selection || selection.empty()) {
43827         return [0, 0];
43828     }
43829     var node = selection.node(),
43830         cached = selection.property('__dimensions__');
43831     return (!cached || force) ? refresh(selection, node) : cached;
43832 }
43833
43834
43835 function utilSetDimensions(selection, dimensions) {
43836     if (!selection || selection.empty()) {
43837         return selection;
43838     }
43839     var node = selection.node();
43840     if (dimensions === null) {
43841         refresh(selection, node);
43842         return selection;
43843     }
43844     return selection
43845         .property('__dimensions__', [dimensions[0], dimensions[1]])
43846         .attr('width', dimensions[0])
43847         .attr('height', dimensions[1]);
43848 }
43849
43850 function svgPointTransform(projection) {
43851     return function(entity) {
43852         // http://jsperf.com/short-array-join
43853         var pt = projection(entity.loc);
43854         return 'translate(' + pt[0] + ',' + pt[1] + ')';
43855     };
43856 }
43857
43858 function d3geoTile() {
43859   var size = [960, 500],
43860       scale = 256,
43861       scaleExtent = [0, 20],
43862       translate = [size[0] / 2, size[1] / 2],
43863       zoomDelta = 0;
43864
43865   function bound(_) {
43866       return Math.min(scaleExtent[1], Math.max(scaleExtent[0], _));
43867   }
43868
43869   function tile() {
43870     var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
43871         z0 = bound(Math.round(z + zoomDelta)),
43872         k = Math.pow(2, z - z0 + 8),
43873         origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
43874         tiles = [],
43875         cols = sequence(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
43876         rows = sequence(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));
43877
43878     rows.forEach(function(y) {
43879       cols.forEach(function(x) {
43880         tiles.push([x, y, z0]);
43881       });
43882     });
43883
43884     tiles.translate = origin;
43885     tiles.scale = k;
43886
43887     return tiles;
43888   }
43889
43890   tile.scaleExtent = function(_) {
43891     if (!arguments.length) return scaleExtent;
43892     scaleExtent = _;
43893     return tile;
43894   };
43895
43896   tile.size = function(_) {
43897     if (!arguments.length) return size;
43898     size = _;
43899     return tile;
43900   };
43901
43902   tile.scale = function(_) {
43903     if (!arguments.length) return scale;
43904     scale = _;
43905     return tile;
43906   };
43907
43908   tile.translate = function(_) {
43909     if (!arguments.length) return translate;
43910     translate = _;
43911     return tile;
43912   };
43913
43914   tile.zoomDelta = function(_) {
43915     if (!arguments.length) return zoomDelta;
43916     zoomDelta = +_;
43917     return tile;
43918   };
43919
43920   return tile;
43921 }
43922
43923 /* global Mapillary:false */
43924 var apibase = 'https://a.mapillary.com/v2/';
43925 var viewercss = 'mapillary-js/mapillary.min.css';
43926 var viewerjs = 'mapillary-js/mapillary.min.js';
43927 var trafficocss = 'traffico/stylesheets/traffico.css';
43928 var clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi';
43929 var maxResults = 1000;
43930 var tileZoom = 14;
43931 var dispatch$2 = dispatch('loadedImages', 'loadedSigns');
43932 var mapillaryCache;
43933 var mapillaryClicks;
43934 var mapillaryImage;
43935 var mapillarySignDefs;
43936 var mapillaryViewer;
43937
43938
43939 function abortRequest(i) {
43940     i.abort();
43941 }
43942
43943
43944 function nearNullIsland(x, y, z) {
43945     if (z >= 7) {
43946         var center = Math.pow(2, z - 1),
43947             width = Math.pow(2, z - 6),
43948             min$$1 = center - (width / 2),
43949             max$$1 = center + (width / 2) - 1;
43950         return x >= min$$1 && x <= max$$1 && y >= min$$1 && y <= max$$1;
43951     }
43952     return false;
43953 }
43954
43955
43956 function maxPageAtZoom(z) {
43957     if (z < 15)   return 2;
43958     if (z === 15) return 5;
43959     if (z === 16) return 10;
43960     if (z === 17) return 20;
43961     if (z === 18) return 40;
43962     if (z > 18)   return 80;
43963 }
43964
43965
43966 function getTiles(projection) {
43967     var s = projection.scale() * 2 * Math.PI,
43968         z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
43969         ts = 256 * Math.pow(2, z - tileZoom),
43970         origin = [
43971             s / 2 - projection.translate()[0],
43972             s / 2 - projection.translate()[1]];
43973
43974     return d3geoTile()
43975         .scaleExtent([tileZoom, tileZoom])
43976         .scale(s)
43977         .size(projection.clipExtent()[1])
43978         .translate(projection.translate())()
43979         .map(function(tile) {
43980             var x = tile[0] * ts - origin[0],
43981                 y = tile[1] * ts - origin[1];
43982
43983             return {
43984                 id: tile.toString(),
43985                 xyz: tile,
43986                 extent: geoExtent$$1(
43987                     projection.invert([x, y + ts]),
43988                     projection.invert([x + ts, y])
43989                 )
43990             };
43991         });
43992 }
43993
43994
43995 function loadTiles(which, url, projection) {
43996     var s = projection.scale() * 2 * Math.PI,
43997         currZoom = Math.floor(Math.max(Math.log(s) / Math.log(2) - 8, 0));
43998
43999     var tiles = getTiles(projection).filter(function(t) {
44000             return !nearNullIsland(t.xyz[0], t.xyz[1], t.xyz[2]);
44001         });
44002
44003     lodash.filter(which.inflight, function(v, k) {
44004         var wanted = lodash.find(tiles, function(tile) { return k === (tile.id + ',0'); });
44005         if (!wanted) delete which.inflight[k];
44006         return !wanted;
44007     }).map(abortRequest);
44008
44009     tiles.forEach(function(tile) {
44010         loadNextTilePage(which, currZoom, url, tile);
44011     });
44012 }
44013
44014
44015 function loadNextTilePage(which, currZoom, url, tile) {
44016     var cache = mapillaryCache[which],
44017         rect = tile.extent.rectangle(),
44018         maxPages = maxPageAtZoom(currZoom),
44019         nextPage = cache.nextPage[tile.id] || 0;
44020
44021     if (nextPage > maxPages) return;
44022
44023     var id = tile.id + ',' + String(nextPage);
44024     if (cache.loaded[id] || cache.inflight[id]) return;
44025
44026     cache.inflight[id] = json(url +
44027         utilQsString({
44028             geojson: 'true',
44029             limit: maxResults,
44030             page: nextPage,
44031             client_id: clientId,
44032             min_lon: rect[0],
44033             min_lat: rect[1],
44034             max_lon: rect[2],
44035             max_lat: rect[3]
44036         }), function(err, data) {
44037             cache.loaded[id] = true;
44038             delete cache.inflight[id];
44039             if (err || !data.features || !data.features.length) return;
44040
44041             var features = [],
44042                 feature, loc, d;
44043
44044             for (var i = 0; i < data.features.length; i++) {
44045                 feature = data.features[i];
44046                 loc = feature.geometry.coordinates;
44047                 d = { key: feature.properties.key, loc: loc };
44048                 if (which === 'images') d.ca = feature.properties.ca;
44049                 if (which === 'signs') d.signs = feature.properties.rects;
44050
44051                 features.push({minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1], data: d});
44052             }
44053
44054             cache.rtree.load(features);
44055
44056             if (which === 'images') dispatch$2.call('loadedImages');
44057             if (which === 'signs') dispatch$2.call('loadedSigns');
44058
44059             if (data.features.length === maxResults) {  // more pages to load
44060                 cache.nextPage[tile.id] = nextPage + 1;
44061                 loadNextTilePage(which, currZoom, url, tile);
44062             } else {
44063                 cache.nextPage[tile.id] = Infinity;     // no more pages to load
44064             }
44065         }
44066     );
44067 }
44068
44069
44070 // partition viewport into `psize` x `psize` regions
44071 function partitionViewport(psize, projection) {
44072     var dimensions = projection.clipExtent()[1];
44073     psize = psize || 16;
44074     var cols = sequence(0, dimensions[0], psize),
44075         rows = sequence(0, dimensions[1], psize),
44076         partitions = [];
44077
44078     rows.forEach(function(y) {
44079         cols.forEach(function(x) {
44080             var min$$1 = [x, y + psize],
44081                 max$$1 = [x + psize, y];
44082             partitions.push(
44083                 geoExtent$$1(projection.invert(min$$1), projection.invert(max$$1)));
44084         });
44085     });
44086
44087     return partitions;
44088 }
44089
44090
44091 // no more than `limit` results per partition.
44092 function searchLimited(psize, limit, projection, rtree) {
44093     limit = limit || 3;
44094
44095     var partitions = partitionViewport(psize, projection);
44096     return lodash.flatten(lodash.compact(lodash.map(partitions, function(extent$$1) {
44097         return rtree.search(extent$$1.bbox())
44098             .slice(0, limit)
44099             .map(function(d) { return d.data; });
44100     })));
44101 }
44102
44103
44104
44105 var serviceMapillary = {
44106
44107     init: function() {
44108         if (!mapillaryCache) {
44109             this.reset();
44110         }
44111
44112         this.event = utilRebind(this, dispatch$2, 'on');
44113     },
44114
44115     reset: function() {
44116         var cache = mapillaryCache;
44117
44118         if (cache) {
44119             if (cache.images && cache.images.inflight) {
44120                 lodash.forEach(cache.images.inflight, abortRequest);
44121             }
44122             if (cache.signs && cache.signs.inflight) {
44123                 lodash.forEach(cache.signs.inflight, abortRequest);
44124             }
44125         }
44126
44127         mapillaryCache = {
44128             images: { inflight: {}, loaded: {}, nextPage: {}, rtree: index$9() },
44129             signs:  { inflight: {}, loaded: {}, nextPage: {}, rtree: index$9() }
44130         };
44131
44132         mapillaryImage = null;
44133         mapillaryClicks = [];
44134     },
44135
44136
44137     images: function(projection) {
44138         var psize = 16, limit = 3;
44139         return searchLimited(psize, limit, projection, mapillaryCache.images.rtree);
44140     },
44141
44142
44143     signs: function(projection) {
44144         var psize = 32, limit = 3;
44145         return searchLimited(psize, limit, projection, mapillaryCache.signs.rtree);
44146     },
44147
44148
44149     signsSupported: function() {
44150         var detected = utilDetect();
44151         if (detected.ie) return false;
44152         if ((detected.browser.toLowerCase() === 'safari') && (parseFloat(detected.version) < 10)) return false;
44153         return true;
44154     },
44155
44156
44157     signHTML: function(d) {
44158         if (!mapillarySignDefs) return;
44159
44160         var detectionPackage = d.signs[0].package,
44161             type = d.signs[0].type,
44162             country = detectionPackage.split('_')[1];
44163
44164         return mapillarySignDefs[country][type];
44165     },
44166
44167
44168     loadImages: function(projection) {
44169         var url = apibase + 'search/im/geojson?';
44170         loadTiles('images', url, projection);
44171     },
44172
44173
44174     loadSigns: function(context, projection) {
44175         var url = apibase + 'search/im/geojson/or?';
44176         loadTiles('signs', url, projection);
44177
44178         // load traffico css
44179         select('head').selectAll('#traffico')
44180             .data([0])
44181             .enter()
44182             .append('link')
44183             .attr('id', 'traffico')
44184             .attr('rel', 'stylesheet')
44185             .attr('href', context.asset(trafficocss));
44186
44187         // load traffico sign defs
44188         if (!mapillarySignDefs) {
44189             mapillarySignDefs = {};
44190             lodash.each(['au', 'br', 'ca', 'de', 'us'], function(region) {
44191                 json(context.asset('traffico/string-maps/' + region + '-map.json'), function(err, data) {
44192                     if (err) return;
44193                     if (region === 'de') region = 'eu';
44194                     mapillarySignDefs[region] = data;
44195                 });
44196             });
44197         }
44198     },
44199
44200
44201     loadViewer: function(context) {
44202         var that = this;
44203         var wrap = select('#content').selectAll('.mapillary-wrap')
44204             .data([0]);
44205
44206         var enter = wrap.enter()
44207             .append('div')
44208             .attr('class', 'mapillary-wrap')
44209             .classed('al', true)       // 'al'=left,  'ar'=right
44210             .classed('hidden', true);
44211
44212         enter
44213             .append('button')
44214             .attr('class', 'thumb-hide')
44215             .on('click', function () { that.hideViewer(); })
44216             .append('div')
44217             .call(svgIcon('#icon-close'));
44218
44219         enter
44220             .append('div')
44221             .attr('id', 'mly')
44222             .attr('class', 'mly-wrapper')
44223             .classed('active', false);
44224
44225         // load mapillary-viewercss
44226         select('head').selectAll('#mapillary-viewercss')
44227             .data([0])
44228             .enter()
44229             .append('link')
44230             .attr('id', 'mapillary-viewercss')
44231             .attr('rel', 'stylesheet')
44232             .attr('href', context.asset(viewercss));
44233
44234         // load mapillary-viewerjs
44235         select('head').selectAll('#mapillary-viewerjs')
44236             .data([0])
44237             .enter()
44238             .append('script')
44239             .attr('id', 'mapillary-viewerjs')
44240             .attr('src', context.asset(viewerjs));
44241     },
44242
44243
44244     showViewer: function() {
44245         select('#content')
44246             .selectAll('.mapillary-wrap')
44247             .classed('hidden', false)
44248             .selectAll('.mly-wrapper')
44249             .classed('active', true);
44250
44251         return this;
44252     },
44253
44254
44255     hideViewer: function() {
44256         select('#content')
44257             .selectAll('.mapillary-wrap')
44258             .classed('hidden', true)
44259             .selectAll('.mly-wrapper')
44260             .classed('active', false);
44261
44262         selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
44263             .classed('selected', false);
44264
44265         mapillaryImage = null;
44266         return this;
44267     },
44268
44269
44270     updateViewer: function(imageKey, context) {
44271         if (!imageKey) return;
44272
44273         if (!mapillaryViewer) {
44274             this.initViewer(imageKey, context);
44275         } else {
44276             mapillaryViewer.moveToKey(imageKey);
44277         }
44278
44279         return this;
44280     },
44281
44282
44283     initViewer: function(imageKey, context) {
44284         var that = this;
44285         if (Mapillary && imageKey) {
44286             var opts = {
44287                 baseImageSize: 320,
44288                 component: {
44289                     cover: false,
44290                     keyboard: false
44291                 }
44292             };
44293
44294             mapillaryViewer = new Mapillary.Viewer('mly', clientId, imageKey, opts);
44295             mapillaryViewer.on('nodechanged', nodeChanged);
44296         }
44297
44298         function nodeChanged(node) {
44299             var clicks = mapillaryClicks;
44300             var index = clicks.indexOf(node.key);
44301             if (index > -1) {    // nodechange initiated from clicking on a marker..
44302                 clicks.splice(index, 1);
44303             } else {             // nodechange initiated from the Mapillary viewer controls..
44304                 var loc = node.computedLatLon ? [node.computedLatLon.lon, node.computedLatLon.lat] : [node.latLon.lon, node.latLon.lat];
44305                 context.map().centerEase(loc);
44306                 that.selectedImage(node.key, false);
44307             }
44308         }
44309     },
44310
44311
44312     selectedImage: function(imageKey, fromClick) {
44313         if (!arguments.length) return mapillaryImage;
44314
44315         mapillaryImage = imageKey;
44316         if (fromClick) {
44317             mapillaryClicks.push(imageKey);
44318         }
44319
44320         selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
44321             .classed('selected', function(d) { return d.key === imageKey; });
44322
44323         return this;
44324     },
44325
44326
44327     cache: function(_) {
44328         if (!arguments.length) return mapillaryCache;
44329         mapillaryCache = _;
44330         return this;
44331     },
44332
44333
44334     signDefs: function(_) {
44335         if (!arguments.length) return mapillarySignDefs;
44336         mapillarySignDefs = _;
44337         return this;
44338     }
44339
44340 };
44341
44342 var apibase$1 = 'https://nominatim.openstreetmap.org/';
44343 var inflight = {};
44344 var nominatimCache;
44345
44346
44347 var serviceNominatim = {
44348
44349     init: function() {
44350         inflight = {};
44351         nominatimCache = index$9();
44352     },
44353
44354     reset: function() {
44355         lodash.forEach(inflight, function(req) { req.abort(); });
44356         inflight = {};
44357         nominatimCache = index$9();
44358     },
44359
44360
44361     countryCode: function (location, callback) {
44362         var countryCodes = nominatimCache.search(
44363             { minX: location[0], minY: location[1], maxX: location[0], maxY: location[1] }
44364         );
44365
44366         if (countryCodes.length > 0) {
44367             return callback(null, countryCodes[0].data);
44368         }
44369
44370         var params = { format: 'json', addressdetails: 1, lat: location[1], lon: location[0] };
44371         var url = apibase$1 + 'reverse?' + utilQsString(params);
44372         if (inflight[url]) return;
44373
44374         inflight[url] = json(url, function(err, result) {
44375             delete inflight[url];
44376
44377             if (err)
44378                 return callback(err);
44379             else if (result && result.error)
44380                 return callback(result.error);
44381
44382             var extent$$1 = geoExtent$$1(location).padByMeters(1000);
44383             nominatimCache.insert(lodash.assign(extent$$1.bbox(),
44384                 { data: result.address.country_code }
44385             ));
44386
44387             callback(null, result.address.country_code);
44388         });
44389     },
44390
44391
44392     search: function (val, callback) {
44393         var searchVal = encodeURIComponent(val);
44394         var url = apibase$1 + 'search/' + searchVal + '?limit=10&format=json';
44395         if (inflight[url]) return;
44396
44397         inflight[url] = json(url, function(err, result) {
44398             delete inflight[url];
44399             callback(err, result);
44400         });
44401     }
44402
44403 };
44404
44405 var hashes = createCommonjsModule(function (module, exports) {
44406 /**
44407  * jshashes - https://github.com/h2non/jshashes
44408  * Released under the "New BSD" license
44409  *
44410  * Algorithms specification:
44411  *
44412  * MD5 - http://www.ietf.org/rfc/rfc1321.txt
44413  * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
44414  * SHA1   - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
44415  * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
44416  * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
44417  * HMAC - http://www.ietf.org/rfc/rfc2104.txt
44418  */
44419 (function() {
44420   var Hashes;
44421
44422   function utf8Encode(str) {
44423     var x, y, output = '',
44424       i = -1,
44425       l;
44426
44427     if (str && str.length) {
44428       l = str.length;
44429       while ((i += 1) < l) {
44430         /* Decode utf-16 surrogate pairs */
44431         x = str.charCodeAt(i);
44432         y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
44433         if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
44434           x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
44435           i += 1;
44436         }
44437         /* Encode output as utf-8 */
44438         if (x <= 0x7F) {
44439           output += String.fromCharCode(x);
44440         } else if (x <= 0x7FF) {
44441           output += String.fromCharCode(0xC0 | ((x >>> 6) & 0x1F),
44442             0x80 | (x & 0x3F));
44443         } else if (x <= 0xFFFF) {
44444           output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
44445             0x80 | ((x >>> 6) & 0x3F),
44446             0x80 | (x & 0x3F));
44447         } else if (x <= 0x1FFFFF) {
44448           output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
44449             0x80 | ((x >>> 12) & 0x3F),
44450             0x80 | ((x >>> 6) & 0x3F),
44451             0x80 | (x & 0x3F));
44452         }
44453       }
44454     }
44455     return output;
44456   }
44457
44458   function utf8Decode(str) {
44459     var i, ac, c1, c2, c3, arr = [],
44460       l;
44461     i = ac = c1 = c2 = c3 = 0;
44462
44463     if (str && str.length) {
44464       l = str.length;
44465       str += '';
44466
44467       while (i < l) {
44468         c1 = str.charCodeAt(i);
44469         ac += 1;
44470         if (c1 < 128) {
44471           arr[ac] = String.fromCharCode(c1);
44472           i += 1;
44473         } else if (c1 > 191 && c1 < 224) {
44474           c2 = str.charCodeAt(i + 1);
44475           arr[ac] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
44476           i += 2;
44477         } else {
44478           c2 = str.charCodeAt(i + 1);
44479           c3 = str.charCodeAt(i + 2);
44480           arr[ac] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
44481           i += 3;
44482         }
44483       }
44484     }
44485     return arr.join('');
44486   }
44487
44488   /**
44489    * Add integers, wrapping at 2^32. This uses 16-bit operations internally
44490    * to work around bugs in some JS interpreters.
44491    */
44492
44493   function safe_add(x, y) {
44494     var lsw = (x & 0xFFFF) + (y & 0xFFFF),
44495       msw = (x >> 16) + (y >> 16) + (lsw >> 16);
44496     return (msw << 16) | (lsw & 0xFFFF);
44497   }
44498
44499   /**
44500    * Bitwise rotate a 32-bit number to the left.
44501    */
44502
44503   function bit_rol(num, cnt) {
44504     return (num << cnt) | (num >>> (32 - cnt));
44505   }
44506
44507   /**
44508    * Convert a raw string to a hex string
44509    */
44510
44511   function rstr2hex(input, hexcase) {
44512     var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
44513       output = '',
44514       x, i = 0,
44515       l = input.length;
44516     for (; i < l; i += 1) {
44517       x = input.charCodeAt(i);
44518       output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F);
44519     }
44520     return output;
44521   }
44522
44523   /**
44524    * Encode a string as utf-16
44525    */
44526
44527   function binb2rstr(input) {
44528     var i, l = input.length * 32,
44529       output = '';
44530     for (i = 0; i < l; i += 8) {
44531       output += String.fromCharCode((input[i >> 5] >>> (24 - i % 32)) & 0xFF);
44532     }
44533     return output;
44534   }
44535
44536   /**
44537    * Convert an array of little-endian words to a string
44538    */
44539
44540   function binl2rstr(input) {
44541     var i, l = input.length * 32,
44542       output = '';
44543     for (i = 0; i < l; i += 8) {
44544       output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
44545     }
44546     return output;
44547   }
44548
44549   /**
44550    * Convert a raw string to an array of little-endian words
44551    * Characters >255 have their high-byte silently ignored.
44552    */
44553
44554   function rstr2binl(input) {
44555     var i, l = input.length * 8,
44556       output = Array(input.length >> 2),
44557       lo = output.length;
44558     for (i = 0; i < lo; i += 1) {
44559       output[i] = 0;
44560     }
44561     for (i = 0; i < l; i += 8) {
44562       output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
44563     }
44564     return output;
44565   }
44566
44567   /**
44568    * Convert a raw string to an array of big-endian words
44569    * Characters >255 have their high-byte silently ignored.
44570    */
44571
44572   function rstr2binb(input) {
44573     var i, l = input.length * 8,
44574       output = Array(input.length >> 2),
44575       lo = output.length;
44576     for (i = 0; i < lo; i += 1) {
44577       output[i] = 0;
44578     }
44579     for (i = 0; i < l; i += 8) {
44580       output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
44581     }
44582     return output;
44583   }
44584
44585   /**
44586    * Convert a raw string to an arbitrary string encoding
44587    */
44588
44589   function rstr2any(input, encoding) {
44590     var divisor = encoding.length,
44591       remainders = Array(),
44592       i, q, x, ld, quotient, dividend, output, full_length;
44593
44594     /* Convert to an array of 16-bit big-endian values, forming the dividend */
44595     dividend = Array(Math.ceil(input.length / 2));
44596     ld = dividend.length;
44597     for (i = 0; i < ld; i += 1) {
44598       dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
44599     }
44600
44601     /**
44602      * Repeatedly perform a long division. The binary array forms the dividend,
44603      * the length of the encoding is the divisor. Once computed, the quotient
44604      * forms the dividend for the next step. We stop when the dividend is zerHashes.
44605      * All remainders are stored for later use.
44606      */
44607     while (dividend.length > 0) {
44608       quotient = Array();
44609       x = 0;
44610       for (i = 0; i < dividend.length; i += 1) {
44611         x = (x << 16) + dividend[i];
44612         q = Math.floor(x / divisor);
44613         x -= q * divisor;
44614         if (quotient.length > 0 || q > 0) {
44615           quotient[quotient.length] = q;
44616         }
44617       }
44618       remainders[remainders.length] = x;
44619       dividend = quotient;
44620     }
44621
44622     /* Convert the remainders to the output string */
44623     output = '';
44624     for (i = remainders.length - 1; i >= 0; i--) {
44625       output += encoding.charAt(remainders[i]);
44626     }
44627
44628     /* Append leading zero equivalents */
44629     full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
44630     for (i = output.length; i < full_length; i += 1) {
44631       output = encoding[0] + output;
44632     }
44633     return output;
44634   }
44635
44636   /**
44637    * Convert a raw string to a base-64 string
44638    */
44639
44640   function rstr2b64(input, b64pad) {
44641     var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
44642       output = '',
44643       len = input.length,
44644       i, j, triplet;
44645     b64pad = b64pad || '=';
44646     for (i = 0; i < len; i += 3) {
44647       triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
44648       for (j = 0; j < 4; j += 1) {
44649         if (i * 8 + j * 6 > input.length * 8) {
44650           output += b64pad;
44651         } else {
44652           output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
44653         }
44654       }
44655     }
44656     return output;
44657   }
44658
44659   Hashes = {
44660     /**
44661      * @property {String} version
44662      * @readonly
44663      */
44664     VERSION: '1.0.6',
44665     /**
44666      * @member Hashes
44667      * @class Base64
44668      * @constructor
44669      */
44670     Base64: function() {
44671       // private properties
44672       var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
44673         pad = '=', // default pad according with the RFC standard
44674         url = false, // URL encoding support @todo
44675         utf8 = true; // by default enable UTF-8 support encoding
44676
44677       // public method for encoding
44678       this.encode = function(input) {
44679         var i, j, triplet,
44680           output = '',
44681           len = input.length;
44682
44683         pad = pad || '=';
44684         input = (utf8) ? utf8Encode(input) : input;
44685
44686         for (i = 0; i < len; i += 3) {
44687           triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
44688           for (j = 0; j < 4; j += 1) {
44689             if (i * 8 + j * 6 > len * 8) {
44690               output += pad;
44691             } else {
44692               output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
44693             }
44694           }
44695         }
44696         return output;
44697       };
44698
44699       // public method for decoding
44700       this.decode = function(input) {
44701         // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
44702         var i, o1, o2, o3, h1, h2, h3, h4, bits, ac,
44703           dec = '',
44704           arr = [];
44705         if (!input) {
44706           return input;
44707         }
44708
44709         i = ac = 0;
44710         input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '='
44711         //input += '';
44712
44713         do { // unpack four hexets into three octets using index points in b64
44714           h1 = tab.indexOf(input.charAt(i += 1));
44715           h2 = tab.indexOf(input.charAt(i += 1));
44716           h3 = tab.indexOf(input.charAt(i += 1));
44717           h4 = tab.indexOf(input.charAt(i += 1));
44718
44719           bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
44720
44721           o1 = bits >> 16 & 0xff;
44722           o2 = bits >> 8 & 0xff;
44723           o3 = bits & 0xff;
44724           ac += 1;
44725
44726           if (h3 === 64) {
44727             arr[ac] = String.fromCharCode(o1);
44728           } else if (h4 === 64) {
44729             arr[ac] = String.fromCharCode(o1, o2);
44730           } else {
44731             arr[ac] = String.fromCharCode(o1, o2, o3);
44732           }
44733         } while (i < input.length);
44734
44735         dec = arr.join('');
44736         dec = (utf8) ? utf8Decode(dec) : dec;
44737
44738         return dec;
44739       };
44740
44741       // set custom pad string
44742       this.setPad = function(str) {
44743         pad = str || pad;
44744         return this;
44745       };
44746       // set custom tab string characters
44747       this.setTab = function(str) {
44748         tab = str || tab;
44749         return this;
44750       };
44751       this.setUTF8 = function(bool) {
44752         if (typeof bool === 'boolean') {
44753           utf8 = bool;
44754         }
44755         return this;
44756       };
44757     },
44758
44759     /**
44760      * CRC-32 calculation
44761      * @member Hashes
44762      * @method CRC32
44763      * @static
44764      * @param {String} str Input String
44765      * @return {String}
44766      */
44767     CRC32: function(str) {
44768       var crc = 0,
44769         x = 0,
44770         y = 0,
44771         table, i, iTop;
44772       str = utf8Encode(str);
44773
44774       table = [
44775         '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ',
44776         '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ',
44777         '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ',
44778         '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ',
44779         'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ',
44780         '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ',
44781         'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ',
44782         '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ',
44783         'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ',
44784         '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ',
44785         'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ',
44786         '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ',
44787         'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ',
44788         '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ',
44789         '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ',
44790         '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ',
44791         '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ',
44792         'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ',
44793         '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ',
44794         'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ',
44795         '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ',
44796         'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ',
44797         '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ',
44798         'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ',
44799         '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ',
44800         'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'
44801       ].join('');
44802
44803       crc = crc ^ (-1);
44804       for (i = 0, iTop = str.length; i < iTop; i += 1) {
44805         y = (crc ^ str.charCodeAt(i)) & 0xFF;
44806         x = '0x' + table.substr(y * 9, 8);
44807         crc = (crc >>> 8) ^ x;
44808       }
44809       // always return a positive number (that's what >>> 0 does)
44810       return (crc ^ (-1)) >>> 0;
44811     },
44812     /**
44813      * @member Hashes
44814      * @class MD5
44815      * @constructor
44816      * @param {Object} [config]
44817      *
44818      * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
44819      * Digest Algorithm, as defined in RFC 1321.
44820      * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
44821      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
44822      * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
44823      */
44824     MD5: function(options) {
44825       /**
44826        * Private config properties. You may need to tweak these to be compatible with
44827        * the server-side, but the defaults work in most cases.
44828        * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
44829        */
44830       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
44831         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
44832         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
44833
44834       // privileged (public) methods
44835       this.hex = function(s) {
44836         return rstr2hex(rstr(s, utf8), hexcase);
44837       };
44838       this.b64 = function(s) {
44839         return rstr2b64(rstr(s), b64pad);
44840       };
44841       this.any = function(s, e) {
44842         return rstr2any(rstr(s, utf8), e);
44843       };
44844       this.raw = function(s) {
44845         return rstr(s, utf8);
44846       };
44847       this.hex_hmac = function(k, d) {
44848         return rstr2hex(rstr_hmac(k, d), hexcase);
44849       };
44850       this.b64_hmac = function(k, d) {
44851         return rstr2b64(rstr_hmac(k, d), b64pad);
44852       };
44853       this.any_hmac = function(k, d, e) {
44854         return rstr2any(rstr_hmac(k, d), e);
44855       };
44856       /**
44857        * Perform a simple self-test to see if the VM is working
44858        * @return {String} Hexadecimal hash sample
44859        */
44860       this.vm_test = function() {
44861         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
44862       };
44863       /**
44864        * Enable/disable uppercase hexadecimal returned string
44865        * @param {Boolean}
44866        * @return {Object} this
44867        */
44868       this.setUpperCase = function(a) {
44869         if (typeof a === 'boolean') {
44870           hexcase = a;
44871         }
44872         return this;
44873       };
44874       /**
44875        * Defines a base64 pad string
44876        * @param {String} Pad
44877        * @return {Object} this
44878        */
44879       this.setPad = function(a) {
44880         b64pad = a || b64pad;
44881         return this;
44882       };
44883       /**
44884        * Defines a base64 pad string
44885        * @param {Boolean}
44886        * @return {Object} [this]
44887        */
44888       this.setUTF8 = function(a) {
44889         if (typeof a === 'boolean') {
44890           utf8 = a;
44891         }
44892         return this;
44893       };
44894
44895       // private methods
44896
44897       /**
44898        * Calculate the MD5 of a raw string
44899        */
44900
44901       function rstr(s) {
44902         s = (utf8) ? utf8Encode(s) : s;
44903         return binl2rstr(binl(rstr2binl(s), s.length * 8));
44904       }
44905
44906       /**
44907        * Calculate the HMAC-MD5, of a key and some data (raw strings)
44908        */
44909
44910       function rstr_hmac(key, data) {
44911         var bkey, ipad, opad, hash, i;
44912
44913         key = (utf8) ? utf8Encode(key) : key;
44914         data = (utf8) ? utf8Encode(data) : data;
44915         bkey = rstr2binl(key);
44916         if (bkey.length > 16) {
44917           bkey = binl(bkey, key.length * 8);
44918         }
44919
44920         ipad = Array(16), opad = Array(16);
44921         for (i = 0; i < 16; i += 1) {
44922           ipad[i] = bkey[i] ^ 0x36363636;
44923           opad[i] = bkey[i] ^ 0x5C5C5C5C;
44924         }
44925         hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
44926         return binl2rstr(binl(opad.concat(hash), 512 + 128));
44927       }
44928
44929       /**
44930        * Calculate the MD5 of an array of little-endian words, and a bit length.
44931        */
44932
44933       function binl(x, len) {
44934         var i, olda, oldb, oldc, oldd,
44935           a = 1732584193,
44936           b = -271733879,
44937           c = -1732584194,
44938           d = 271733878;
44939
44940         /* append padding */
44941         x[len >> 5] |= 0x80 << ((len) % 32);
44942         x[(((len + 64) >>> 9) << 4) + 14] = len;
44943
44944         for (i = 0; i < x.length; i += 16) {
44945           olda = a;
44946           oldb = b;
44947           oldc = c;
44948           oldd = d;
44949
44950           a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
44951           d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
44952           c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
44953           b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
44954           a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
44955           d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
44956           c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
44957           b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
44958           a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
44959           d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
44960           c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
44961           b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
44962           a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
44963           d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
44964           c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
44965           b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
44966
44967           a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
44968           d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
44969           c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
44970           b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
44971           a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
44972           d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
44973           c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
44974           b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
44975           a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
44976           d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
44977           c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
44978           b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
44979           a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
44980           d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
44981           c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
44982           b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
44983
44984           a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
44985           d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
44986           c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
44987           b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
44988           a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
44989           d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
44990           c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
44991           b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
44992           a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
44993           d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
44994           c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
44995           b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
44996           a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
44997           d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
44998           c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
44999           b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
45000
45001           a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
45002           d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
45003           c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
45004           b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
45005           a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
45006           d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
45007           c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
45008           b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
45009           a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
45010           d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
45011           c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
45012           b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
45013           a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
45014           d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
45015           c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
45016           b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
45017
45018           a = safe_add(a, olda);
45019           b = safe_add(b, oldb);
45020           c = safe_add(c, oldc);
45021           d = safe_add(d, oldd);
45022         }
45023         return Array(a, b, c, d);
45024       }
45025
45026       /**
45027        * These functions implement the four basic operations the algorithm uses.
45028        */
45029
45030       function md5_cmn(q, a, b, x, s, t) {
45031         return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
45032       }
45033
45034       function md5_ff(a, b, c, d, x, s, t) {
45035         return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
45036       }
45037
45038       function md5_gg(a, b, c, d, x, s, t) {
45039         return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
45040       }
45041
45042       function md5_hh(a, b, c, d, x, s, t) {
45043         return md5_cmn(b ^ c ^ d, a, b, x, s, t);
45044       }
45045
45046       function md5_ii(a, b, c, d, x, s, t) {
45047         return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
45048       }
45049     },
45050     /**
45051      * @member Hashes
45052      * @class Hashes.SHA1
45053      * @param {Object} [config]
45054      * @constructor
45055      *
45056      * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
45057      * Version 2.2 Copyright Paul Johnston 2000 - 2009.
45058      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45059      * See http://pajhome.org.uk/crypt/md5 for details.
45060      */
45061     SHA1: function(options) {
45062       /**
45063        * Private config properties. You may need to tweak these to be compatible with
45064        * the server-side, but the defaults work in most cases.
45065        * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
45066        */
45067       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
45068         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
45069         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
45070
45071       // public methods
45072       this.hex = function(s) {
45073         return rstr2hex(rstr(s, utf8), hexcase);
45074       };
45075       this.b64 = function(s) {
45076         return rstr2b64(rstr(s, utf8), b64pad);
45077       };
45078       this.any = function(s, e) {
45079         return rstr2any(rstr(s, utf8), e);
45080       };
45081       this.raw = function(s) {
45082         return rstr(s, utf8);
45083       };
45084       this.hex_hmac = function(k, d) {
45085         return rstr2hex(rstr_hmac(k, d));
45086       };
45087       this.b64_hmac = function(k, d) {
45088         return rstr2b64(rstr_hmac(k, d), b64pad);
45089       };
45090       this.any_hmac = function(k, d, e) {
45091         return rstr2any(rstr_hmac(k, d), e);
45092       };
45093       /**
45094        * Perform a simple self-test to see if the VM is working
45095        * @return {String} Hexadecimal hash sample
45096        * @public
45097        */
45098       this.vm_test = function() {
45099         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45100       };
45101       /**
45102        * @description Enable/disable uppercase hexadecimal returned string
45103        * @param {boolean}
45104        * @return {Object} this
45105        * @public
45106        */
45107       this.setUpperCase = function(a) {
45108         if (typeof a === 'boolean') {
45109           hexcase = a;
45110         }
45111         return this;
45112       };
45113       /**
45114        * @description Defines a base64 pad string
45115        * @param {string} Pad
45116        * @return {Object} this
45117        * @public
45118        */
45119       this.setPad = function(a) {
45120         b64pad = a || b64pad;
45121         return this;
45122       };
45123       /**
45124        * @description Defines a base64 pad string
45125        * @param {boolean}
45126        * @return {Object} this
45127        * @public
45128        */
45129       this.setUTF8 = function(a) {
45130         if (typeof a === 'boolean') {
45131           utf8 = a;
45132         }
45133         return this;
45134       };
45135
45136       // private methods
45137
45138       /**
45139        * Calculate the SHA-512 of a raw string
45140        */
45141
45142       function rstr(s) {
45143         s = (utf8) ? utf8Encode(s) : s;
45144         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45145       }
45146
45147       /**
45148        * Calculate the HMAC-SHA1 of a key and some data (raw strings)
45149        */
45150
45151       function rstr_hmac(key, data) {
45152         var bkey, ipad, opad, i, hash;
45153         key = (utf8) ? utf8Encode(key) : key;
45154         data = (utf8) ? utf8Encode(data) : data;
45155         bkey = rstr2binb(key);
45156
45157         if (bkey.length > 16) {
45158           bkey = binb(bkey, key.length * 8);
45159         }
45160         ipad = Array(16), opad = Array(16);
45161         for (i = 0; i < 16; i += 1) {
45162           ipad[i] = bkey[i] ^ 0x36363636;
45163           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45164         }
45165         hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
45166         return binb2rstr(binb(opad.concat(hash), 512 + 160));
45167       }
45168
45169       /**
45170        * Calculate the SHA-1 of an array of big-endian words, and a bit length
45171        */
45172
45173       function binb(x, len) {
45174         var i, j, t, olda, oldb, oldc, oldd, olde,
45175           w = Array(80),
45176           a = 1732584193,
45177           b = -271733879,
45178           c = -1732584194,
45179           d = 271733878,
45180           e = -1009589776;
45181
45182         /* append padding */
45183         x[len >> 5] |= 0x80 << (24 - len % 32);
45184         x[((len + 64 >> 9) << 4) + 15] = len;
45185
45186         for (i = 0; i < x.length; i += 16) {
45187           olda = a,
45188           oldb = b;
45189           oldc = c;
45190           oldd = d;
45191           olde = e;
45192
45193           for (j = 0; j < 80; j += 1) {
45194             if (j < 16) {
45195               w[j] = x[i + j];
45196             } else {
45197               w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
45198             }
45199             t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
45200               safe_add(safe_add(e, w[j]), sha1_kt(j)));
45201             e = d;
45202             d = c;
45203             c = bit_rol(b, 30);
45204             b = a;
45205             a = t;
45206           }
45207
45208           a = safe_add(a, olda);
45209           b = safe_add(b, oldb);
45210           c = safe_add(c, oldc);
45211           d = safe_add(d, oldd);
45212           e = safe_add(e, olde);
45213         }
45214         return Array(a, b, c, d, e);
45215       }
45216
45217       /**
45218        * Perform the appropriate triplet combination function for the current
45219        * iteration
45220        */
45221
45222       function sha1_ft(t, b, c, d) {
45223         if (t < 20) {
45224           return (b & c) | ((~b) & d);
45225         }
45226         if (t < 40) {
45227           return b ^ c ^ d;
45228         }
45229         if (t < 60) {
45230           return (b & c) | (b & d) | (c & d);
45231         }
45232         return b ^ c ^ d;
45233       }
45234
45235       /**
45236        * Determine the appropriate additive constant for the current iteration
45237        */
45238
45239       function sha1_kt(t) {
45240         return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
45241           (t < 60) ? -1894007588 : -899497514;
45242       }
45243     },
45244     /**
45245      * @class Hashes.SHA256
45246      * @param {config}
45247      *
45248      * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
45249      * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
45250      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45251      * See http://pajhome.org.uk/crypt/md5 for details.
45252      * Also http://anmar.eu.org/projects/jssha2/
45253      */
45254     SHA256: function(options) {
45255       /**
45256        * Private properties configuration variables. You may need to tweak these to be compatible with
45257        * the server-side, but the defaults work in most cases.
45258        * @see this.setUpperCase() method
45259        * @see this.setPad() method
45260        */
45261       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase  */
45262         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=',
45263         /* base-64 pad character. Default '=' for strict RFC compliance   */
45264         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
45265         /* enable/disable utf8 encoding */
45266         sha256_K;
45267
45268       /* privileged (public) methods */
45269       this.hex = function(s) {
45270         return rstr2hex(rstr(s, utf8));
45271       };
45272       this.b64 = function(s) {
45273         return rstr2b64(rstr(s, utf8), b64pad);
45274       };
45275       this.any = function(s, e) {
45276         return rstr2any(rstr(s, utf8), e);
45277       };
45278       this.raw = function(s) {
45279         return rstr(s, utf8);
45280       };
45281       this.hex_hmac = function(k, d) {
45282         return rstr2hex(rstr_hmac(k, d));
45283       };
45284       this.b64_hmac = function(k, d) {
45285         return rstr2b64(rstr_hmac(k, d), b64pad);
45286       };
45287       this.any_hmac = function(k, d, e) {
45288         return rstr2any(rstr_hmac(k, d), e);
45289       };
45290       /**
45291        * Perform a simple self-test to see if the VM is working
45292        * @return {String} Hexadecimal hash sample
45293        * @public
45294        */
45295       this.vm_test = function() {
45296         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45297       };
45298       /**
45299        * Enable/disable uppercase hexadecimal returned string
45300        * @param {boolean}
45301        * @return {Object} this
45302        * @public
45303        */
45304       this.setUpperCase = function(a) {
45305         if (typeof a === 'boolean') {
45306           hexcase = a;
45307         }
45308         return this;
45309       };
45310       /**
45311        * @description Defines a base64 pad string
45312        * @param {string} Pad
45313        * @return {Object} this
45314        * @public
45315        */
45316       this.setPad = function(a) {
45317         b64pad = a || b64pad;
45318         return this;
45319       };
45320       /**
45321        * Defines a base64 pad string
45322        * @param {boolean}
45323        * @return {Object} this
45324        * @public
45325        */
45326       this.setUTF8 = function(a) {
45327         if (typeof a === 'boolean') {
45328           utf8 = a;
45329         }
45330         return this;
45331       };
45332
45333       // private methods
45334
45335       /**
45336        * Calculate the SHA-512 of a raw string
45337        */
45338
45339       function rstr(s, utf8) {
45340         s = (utf8) ? utf8Encode(s) : s;
45341         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45342       }
45343
45344       /**
45345        * Calculate the HMAC-sha256 of a key and some data (raw strings)
45346        */
45347
45348       function rstr_hmac(key, data) {
45349         key = (utf8) ? utf8Encode(key) : key;
45350         data = (utf8) ? utf8Encode(data) : data;
45351         var hash, i = 0,
45352           bkey = rstr2binb(key),
45353           ipad = Array(16),
45354           opad = Array(16);
45355
45356         if (bkey.length > 16) {
45357           bkey = binb(bkey, key.length * 8);
45358         }
45359
45360         for (; i < 16; i += 1) {
45361           ipad[i] = bkey[i] ^ 0x36363636;
45362           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45363         }
45364
45365         hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
45366         return binb2rstr(binb(opad.concat(hash), 512 + 256));
45367       }
45368
45369       /*
45370        * Main sha256 function, with its support functions
45371        */
45372
45373       function sha256_S(X, n) {
45374         return (X >>> n) | (X << (32 - n));
45375       }
45376
45377       function sha256_R(X, n) {
45378         return (X >>> n);
45379       }
45380
45381       function sha256_Ch(x, y, z) {
45382         return ((x & y) ^ ((~x) & z));
45383       }
45384
45385       function sha256_Maj(x, y, z) {
45386         return ((x & y) ^ (x & z) ^ (y & z));
45387       }
45388
45389       function sha256_Sigma0256(x) {
45390         return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));
45391       }
45392
45393       function sha256_Sigma1256(x) {
45394         return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));
45395       }
45396
45397       function sha256_Gamma0256(x) {
45398         return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));
45399       }
45400
45401       function sha256_Gamma1256(x) {
45402         return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));
45403       }
45404
45405       sha256_K = [
45406         1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
45407         1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
45408         264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
45409         113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
45410         1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
45411         430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
45412         1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998
45413       ];
45414
45415       function binb(m, l) {
45416         var HASH = [1779033703, -1150833019, 1013904242, -1521486534,
45417           1359893119, -1694144372, 528734635, 1541459225
45418         ];
45419         var W = new Array(64);
45420         var a, b, c, d, e, f, g, h;
45421         var i, j, T1, T2;
45422
45423         /* append padding */
45424         m[l >> 5] |= 0x80 << (24 - l % 32);
45425         m[((l + 64 >> 9) << 4) + 15] = l;
45426
45427         for (i = 0; i < m.length; i += 16) {
45428           a = HASH[0];
45429           b = HASH[1];
45430           c = HASH[2];
45431           d = HASH[3];
45432           e = HASH[4];
45433           f = HASH[5];
45434           g = HASH[6];
45435           h = HASH[7];
45436
45437           for (j = 0; j < 64; j += 1) {
45438             if (j < 16) {
45439               W[j] = m[j + i];
45440             } else {
45441               W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
45442                 sha256_Gamma0256(W[j - 15])), W[j - 16]);
45443             }
45444
45445             T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
45446               sha256_K[j]), W[j]);
45447             T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
45448             h = g;
45449             g = f;
45450             f = e;
45451             e = safe_add(d, T1);
45452             d = c;
45453             c = b;
45454             b = a;
45455             a = safe_add(T1, T2);
45456           }
45457
45458           HASH[0] = safe_add(a, HASH[0]);
45459           HASH[1] = safe_add(b, HASH[1]);
45460           HASH[2] = safe_add(c, HASH[2]);
45461           HASH[3] = safe_add(d, HASH[3]);
45462           HASH[4] = safe_add(e, HASH[4]);
45463           HASH[5] = safe_add(f, HASH[5]);
45464           HASH[6] = safe_add(g, HASH[6]);
45465           HASH[7] = safe_add(h, HASH[7]);
45466         }
45467         return HASH;
45468       }
45469
45470     },
45471
45472     /**
45473      * @class Hashes.SHA512
45474      * @param {config}
45475      *
45476      * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
45477      * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
45478      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45479      * See http://pajhome.org.uk/crypt/md5 for details.
45480      */
45481     SHA512: function(options) {
45482       /**
45483        * Private properties configuration variables. You may need to tweak these to be compatible with
45484        * the server-side, but the defaults work in most cases.
45485        * @see this.setUpperCase() method
45486        * @see this.setPad() method
45487        */
45488       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false,
45489         /* hexadecimal output case format. false - lowercase; true - uppercase  */
45490         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=',
45491         /* base-64 pad character. Default '=' for strict RFC compliance   */
45492         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
45493         /* enable/disable utf8 encoding */
45494         sha512_k;
45495
45496       /* privileged (public) methods */
45497       this.hex = function(s) {
45498         return rstr2hex(rstr(s));
45499       };
45500       this.b64 = function(s) {
45501         return rstr2b64(rstr(s), b64pad);
45502       };
45503       this.any = function(s, e) {
45504         return rstr2any(rstr(s), e);
45505       };
45506       this.raw = function(s) {
45507         return rstr(s, utf8);
45508       };
45509       this.hex_hmac = function(k, d) {
45510         return rstr2hex(rstr_hmac(k, d));
45511       };
45512       this.b64_hmac = function(k, d) {
45513         return rstr2b64(rstr_hmac(k, d), b64pad);
45514       };
45515       this.any_hmac = function(k, d, e) {
45516         return rstr2any(rstr_hmac(k, d), e);
45517       };
45518       /**
45519        * Perform a simple self-test to see if the VM is working
45520        * @return {String} Hexadecimal hash sample
45521        * @public
45522        */
45523       this.vm_test = function() {
45524         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45525       };
45526       /**
45527        * @description Enable/disable uppercase hexadecimal returned string
45528        * @param {boolean}
45529        * @return {Object} this
45530        * @public
45531        */
45532       this.setUpperCase = function(a) {
45533         if (typeof a === 'boolean') {
45534           hexcase = a;
45535         }
45536         return this;
45537       };
45538       /**
45539        * @description Defines a base64 pad string
45540        * @param {string} Pad
45541        * @return {Object} this
45542        * @public
45543        */
45544       this.setPad = function(a) {
45545         b64pad = a || b64pad;
45546         return this;
45547       };
45548       /**
45549        * @description Defines a base64 pad string
45550        * @param {boolean}
45551        * @return {Object} this
45552        * @public
45553        */
45554       this.setUTF8 = function(a) {
45555         if (typeof a === 'boolean') {
45556           utf8 = a;
45557         }
45558         return this;
45559       };
45560
45561       /* private methods */
45562
45563       /**
45564        * Calculate the SHA-512 of a raw string
45565        */
45566
45567       function rstr(s) {
45568         s = (utf8) ? utf8Encode(s) : s;
45569         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45570       }
45571       /*
45572        * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
45573        */
45574
45575       function rstr_hmac(key, data) {
45576         key = (utf8) ? utf8Encode(key) : key;
45577         data = (utf8) ? utf8Encode(data) : data;
45578
45579         var hash, i = 0,
45580           bkey = rstr2binb(key),
45581           ipad = Array(32),
45582           opad = Array(32);
45583
45584         if (bkey.length > 32) {
45585           bkey = binb(bkey, key.length * 8);
45586         }
45587
45588         for (; i < 32; i += 1) {
45589           ipad[i] = bkey[i] ^ 0x36363636;
45590           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45591         }
45592
45593         hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
45594         return binb2rstr(binb(opad.concat(hash), 1024 + 512));
45595       }
45596
45597       /**
45598        * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
45599        */
45600
45601       function binb(x, len) {
45602         var j, i, l,
45603           W = new Array(80),
45604           hash = new Array(16),
45605           //Initial hash values
45606           H = [
45607             new int64(0x6a09e667, -205731576),
45608             new int64(-1150833019, -2067093701),
45609             new int64(0x3c6ef372, -23791573),
45610             new int64(-1521486534, 0x5f1d36f1),
45611             new int64(0x510e527f, -1377402159),
45612             new int64(-1694144372, 0x2b3e6c1f),
45613             new int64(0x1f83d9ab, -79577749),
45614             new int64(0x5be0cd19, 0x137e2179)
45615           ],
45616           T1 = new int64(0, 0),
45617           T2 = new int64(0, 0),
45618           a = new int64(0, 0),
45619           b = new int64(0, 0),
45620           c = new int64(0, 0),
45621           d = new int64(0, 0),
45622           e = new int64(0, 0),
45623           f = new int64(0, 0),
45624           g = new int64(0, 0),
45625           h = new int64(0, 0),
45626           //Temporary variables not specified by the document
45627           s0 = new int64(0, 0),
45628           s1 = new int64(0, 0),
45629           Ch = new int64(0, 0),
45630           Maj = new int64(0, 0),
45631           r1 = new int64(0, 0),
45632           r2 = new int64(0, 0),
45633           r3 = new int64(0, 0);
45634
45635         if (sha512_k === undefined) {
45636           //SHA512 constants
45637           sha512_k = [
45638             new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd),
45639             new int64(-1245643825, -330482897), new int64(-373957723, -2121671748),
45640             new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031),
45641             new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736),
45642             new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe),
45643             new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302),
45644             new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1),
45645             new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428),
45646             new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3),
45647             new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65),
45648             new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
45649             new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459),
45650             new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210),
45651             new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340),
45652             new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395),
45653             new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70),
45654             new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
45655             new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473),
45656             new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8),
45657             new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b),
45658             new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023),
45659             new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30),
45660             new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910),
45661             new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
45662             new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53),
45663             new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016),
45664             new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893),
45665             new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397),
45666             new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
45667             new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec),
45668             new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047),
45669             new int64(-1090935817, -1295615723), new int64(-965641998, -479046869),
45670             new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207),
45671             new int64(-354779690, -840897762), new int64(-176337025, -294727304),
45672             new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026),
45673             new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b),
45674             new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
45675             new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620),
45676             new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430),
45677             new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)
45678           ];
45679         }
45680
45681         for (i = 0; i < 80; i += 1) {
45682           W[i] = new int64(0, 0);
45683         }
45684
45685         // append padding to the source string. The format is described in the FIPS.
45686         x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
45687         x[((len + 128 >> 10) << 5) + 31] = len;
45688         l = x.length;
45689         for (i = 0; i < l; i += 32) { //32 dwords is the block size
45690           int64copy(a, H[0]);
45691           int64copy(b, H[1]);
45692           int64copy(c, H[2]);
45693           int64copy(d, H[3]);
45694           int64copy(e, H[4]);
45695           int64copy(f, H[5]);
45696           int64copy(g, H[6]);
45697           int64copy(h, H[7]);
45698
45699           for (j = 0; j < 16; j += 1) {
45700             W[j].h = x[i + 2 * j];
45701             W[j].l = x[i + 2 * j + 1];
45702           }
45703
45704           for (j = 16; j < 80; j += 1) {
45705             //sigma1
45706             int64rrot(r1, W[j - 2], 19);
45707             int64revrrot(r2, W[j - 2], 29);
45708             int64shr(r3, W[j - 2], 6);
45709             s1.l = r1.l ^ r2.l ^ r3.l;
45710             s1.h = r1.h ^ r2.h ^ r3.h;
45711             //sigma0
45712             int64rrot(r1, W[j - 15], 1);
45713             int64rrot(r2, W[j - 15], 8);
45714             int64shr(r3, W[j - 15], 7);
45715             s0.l = r1.l ^ r2.l ^ r3.l;
45716             s0.h = r1.h ^ r2.h ^ r3.h;
45717
45718             int64add4(W[j], s1, W[j - 7], s0, W[j - 16]);
45719           }
45720
45721           for (j = 0; j < 80; j += 1) {
45722             //Ch
45723             Ch.l = (e.l & f.l) ^ (~e.l & g.l);
45724             Ch.h = (e.h & f.h) ^ (~e.h & g.h);
45725
45726             //Sigma1
45727             int64rrot(r1, e, 14);
45728             int64rrot(r2, e, 18);
45729             int64revrrot(r3, e, 9);
45730             s1.l = r1.l ^ r2.l ^ r3.l;
45731             s1.h = r1.h ^ r2.h ^ r3.h;
45732
45733             //Sigma0
45734             int64rrot(r1, a, 28);
45735             int64revrrot(r2, a, 2);
45736             int64revrrot(r3, a, 7);
45737             s0.l = r1.l ^ r2.l ^ r3.l;
45738             s0.h = r1.h ^ r2.h ^ r3.h;
45739
45740             //Maj
45741             Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
45742             Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
45743
45744             int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
45745             int64add(T2, s0, Maj);
45746
45747             int64copy(h, g);
45748             int64copy(g, f);
45749             int64copy(f, e);
45750             int64add(e, d, T1);
45751             int64copy(d, c);
45752             int64copy(c, b);
45753             int64copy(b, a);
45754             int64add(a, T1, T2);
45755           }
45756           int64add(H[0], H[0], a);
45757           int64add(H[1], H[1], b);
45758           int64add(H[2], H[2], c);
45759           int64add(H[3], H[3], d);
45760           int64add(H[4], H[4], e);
45761           int64add(H[5], H[5], f);
45762           int64add(H[6], H[6], g);
45763           int64add(H[7], H[7], h);
45764         }
45765
45766         //represent the hash as an array of 32-bit dwords
45767         for (i = 0; i < 8; i += 1) {
45768           hash[2 * i] = H[i].h;
45769           hash[2 * i + 1] = H[i].l;
45770         }
45771         return hash;
45772       }
45773
45774       //A constructor for 64-bit numbers
45775
45776       function int64(h, l) {
45777         this.h = h;
45778         this.l = l;
45779         //this.toString = int64toString;
45780       }
45781
45782       //Copies src into dst, assuming both are 64-bit numbers
45783
45784       function int64copy(dst, src) {
45785         dst.h = src.h;
45786         dst.l = src.l;
45787       }
45788
45789       //Right-rotates a 64-bit number by shift
45790       //Won't handle cases of shift>=32
45791       //The function revrrot() is for that
45792
45793       function int64rrot(dst, x, shift) {
45794         dst.l = (x.l >>> shift) | (x.h << (32 - shift));
45795         dst.h = (x.h >>> shift) | (x.l << (32 - shift));
45796       }
45797
45798       //Reverses the dwords of the source and then rotates right by shift.
45799       //This is equivalent to rotation by 32+shift
45800
45801       function int64revrrot(dst, x, shift) {
45802         dst.l = (x.h >>> shift) | (x.l << (32 - shift));
45803         dst.h = (x.l >>> shift) | (x.h << (32 - shift));
45804       }
45805
45806       //Bitwise-shifts right a 64-bit number by shift
45807       //Won't handle shift>=32, but it's never needed in SHA512
45808
45809       function int64shr(dst, x, shift) {
45810         dst.l = (x.l >>> shift) | (x.h << (32 - shift));
45811         dst.h = (x.h >>> shift);
45812       }
45813
45814       //Adds two 64-bit numbers
45815       //Like the original implementation, does not rely on 32-bit operations
45816
45817       function int64add(dst, x, y) {
45818         var w0 = (x.l & 0xffff) + (y.l & 0xffff);
45819         var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
45820         var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
45821         var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
45822         dst.l = (w0 & 0xffff) | (w1 << 16);
45823         dst.h = (w2 & 0xffff) | (w3 << 16);
45824       }
45825
45826       //Same, except with 4 addends. Works faster than adding them one by one.
45827
45828       function int64add4(dst, a, b, c, d) {
45829         var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
45830         var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
45831         var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
45832         var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
45833         dst.l = (w0 & 0xffff) | (w1 << 16);
45834         dst.h = (w2 & 0xffff) | (w3 << 16);
45835       }
45836
45837       //Same, except with 5 addends
45838
45839       function int64add5(dst, a, b, c, d, e) {
45840         var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
45841           w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
45842           w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
45843           w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
45844         dst.l = (w0 & 0xffff) | (w1 << 16);
45845         dst.h = (w2 & 0xffff) | (w3 << 16);
45846       }
45847     },
45848     /**
45849      * @class Hashes.RMD160
45850      * @constructor
45851      * @param {Object} [config]
45852      *
45853      * A JavaScript implementation of the RIPEMD-160 Algorithm
45854      * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
45855      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45856      * See http://pajhome.org.uk/crypt/md5 for details.
45857      * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
45858      */
45859     RMD160: function(options) {
45860       /**
45861        * Private properties configuration variables. You may need to tweak these to be compatible with
45862        * the server-side, but the defaults work in most cases.
45863        * @see this.setUpperCase() method
45864        * @see this.setPad() method
45865        */
45866       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false,
45867         /* hexadecimal output case format. false - lowercase; true - uppercase  */
45868         b64pad = (options && typeof options.pad === 'string') ? options.pa : '=',
45869         /* base-64 pad character. Default '=' for strict RFC compliance   */
45870         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
45871         /* enable/disable utf8 encoding */
45872         rmd160_r1 = [
45873           0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
45874           7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
45875           3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
45876           1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
45877           4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
45878         ],
45879         rmd160_r2 = [
45880           5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
45881           6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
45882           15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
45883           8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
45884           12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
45885         ],
45886         rmd160_s1 = [
45887           11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
45888           7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
45889           11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
45890           11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
45891           9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
45892         ],
45893         rmd160_s2 = [
45894           8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
45895           9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
45896           9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
45897           15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
45898           8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
45899         ];
45900
45901       /* privileged (public) methods */
45902       this.hex = function(s) {
45903         return rstr2hex(rstr(s, utf8));
45904       };
45905       this.b64 = function(s) {
45906         return rstr2b64(rstr(s, utf8), b64pad);
45907       };
45908       this.any = function(s, e) {
45909         return rstr2any(rstr(s, utf8), e);
45910       };
45911       this.raw = function(s) {
45912         return rstr(s, utf8);
45913       };
45914       this.hex_hmac = function(k, d) {
45915         return rstr2hex(rstr_hmac(k, d));
45916       };
45917       this.b64_hmac = function(k, d) {
45918         return rstr2b64(rstr_hmac(k, d), b64pad);
45919       };
45920       this.any_hmac = function(k, d, e) {
45921         return rstr2any(rstr_hmac(k, d), e);
45922       };
45923       /**
45924        * Perform a simple self-test to see if the VM is working
45925        * @return {String} Hexadecimal hash sample
45926        * @public
45927        */
45928       this.vm_test = function() {
45929         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45930       };
45931       /**
45932        * @description Enable/disable uppercase hexadecimal returned string
45933        * @param {boolean}
45934        * @return {Object} this
45935        * @public
45936        */
45937       this.setUpperCase = function(a) {
45938         if (typeof a === 'boolean') {
45939           hexcase = a;
45940         }
45941         return this;
45942       };
45943       /**
45944        * @description Defines a base64 pad string
45945        * @param {string} Pad
45946        * @return {Object} this
45947        * @public
45948        */
45949       this.setPad = function(a) {
45950         if (typeof a !== 'undefined') {
45951           b64pad = a;
45952         }
45953         return this;
45954       };
45955       /**
45956        * @description Defines a base64 pad string
45957        * @param {boolean}
45958        * @return {Object} this
45959        * @public
45960        */
45961       this.setUTF8 = function(a) {
45962         if (typeof a === 'boolean') {
45963           utf8 = a;
45964         }
45965         return this;
45966       };
45967
45968       /* private methods */
45969
45970       /**
45971        * Calculate the rmd160 of a raw string
45972        */
45973
45974       function rstr(s) {
45975         s = (utf8) ? utf8Encode(s) : s;
45976         return binl2rstr(binl(rstr2binl(s), s.length * 8));
45977       }
45978
45979       /**
45980        * Calculate the HMAC-rmd160 of a key and some data (raw strings)
45981        */
45982
45983       function rstr_hmac(key, data) {
45984         key = (utf8) ? utf8Encode(key) : key;
45985         data = (utf8) ? utf8Encode(data) : data;
45986         var i, hash,
45987           bkey = rstr2binl(key),
45988           ipad = Array(16),
45989           opad = Array(16);
45990
45991         if (bkey.length > 16) {
45992           bkey = binl(bkey, key.length * 8);
45993         }
45994
45995         for (i = 0; i < 16; i += 1) {
45996           ipad[i] = bkey[i] ^ 0x36363636;
45997           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45998         }
45999         hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
46000         return binl2rstr(binl(opad.concat(hash), 512 + 160));
46001       }
46002
46003       /**
46004        * Convert an array of little-endian words to a string
46005        */
46006
46007       function binl2rstr(input) {
46008         var i, output = '',
46009           l = input.length * 32;
46010         for (i = 0; i < l; i += 8) {
46011           output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
46012         }
46013         return output;
46014       }
46015
46016       /**
46017        * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
46018        */
46019
46020       function binl(x, len) {
46021         var T, j, i, l,
46022           h0 = 0x67452301,
46023           h1 = 0xefcdab89,
46024           h2 = 0x98badcfe,
46025           h3 = 0x10325476,
46026           h4 = 0xc3d2e1f0,
46027           A1, B1, C1, D1, E1,
46028           A2, B2, C2, D2, E2;
46029
46030         /* append padding */
46031         x[len >> 5] |= 0x80 << (len % 32);
46032         x[(((len + 64) >>> 9) << 4) + 14] = len;
46033         l = x.length;
46034
46035         for (i = 0; i < l; i += 16) {
46036           A1 = A2 = h0;
46037           B1 = B2 = h1;
46038           C1 = C2 = h2;
46039           D1 = D2 = h3;
46040           E1 = E2 = h4;
46041           for (j = 0; j <= 79; j += 1) {
46042             T = safe_add(A1, rmd160_f(j, B1, C1, D1));
46043             T = safe_add(T, x[i + rmd160_r1[j]]);
46044             T = safe_add(T, rmd160_K1(j));
46045             T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
46046             A1 = E1;
46047             E1 = D1;
46048             D1 = bit_rol(C1, 10);
46049             C1 = B1;
46050             B1 = T;
46051             T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
46052             T = safe_add(T, x[i + rmd160_r2[j]]);
46053             T = safe_add(T, rmd160_K2(j));
46054             T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
46055             A2 = E2;
46056             E2 = D2;
46057             D2 = bit_rol(C2, 10);
46058             C2 = B2;
46059             B2 = T;
46060           }
46061
46062           T = safe_add(h1, safe_add(C1, D2));
46063           h1 = safe_add(h2, safe_add(D1, E2));
46064           h2 = safe_add(h3, safe_add(E1, A2));
46065           h3 = safe_add(h4, safe_add(A1, B2));
46066           h4 = safe_add(h0, safe_add(B1, C2));
46067           h0 = T;
46068         }
46069         return [h0, h1, h2, h3, h4];
46070       }
46071
46072       // specific algorithm methods
46073
46074       function rmd160_f(j, x, y, z) {
46075         return (0 <= j && j <= 15) ? (x ^ y ^ z) :
46076           (16 <= j && j <= 31) ? (x & y) | (~x & z) :
46077           (32 <= j && j <= 47) ? (x | ~y) ^ z :
46078           (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
46079           (64 <= j && j <= 79) ? x ^ (y | ~z) :
46080           'rmd160_f: j out of range';
46081       }
46082
46083       function rmd160_K1(j) {
46084         return (0 <= j && j <= 15) ? 0x00000000 :
46085           (16 <= j && j <= 31) ? 0x5a827999 :
46086           (32 <= j && j <= 47) ? 0x6ed9eba1 :
46087           (48 <= j && j <= 63) ? 0x8f1bbcdc :
46088           (64 <= j && j <= 79) ? 0xa953fd4e :
46089           'rmd160_K1: j out of range';
46090       }
46091
46092       function rmd160_K2(j) {
46093         return (0 <= j && j <= 15) ? 0x50a28be6 :
46094           (16 <= j && j <= 31) ? 0x5c4dd124 :
46095           (32 <= j && j <= 47) ? 0x6d703ef3 :
46096           (48 <= j && j <= 63) ? 0x7a6d76e9 :
46097           (64 <= j && j <= 79) ? 0x00000000 :
46098           'rmd160_K2: j out of range';
46099       }
46100     }
46101   };
46102
46103   // exposes Hashes
46104   (function(window, undefined) {
46105     var freeExports = false;
46106     {
46107       freeExports = exports;
46108       if (exports && typeof commonjsGlobal === 'object' && commonjsGlobal && commonjsGlobal === commonjsGlobal.global) {
46109         window = commonjsGlobal;
46110       }
46111     }
46112
46113     if (typeof undefined === 'function' && typeof undefined.amd === 'object' && undefined.amd) {
46114       // define as an anonymous module, so, through path mapping, it can be aliased
46115       undefined(function() {
46116         return Hashes;
46117       });
46118     } else if (freeExports) {
46119       // in Node.js or RingoJS v0.8.0+
46120       if ('object' === 'object' && module && module.exports === freeExports) {
46121         module.exports = Hashes;
46122       }
46123       // in Narwhal or RingoJS v0.7.0-
46124       else {
46125         freeExports.Hashes = Hashes;
46126       }
46127     } else {
46128       // in a browser or Rhino
46129       window.Hashes = Hashes;
46130     }
46131   }(this));
46132 }()); // IIFE
46133 });
46134
46135 var immutable = extend$2;
46136
46137 var hasOwnProperty = Object.prototype.hasOwnProperty;
46138
46139 function extend$2() {
46140     var target = {};
46141
46142     for (var i = 0; i < arguments.length; i++) {
46143         var source = arguments[i];
46144
46145         for (var key in source) {
46146             if (hasOwnProperty.call(source, key)) {
46147                 target[key] = source[key];
46148             }
46149         }
46150     }
46151
46152     return target
46153 }
46154
46155 var sha1 = new hashes.SHA1();
46156
46157 var ohauth = {};
46158
46159 ohauth.qsString = function(obj) {
46160     return Object.keys(obj).sort().map(function(key) {
46161         return ohauth.percentEncode(key) + '=' +
46162             ohauth.percentEncode(obj[key]);
46163     }).join('&');
46164 };
46165
46166 ohauth.stringQs = function(str) {
46167     return str.split('&').filter(function (pair) {
46168         return pair !== '';
46169     }).reduce(function(obj, pair){
46170         var parts = pair.split('=');
46171         obj[decodeURIComponent(parts[0])] = (null === parts[1]) ?
46172             '' : decodeURIComponent(parts[1]);
46173         return obj;
46174     }, {});
46175 };
46176
46177 ohauth.rawxhr = function(method, url, data, headers, callback) {
46178     var xhr = new XMLHttpRequest(),
46179         twoHundred = /^20\d$/;
46180     xhr.onreadystatechange = function() {
46181         if (4 === xhr.readyState && 0 !== xhr.status) {
46182             if (twoHundred.test(xhr.status)) callback(null, xhr);
46183             else return callback(xhr, null);
46184         }
46185     };
46186     xhr.onerror = function(e) { return callback(e, null); };
46187     xhr.open(method, url, true);
46188     for (var h in headers) xhr.setRequestHeader(h, headers[h]);
46189     xhr.send(data);
46190     return xhr;
46191 };
46192
46193 ohauth.xhr = function(method, url, auth, data, options, callback) {
46194     var headers = (options && options.header) || {
46195         'Content-Type': 'application/x-www-form-urlencoded'
46196     };
46197     headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
46198     return ohauth.rawxhr(method, url, data, headers, callback);
46199 };
46200
46201 ohauth.nonce = function() {
46202     for (var o = ''; o.length < 6;) {
46203         o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
46204     }
46205     return o;
46206 };
46207
46208 ohauth.authHeader = function(obj) {
46209     return Object.keys(obj).sort().map(function(key) {
46210         return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
46211     }).join(', ');
46212 };
46213
46214 ohauth.timestamp = function() { return ~~((+new Date()) / 1000); };
46215
46216 ohauth.percentEncode = function(s) {
46217     return encodeURIComponent(s)
46218         .replace(/\!/g, '%21').replace(/\'/g, '%27')
46219         .replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
46220 };
46221
46222 ohauth.baseString = function(method, url, params) {
46223     if (params.oauth_signature) delete params.oauth_signature;
46224     return [
46225         method,
46226         ohauth.percentEncode(url),
46227         ohauth.percentEncode(ohauth.qsString(params))].join('&');
46228 };
46229
46230 ohauth.signature = function(oauth_secret, token_secret, baseString) {
46231     return sha1.b64_hmac(
46232         ohauth.percentEncode(oauth_secret) + '&' +
46233         ohauth.percentEncode(token_secret),
46234         baseString);
46235 };
46236
46237 /**
46238  * Takes an options object for configuration (consumer_key,
46239  * consumer_secret, version, signature_method, token, token_secret)
46240  * and returns a function that generates the Authorization header
46241  * for given data.
46242  *
46243  * The returned function takes these parameters:
46244  * - method: GET/POST/...
46245  * - uri: full URI with protocol, port, path and query string
46246  * - extra_params: any extra parameters (that are passed in the POST data),
46247  *   can be an object or a from-urlencoded string.
46248  *
46249  * Returned function returns full OAuth header with "OAuth" string in it.
46250  */
46251
46252 ohauth.headerGenerator = function(options) {
46253     options = options || {};
46254     var consumer_key = options.consumer_key || '',
46255         consumer_secret = options.consumer_secret || '',
46256         signature_method = options.signature_method || 'HMAC-SHA1',
46257         version = options.version || '1.0',
46258         token = options.token || '',
46259         token_secret = options.token_secret || '';
46260
46261     return function(method, uri, extra_params) {
46262         method = method.toUpperCase();
46263         if (typeof extra_params === 'string' && extra_params.length > 0) {
46264             extra_params = ohauth.stringQs(extra_params);
46265         }
46266
46267         var uri_parts = uri.split('?', 2),
46268         base_uri = uri_parts[0];
46269
46270         var query_params = uri_parts.length === 2 ?
46271             ohauth.stringQs(uri_parts[1]) : {};
46272
46273         var oauth_params = {
46274             oauth_consumer_key: consumer_key,
46275             oauth_signature_method: signature_method,
46276             oauth_version: version,
46277             oauth_timestamp: ohauth.timestamp(),
46278             oauth_nonce: ohauth.nonce()
46279         };
46280
46281         if (token) oauth_params.oauth_token = token;
46282
46283         var all_params = immutable({}, oauth_params, query_params, extra_params),
46284             base_str = ohauth.baseString(method, base_uri, all_params);
46285
46286         oauth_params.oauth_signature = ohauth.signature(consumer_secret, token_secret, base_str);
46287
46288         return 'OAuth ' + ohauth.authHeader(oauth_params);
46289     };
46290 };
46291
46292 var index$13 = ohauth;
46293
46294 var store = createCommonjsModule(function (module, exports) {
46295 "use strict"
46296 // Module export pattern from
46297 // https://github.com/umdjs/umd/blob/master/returnExports.js
46298 ;(function (root, factory) {
46299     if (typeof undefined === 'function' && undefined.amd) {
46300         // AMD. Register as an anonymous module.
46301         undefined([], factory);
46302     } else {
46303         // Node. Does not work with strict CommonJS, but
46304         // only CommonJS-like environments that support module.exports,
46305         // like Node.
46306         module.exports = factory();
46307     }
46308 }(commonjsGlobal, function () {
46309         
46310         // Store.js
46311         var store = {},
46312                 win = (typeof window != 'undefined' ? window : commonjsGlobal),
46313                 doc = win.document,
46314                 localStorageName = 'localStorage',
46315                 scriptTag = 'script',
46316                 storage;
46317
46318         store.disabled = false;
46319         store.version = '1.3.20';
46320         store.set = function(key, value) {};
46321         store.get = function(key, defaultVal) {};
46322         store.has = function(key) { return store.get(key) !== undefined };
46323         store.remove = function(key) {};
46324         store.clear = function() {};
46325         store.transact = function(key, defaultVal, transactionFn) {
46326                 if (transactionFn == null) {
46327                         transactionFn = defaultVal;
46328                         defaultVal = null;
46329                 }
46330                 if (defaultVal == null) {
46331                         defaultVal = {};
46332                 }
46333                 var val = store.get(key, defaultVal);
46334                 transactionFn(val);
46335                 store.set(key, val);
46336         };
46337         store.getAll = function() {};
46338         store.forEach = function() {};
46339
46340         store.serialize = function(value) {
46341                 return JSON.stringify(value)
46342         };
46343         store.deserialize = function(value) {
46344                 if (typeof value != 'string') { return undefined }
46345                 try { return JSON.parse(value) }
46346                 catch(e) { return value || undefined }
46347         };
46348
46349         // Functions to encapsulate questionable FireFox 3.6.13 behavior
46350         // when about.config::dom.storage.enabled === false
46351         // See https://github.com/marcuswestin/store.js/issues#issue/13
46352         function isLocalStorageNameSupported() {
46353                 try { return (localStorageName in win && win[localStorageName]) }
46354                 catch(err) { return false }
46355         }
46356
46357         if (isLocalStorageNameSupported()) {
46358                 storage = win[localStorageName];
46359                 store.set = function(key, val) {
46360                         if (val === undefined) { return store.remove(key) }
46361                         storage.setItem(key, store.serialize(val));
46362                         return val
46363                 };
46364                 store.get = function(key, defaultVal) {
46365                         var val = store.deserialize(storage.getItem(key));
46366                         return (val === undefined ? defaultVal : val)
46367                 };
46368                 store.remove = function(key) { storage.removeItem(key); };
46369                 store.clear = function() { storage.clear(); };
46370                 store.getAll = function() {
46371                         var ret = {};
46372                         store.forEach(function(key, val) {
46373                                 ret[key] = val;
46374                         });
46375                         return ret
46376                 };
46377                 store.forEach = function(callback) {
46378                         for (var i=0; i<storage.length; i++) {
46379                                 var key = storage.key(i);
46380                                 callback(key, store.get(key));
46381                         }
46382                 };
46383         } else if (doc && doc.documentElement.addBehavior) {
46384                 var storageOwner,
46385                         storageContainer;
46386                 // Since #userData storage applies only to specific paths, we need to
46387                 // somehow link our data to a specific path.  We choose /favicon.ico
46388                 // as a pretty safe option, since all browsers already make a request to
46389                 // this URL anyway and being a 404 will not hurt us here.  We wrap an
46390                 // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
46391                 // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
46392                 // since the iframe access rules appear to allow direct access and
46393                 // manipulation of the document element, even for a 404 page.  This
46394                 // document can be used instead of the current document (which would
46395                 // have been limited to the current path) to perform #userData storage.
46396                 try {
46397                         storageContainer = new ActiveXObject('htmlfile');
46398                         storageContainer.open();
46399                         storageContainer.write('<'+scriptTag+'>document.w=window</'+scriptTag+'><iframe src="/favicon.ico"></iframe>');
46400                         storageContainer.close();
46401                         storageOwner = storageContainer.w.frames[0].document;
46402                         storage = storageOwner.createElement('div');
46403                 } catch(e) {
46404                         // somehow ActiveXObject instantiation failed (perhaps some special
46405                         // security settings or otherwse), fall back to per-path storage
46406                         storage = doc.createElement('div');
46407                         storageOwner = doc.body;
46408                 }
46409                 var withIEStorage = function(storeFunction) {
46410                         return function() {
46411                                 var args = Array.prototype.slice.call(arguments, 0);
46412                                 args.unshift(storage);
46413                                 // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
46414                                 // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
46415                                 storageOwner.appendChild(storage);
46416                                 storage.addBehavior('#default#userData');
46417                                 storage.load(localStorageName);
46418                                 var result = storeFunction.apply(store, args);
46419                                 storageOwner.removeChild(storage);
46420                                 return result
46421                         }
46422                 };
46423
46424                 // In IE7, keys cannot start with a digit or contain certain chars.
46425                 // See https://github.com/marcuswestin/store.js/issues/40
46426                 // See https://github.com/marcuswestin/store.js/issues/83
46427                 var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
46428                 var ieKeyFix = function(key) {
46429                         return key.replace(/^d/, '___$&').replace(forbiddenCharsRegex, '___')
46430                 };
46431                 store.set = withIEStorage(function(storage, key, val) {
46432                         key = ieKeyFix(key);
46433                         if (val === undefined) { return store.remove(key) }
46434                         storage.setAttribute(key, store.serialize(val));
46435                         storage.save(localStorageName);
46436                         return val
46437                 });
46438                 store.get = withIEStorage(function(storage, key, defaultVal) {
46439                         key = ieKeyFix(key);
46440                         var val = store.deserialize(storage.getAttribute(key));
46441                         return (val === undefined ? defaultVal : val)
46442                 });
46443                 store.remove = withIEStorage(function(storage, key) {
46444                         key = ieKeyFix(key);
46445                         storage.removeAttribute(key);
46446                         storage.save(localStorageName);
46447                 });
46448                 store.clear = withIEStorage(function(storage) {
46449                         var attributes = storage.XMLDocument.documentElement.attributes;
46450                         storage.load(localStorageName);
46451                         for (var i=attributes.length-1; i>=0; i--) {
46452                                 storage.removeAttribute(attributes[i].name);
46453                         }
46454                         storage.save(localStorageName);
46455                 });
46456                 store.getAll = function(storage) {
46457                         var ret = {};
46458                         store.forEach(function(key, val) {
46459                                 ret[key] = val;
46460                         });
46461                         return ret
46462                 };
46463                 store.forEach = withIEStorage(function(storage, callback) {
46464                         var attributes = storage.XMLDocument.documentElement.attributes;
46465                         for (var i=0, attr; attr=attributes[i]; ++i) {
46466                                 callback(attr.name, store.deserialize(storage.getAttribute(attr.name)));
46467                         }
46468                 });
46469         }
46470
46471         try {
46472                 var testKey = '__storejs__';
46473                 store.set(testKey, testKey);
46474                 if (store.get(testKey) != testKey) { store.disabled = true; }
46475                 store.remove(testKey);
46476         } catch(e) {
46477                 store.disabled = true;
46478         }
46479         store.enabled = !store.disabled;
46480         
46481         return store
46482 }));
46483 });
46484
46485 // # osm-auth
46486 //
46487 // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
46488 // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
46489 // does not support custom headers, which this uses everywhere.
46490 var index$12 = function(o) {
46491
46492     var oauth = {};
46493
46494     // authenticated users will also have a request token secret, but it's
46495     // not used in transactions with the server
46496     oauth.authenticated = function() {
46497         return !!(token('oauth_token') && token('oauth_token_secret'));
46498     };
46499
46500     oauth.logout = function() {
46501         token('oauth_token', '');
46502         token('oauth_token_secret', '');
46503         token('oauth_request_token_secret', '');
46504         return oauth;
46505     };
46506
46507     // TODO: detect lack of click event
46508     oauth.authenticate = function(callback) {
46509         if (oauth.authenticated()) return callback();
46510
46511         oauth.logout();
46512
46513         // ## Getting a request token
46514         var params = timenonce(getAuth(o)),
46515             url = o.url + '/oauth/request_token';
46516
46517         params.oauth_signature = index$13.signature(
46518             o.oauth_secret, '',
46519             index$13.baseString('POST', url, params));
46520
46521         if (!o.singlepage) {
46522             // Create a 600x550 popup window in the center of the screen
46523             var w = 600, h = 550,
46524                 settings = [
46525                     ['width', w], ['height', h],
46526                     ['left', screen.width / 2 - w / 2],
46527                     ['top', screen.height / 2 - h / 2]].map(function(x) {
46528                         return x.join('=');
46529                     }).join(','),
46530                 popup = window.open('about:blank', 'oauth_window', settings);
46531         }
46532
46533         // Request a request token. When this is complete, the popup
46534         // window is redirected to OSM's authorization page.
46535         index$13.xhr('POST', url, params, null, {}, reqTokenDone);
46536         o.loading();
46537
46538         function reqTokenDone(err, xhr) {
46539             o.done();
46540             if (err) return callback(err);
46541             var resp = index$13.stringQs(xhr.response);
46542             token('oauth_request_token_secret', resp.oauth_token_secret);
46543             var authorize_url = o.url + '/oauth/authorize?' + index$13.qsString({
46544                 oauth_token: resp.oauth_token,
46545                 oauth_callback: location.href.replace('index.html', '')
46546                     .replace(/#.*/, '').replace(location.search, '') + o.landing
46547             });
46548
46549             if (o.singlepage) {
46550                 location.href = authorize_url;
46551             } else {
46552                 popup.location = authorize_url;
46553             }
46554         }
46555
46556         // Called by a function in a landing page, in the popup window. The
46557         // window closes itself.
46558         window.authComplete = function(token) {
46559             var oauth_token = index$13.stringQs(token.split('?')[1]);
46560             get_access_token(oauth_token.oauth_token);
46561             delete window.authComplete;
46562         };
46563
46564         // ## Getting an request token
46565         //
46566         // At this point we have an `oauth_token`, brought in from a function
46567         // call on a landing page popup.
46568         function get_access_token(oauth_token) {
46569             var url = o.url + '/oauth/access_token',
46570                 params = timenonce(getAuth(o)),
46571                 request_token_secret = token('oauth_request_token_secret');
46572             params.oauth_token = oauth_token;
46573             params.oauth_signature = index$13.signature(
46574                 o.oauth_secret,
46575                 request_token_secret,
46576                 index$13.baseString('POST', url, params));
46577
46578             // ## Getting an access token
46579             //
46580             // The final token required for authentication. At this point
46581             // we have a `request token secret`
46582             index$13.xhr('POST', url, params, null, {}, accessTokenDone);
46583             o.loading();
46584         }
46585
46586         function accessTokenDone(err, xhr) {
46587             o.done();
46588             if (err) return callback(err);
46589             var access_token = index$13.stringQs(xhr.response);
46590             token('oauth_token', access_token.oauth_token);
46591             token('oauth_token_secret', access_token.oauth_token_secret);
46592             callback(null, oauth);
46593         }
46594     };
46595
46596     oauth.bootstrapToken = function(oauth_token, callback) {
46597         // ## Getting an request token
46598         // At this point we have an `oauth_token`, brought in from a function
46599         // call on a landing page popup.
46600         function get_access_token(oauth_token) {
46601             var url = o.url + '/oauth/access_token',
46602                 params = timenonce(getAuth(o)),
46603                 request_token_secret = token('oauth_request_token_secret');
46604             params.oauth_token = oauth_token;
46605             params.oauth_signature = index$13.signature(
46606                 o.oauth_secret,
46607                 request_token_secret,
46608                 index$13.baseString('POST', url, params));
46609
46610             // ## Getting an access token
46611             // The final token required for authentication. At this point
46612             // we have a `request token secret`
46613             index$13.xhr('POST', url, params, null, {}, accessTokenDone);
46614             o.loading();
46615         }
46616
46617         function accessTokenDone(err, xhr) {
46618             o.done();
46619             if (err) return callback(err);
46620             var access_token = index$13.stringQs(xhr.response);
46621             token('oauth_token', access_token.oauth_token);
46622             token('oauth_token_secret', access_token.oauth_token_secret);
46623             callback(null, oauth);
46624         }
46625
46626         get_access_token(oauth_token);
46627     };
46628
46629     // # xhr
46630     //
46631     // A single XMLHttpRequest wrapper that does authenticated calls if the
46632     // user has logged in.
46633     oauth.xhr = function(options, callback) {
46634         if (!oauth.authenticated()) {
46635             if (o.auto) {
46636                 return oauth.authenticate(run);
46637             } else {
46638                 callback('not authenticated', null);
46639                 return;
46640             }
46641         } else {
46642             return run();
46643         }
46644
46645         function run() {
46646             var params = timenonce(getAuth(o)),
46647                 oauth_token_secret = token('oauth_token_secret'),
46648                 url = (options.prefix !== false) ? o.url + options.path : options.path,
46649                 url_parts = url.replace(/#.*$/, '').split('?', 2),
46650                 base_url = url_parts[0],
46651                 query = (url_parts.length === 2) ? url_parts[1] : '';
46652
46653             // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
46654             if ((!options.options || !options.options.header ||
46655                 options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') &&
46656                 options.content) {
46657                 params = immutable(params, index$13.stringQs(options.content));
46658             }
46659
46660             params.oauth_token = token('oauth_token');
46661             params.oauth_signature = index$13.signature(
46662                 o.oauth_secret,
46663                 oauth_token_secret,
46664                 index$13.baseString(options.method, base_url, immutable(params, index$13.stringQs(query)))
46665             );
46666
46667             return index$13.xhr(options.method, url, params, options.content, options.options, done);
46668         }
46669
46670         function done(err, xhr) {
46671             if (err) return callback(err);
46672             else if (xhr.responseXML) return callback(err, xhr.responseXML);
46673             else return callback(err, xhr.response);
46674         }
46675     };
46676
46677     // pre-authorize this object, if we can just get a token and token_secret
46678     // from the start
46679     oauth.preauth = function(c) {
46680         if (!c) return;
46681         if (c.oauth_token) token('oauth_token', c.oauth_token);
46682         if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
46683         return oauth;
46684     };
46685
46686     oauth.options = function(_) {
46687         if (!arguments.length) return o;
46688
46689         o = _;
46690         o.url = o.url || 'http://www.openstreetmap.org';
46691         o.landing = o.landing || 'land.html';
46692         o.singlepage = o.singlepage || false;
46693
46694         // Optional loading and loading-done functions for nice UI feedback.
46695         // by default, no-ops
46696         o.loading = o.loading || function() {};
46697         o.done = o.done || function() {};
46698
46699         return oauth.preauth(o);
46700     };
46701
46702     // 'stamp' an authentication object from `getAuth()`
46703     // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
46704     // and timestamp
46705     function timenonce(o) {
46706         o.oauth_timestamp = index$13.timestamp();
46707         o.oauth_nonce = index$13.nonce();
46708         return o;
46709     }
46710
46711     // get/set tokens. These are prefixed with the base URL so that `osm-auth`
46712     // can be used with multiple APIs and the keys in `localStorage`
46713     // will not clash
46714     var token;
46715
46716     if (store.enabled) {
46717         token = function (x, y) {
46718             if (arguments.length === 1) return store.get(o.url + x);
46719             else if (arguments.length === 2) return store.set(o.url + x, y);
46720         };
46721     } else {
46722         var storage = {};
46723         token = function (x, y) {
46724             if (arguments.length === 1) return storage[o.url + x];
46725             else if (arguments.length === 2) return storage[o.url + x] = y;
46726         };
46727     }
46728
46729     // Get an authentication object. If you just add and remove properties
46730     // from a single object, you'll need to use `delete` to make sure that
46731     // it doesn't contain undesired properties for authentication
46732     function getAuth(o) {
46733         return {
46734             oauth_consumer_key: o.oauth_consumer_key,
46735             oauth_signature_method: 'HMAC-SHA1'
46736         };
46737     }
46738
46739     // potentially pre-authorize
46740     oauth.options(o);
46741
46742     return oauth;
46743 };
46744
46745 var JXON = new (function () {
46746   var
46747     sValueProp = 'keyValue', sAttributesProp = 'keyAttributes', sAttrPref = '@', /* you can customize these values */
46748     aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
46749
46750   function parseText (sValue) {
46751     if (rIsNull.test(sValue)) { return null; }
46752     if (rIsBool.test(sValue)) { return sValue.toLowerCase() === 'true'; }
46753     if (isFinite(sValue)) { return parseFloat(sValue); }
46754     if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
46755     return sValue;
46756   }
46757
46758   function EmptyTree () { }
46759   EmptyTree.prototype.toString = function () { return 'null'; };
46760   EmptyTree.prototype.valueOf = function () { return null; };
46761
46762   function objectify (vValue) {
46763     return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
46764   }
46765
46766   function createObjTree (oParentNode, nVerb, bFreeze, bNesteAttr) {
46767     var
46768       nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(),
46769       bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
46770
46771     var
46772       sProp, vContent, nLength = 0, sCollectedTxt = '',
46773       vResult = bHighVerb ? {} : /* put here the default value for empty nodes: */ true;
46774
46775     if (bChildren) {
46776       for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
46777         oNode = oParentNode.childNodes.item(nItem);
46778         if (oNode.nodeType === 4) { sCollectedTxt += oNode.nodeValue; } /* nodeType is 'CDATASection' (4) */
46779         else if (oNode.nodeType === 3) { sCollectedTxt += oNode.nodeValue.trim(); } /* nodeType is 'Text' (3) */
46780         else if (oNode.nodeType === 1 && !oNode.prefix) { aCache.push(oNode); } /* nodeType is 'Element' (1) */
46781       }
46782     }
46783
46784     var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
46785
46786     if (!bHighVerb && (bChildren || bAttributes)) { vResult = nVerb === 0 ? objectify(vBuiltVal) : {}; }
46787
46788     for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
46789       sProp = aCache[nElId].nodeName.toLowerCase();
46790       vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
46791       if (vResult.hasOwnProperty(sProp)) {
46792         if (vResult[sProp].constructor !== Array) { vResult[sProp] = [vResult[sProp]]; }
46793         vResult[sProp].push(vContent);
46794       } else {
46795         vResult[sProp] = vContent;
46796         nLength++;
46797       }
46798     }
46799
46800     if (bAttributes) {
46801       var
46802         nAttrLen = oParentNode.attributes.length,
46803         sAPrefix = bNesteAttr ? '' : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
46804
46805       for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
46806         oAttrib = oParentNode.attributes.item(nAttrib);
46807         oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
46808       }
46809
46810       if (bNesteAttr) {
46811         if (bFreeze) { Object.freeze(oAttrParent); }
46812         vResult[sAttributesProp] = oAttrParent;
46813         nLength -= nAttrLen - 1;
46814       }
46815     }
46816
46817     if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
46818       vResult[sValueProp] = vBuiltVal;
46819     } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
46820       vResult = vBuiltVal;
46821     }
46822
46823     if (bFreeze && (bHighVerb || nLength > 0)) { Object.freeze(vResult); }
46824
46825     aCache.length = nLevelStart;
46826
46827     return vResult;
46828   }
46829
46830   function loadObjTree (oXMLDoc, oParentEl, oParentObj) {
46831     var vValue, oChild;
46832
46833     if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
46834       oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 */
46835     } else if (oParentObj.constructor === Date) {
46836       oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));    
46837     }
46838
46839     for (var sName in oParentObj) {
46840       vValue = oParentObj[sName];
46841       if (isFinite(sName) || vValue instanceof Function) { continue; } /* verbosity level is 0 */
46842       if (sName === sValueProp) {
46843         if (vValue !== null && vValue !== true) { oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue))); }
46844       } else if (sName === sAttributesProp) { /* verbosity level is 3 */
46845         for (var sAttrib in vValue) { oParentEl.setAttribute(sAttrib, vValue[sAttrib]); }
46846       } else if (sName.charAt(0) === sAttrPref) {
46847         oParentEl.setAttribute(sName.slice(1), vValue);
46848       } else if (vValue.constructor === Array) {
46849         for (var nItem = 0; nItem < vValue.length; nItem++) {
46850           oChild = oXMLDoc.createElement(sName);
46851           loadObjTree(oXMLDoc, oChild, vValue[nItem]);
46852           oParentEl.appendChild(oChild);
46853         }
46854       } else {
46855         oChild = oXMLDoc.createElement(sName);
46856         if (vValue instanceof Object) {
46857           loadObjTree(oXMLDoc, oChild, vValue);
46858         } else if (vValue !== null && vValue !== true) {
46859           oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
46860         }
46861         oParentEl.appendChild(oChild);
46862      }
46863    }
46864   }
46865
46866   this.build = function (oXMLParent, nVerbosity /* optional */, bFreeze /* optional */, bNesteAttributes /* optional */) {
46867     var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 : /* put here the default verbosity level: */ 1;
46868     return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);    
46869   };
46870
46871   this.unbuild = function (oObjTree) {    
46872     var oNewDoc = document.implementation.createDocument('', '', null);
46873     loadObjTree(oNewDoc, oNewDoc, oObjTree);
46874     return oNewDoc;
46875   };
46876
46877   this.stringify = function (oObjTree) {
46878     return (new XMLSerializer()).serializeToString(JXON.unbuild(oObjTree));
46879   };
46880 })();
46881
46882 // var myObject = JXON.build(doc);
46883 // we got our javascript object! try: alert(JSON.stringify(myObject));
46884
46885 // var newDoc = JXON.unbuild(myObject);
46886 // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
46887
46888 var dispatch$3 = dispatch('authLoading', 'authDone', 'change', 'loading', 'loaded');
46889 var urlroot = 'https://www.openstreetmap.org';
46890 var blacklists = ['.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*'];
46891 var inflight$1 = {};
46892 var loadedTiles = {};
46893 var tileZoom$1 = 16;
46894 var oauth = index$12({
46895         url: urlroot,
46896         oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
46897         oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
46898         loading: authLoading,
46899         done: authDone
46900     });
46901 var rateLimitError;
46902 var userChangesets;
46903 var userDetails;
46904 var off;
46905
46906
46907 function authLoading() {
46908     dispatch$3.call('authLoading');
46909 }
46910
46911
46912 function authDone() {
46913     dispatch$3.call('authDone');
46914 }
46915
46916
46917 function abortRequest$1(i) {
46918     if (i) {
46919         i.abort();
46920     }
46921 }
46922
46923
46924 function getLoc(attrs) {
46925     var lon = attrs.lon && attrs.lon.value,
46926         lat = attrs.lat && attrs.lat.value;
46927     return [parseFloat(lon), parseFloat(lat)];
46928 }
46929
46930
46931 function getNodes(obj) {
46932     var elems = obj.getElementsByTagName('nd'),
46933         nodes = new Array(elems.length);
46934     for (var i = 0, l = elems.length; i < l; i++) {
46935         nodes[i] = 'n' + elems[i].attributes.ref.value;
46936     }
46937     return nodes;
46938 }
46939
46940
46941 function getTags(obj) {
46942     var elems = obj.getElementsByTagName('tag'),
46943         tags = {};
46944     for (var i = 0, l = elems.length; i < l; i++) {
46945         var attrs = elems[i].attributes;
46946         tags[attrs.k.value] = attrs.v.value;
46947     }
46948
46949     return tags;
46950 }
46951
46952
46953 function getMembers(obj) {
46954     var elems = obj.getElementsByTagName('member'),
46955         members = new Array(elems.length);
46956     for (var i = 0, l = elems.length; i < l; i++) {
46957         var attrs = elems[i].attributes;
46958         members[i] = {
46959             id: attrs.type.value[0] + attrs.ref.value,
46960             type: attrs.type.value,
46961             role: attrs.role.value
46962         };
46963     }
46964     return members;
46965 }
46966
46967
46968 function getVisible(attrs) {
46969     return (!attrs.visible || attrs.visible.value !== 'false');
46970 }
46971
46972
46973 var parsers = {
46974     node: function nodeData(obj) {
46975         var attrs = obj.attributes;
46976         return new osmNode({
46977             id: osmEntity$$1.id.fromOSM('node', attrs.id.value),
46978             loc: getLoc(attrs),
46979             version: attrs.version.value,
46980             user: attrs.user && attrs.user.value,
46981             tags: getTags(obj),
46982             visible: getVisible(attrs)
46983         });
46984     },
46985
46986     way: function wayData(obj) {
46987         var attrs = obj.attributes;
46988         return new osmWay({
46989             id: osmEntity$$1.id.fromOSM('way', attrs.id.value),
46990             version: attrs.version.value,
46991             user: attrs.user && attrs.user.value,
46992             tags: getTags(obj),
46993             nodes: getNodes(obj),
46994             visible: getVisible(attrs)
46995         });
46996     },
46997
46998     relation: function relationData(obj) {
46999         var attrs = obj.attributes;
47000         return new osmRelation({
47001             id: osmEntity$$1.id.fromOSM('relation', attrs.id.value),
47002             version: attrs.version.value,
47003             user: attrs.user && attrs.user.value,
47004             tags: getTags(obj),
47005             members: getMembers(obj),
47006             visible: getVisible(attrs)
47007         });
47008     }
47009 };
47010
47011
47012 function parse$1(xml$$1) {
47013     if (!xml$$1 || !xml$$1.childNodes) return;
47014
47015     var root = xml$$1.childNodes[0],
47016         children = root.childNodes,
47017         entities = [];
47018
47019     for (var i = 0, l = children.length; i < l; i++) {
47020         var child = children[i],
47021             parser = parsers[child.nodeName];
47022         if (parser) {
47023             entities.push(parser(child));
47024         }
47025     }
47026
47027     return entities;
47028 }
47029
47030
47031 var serviceOsm = {
47032
47033     init: function() {
47034         utilRebind(this, dispatch$3, 'on');
47035     },
47036
47037
47038     reset: function() {
47039         userChangesets = undefined;
47040         userDetails = undefined;
47041         rateLimitError = undefined;
47042         lodash.forEach(inflight$1, abortRequest$1);
47043         loadedTiles = {};
47044         inflight$1 = {};
47045         return this;
47046     },
47047
47048
47049     changesetURL: function(changesetId) {
47050         return urlroot + '/changeset/' + changesetId;
47051     },
47052
47053
47054     changesetsURL: function(center, zoom$$1) {
47055         var precision = Math.max(0, Math.ceil(Math.log(zoom$$1) / Math.LN2));
47056         return urlroot + '/history#map=' +
47057             Math.floor(zoom$$1) + '/' +
47058             center[1].toFixed(precision) + '/' +
47059             center[0].toFixed(precision);
47060     },
47061
47062
47063     entityURL: function(entity) {
47064         return urlroot + '/' + entity.type + '/' + entity.osmId();
47065     },
47066
47067
47068     userURL: function(username) {
47069         return urlroot + '/user/' + username;
47070     },
47071
47072
47073     loadFromAPI: function(path$$1, callback) {
47074         var that = this;
47075
47076         function done(err, xml$$1) {
47077             var isAuthenticated = that.authenticated();
47078
47079             // 400 Bad Request, 401 Unauthorized, 403 Forbidden
47080             // Logout and retry the request..
47081             if (isAuthenticated && err &&
47082                     (err.status === 400 || err.status === 401 || err.status === 403)) {
47083                 that.logout();
47084                 that.loadFromAPI(path$$1, callback);
47085
47086             // else, no retry..
47087             } else {
47088                 // 509 Bandwidth Limit Exceeded, 429 Too Many Requests
47089                 // Set the rateLimitError flag and trigger a warning..
47090                 if (!isAuthenticated && !rateLimitError && err &&
47091                         (err.status === 509 || err.status === 429)) {
47092                     rateLimitError = err;
47093                     dispatch$3.call('change');
47094                 }
47095
47096                 if (callback) {
47097                     callback(err, parse$1(xml$$1));
47098                 }
47099             }
47100         }
47101
47102         if (this.authenticated()) {
47103             return oauth.xhr({ method: 'GET', path: path$$1 }, done);
47104         } else {
47105             var url = urlroot + path$$1;
47106             return xml(url).get(done);
47107         }
47108     },
47109
47110
47111     loadEntity: function(id, callback) {
47112         var type = osmEntity$$1.id.type(id),
47113             osmID = osmEntity$$1.id.toOSM(id);
47114
47115         this.loadFromAPI(
47116             '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''),
47117             function(err, entities) {
47118                 if (callback) callback(err, { data: entities });
47119             }
47120         );
47121     },
47122
47123
47124     loadEntityVersion: function(id, version$$1, callback) {
47125         var type = osmEntity$$1.id.type(id),
47126             osmID = osmEntity$$1.id.toOSM(id);
47127
47128         this.loadFromAPI(
47129             '/api/0.6/' + type + '/' + osmID + '/' + version$$1,
47130             function(err, entities) {
47131                 if (callback) callback(err, { data: entities });
47132             }
47133         );
47134     },
47135
47136
47137     loadMultiple: function(ids, callback) {
47138         var that = this;
47139         lodash.each(lodash.groupBy(lodash.uniq(ids), osmEntity$$1.id.type), function(v, k) {
47140             var type = k + 's',
47141                 osmIDs = lodash.map(v, osmEntity$$1.id.toOSM);
47142
47143             lodash.each(lodash.chunk(osmIDs, 150), function(arr) {
47144                 that.loadFromAPI(
47145                     '/api/0.6/' + type + '?' + type + '=' + arr.join(),
47146                     function(err, entities) {
47147                         if (callback) callback(err, { data: entities });
47148                     }
47149                 );
47150             });
47151         });
47152     },
47153
47154
47155     authenticated: function() {
47156         return oauth.authenticated();
47157     },
47158
47159
47160     putChangeset: function(changeset, changes, callback) {
47161
47162         // Create the changeset..
47163         oauth.xhr({
47164             method: 'PUT',
47165             path: '/api/0.6/changeset/create',
47166             options: { header: { 'Content-Type': 'text/xml' } },
47167             content: JXON.stringify(changeset.asJXON())
47168         }, createdChangeset);
47169
47170
47171         function createdChangeset(err, changeset_id) {
47172             if (err) return callback(err);
47173             changeset = changeset.update({ id: changeset_id });
47174
47175             // Upload the changeset..
47176             oauth.xhr({
47177                 method: 'POST',
47178                 path: '/api/0.6/changeset/' + changeset_id + '/upload',
47179                 options: { header: { 'Content-Type': 'text/xml' } },
47180                 content: JXON.stringify(changeset.osmChangeJXON(changes))
47181             }, uploadedChangeset);
47182         }
47183
47184
47185         function uploadedChangeset(err) {
47186             if (err) return callback(err);
47187
47188             // Upload was successful, safe to call the callback.
47189             // Add delay to allow for postgres replication #1646 #2678
47190             window.setTimeout(function() {
47191                 callback(null, changeset);
47192             }, 2500);
47193
47194             // Still attempt to close changeset, but ignore response because #2667
47195             oauth.xhr({
47196                 method: 'PUT',
47197                 path: '/api/0.6/changeset/' + changeset.id + '/close',
47198                 options: { header: { 'Content-Type': 'text/xml' } }
47199             }, function() { return true; });
47200         }
47201     },
47202
47203
47204     userDetails: function(callback) {
47205         if (userDetails) {
47206             callback(undefined, userDetails);
47207             return;
47208         }
47209
47210         function done(err, user_details) {
47211             if (err) return callback(err);
47212
47213             var u = user_details.getElementsByTagName('user')[0],
47214                 img = u.getElementsByTagName('img'),
47215                 image_url = '';
47216
47217             if (img && img[0] && img[0].getAttribute('href')) {
47218                 image_url = img[0].getAttribute('href');
47219             }
47220
47221             userDetails = {
47222                 display_name: u.attributes.display_name.value,
47223                 image_url: image_url,
47224                 id: u.attributes.id.value
47225             };
47226
47227             callback(undefined, userDetails);
47228         }
47229
47230         oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
47231     },
47232
47233
47234     userChangesets: function(callback) {
47235         if (userChangesets) {
47236             callback(undefined, userChangesets);
47237             return;
47238         }
47239
47240         this.userDetails(function(err, user) {
47241             if (err) {
47242                 callback(err);
47243                 return;
47244             }
47245
47246             function done(err, changesets) {
47247                 if (err) {
47248                     callback(err);
47249                 } else {
47250                     userChangesets = Array.prototype.map.call(
47251                         changesets.getElementsByTagName('changeset'),
47252                         function (changeset) {
47253                             return { tags: getTags(changeset) };
47254                         }
47255                     ).filter(function (changeset) {
47256                         var comment = changeset.tags.comment;
47257                         return comment && comment !== '';
47258                     });
47259                     callback(undefined, userChangesets);
47260                 }
47261             }
47262
47263             oauth.xhr({ method: 'GET', path: '/api/0.6/changesets?user=' + user.id }, done);
47264         });
47265     },
47266
47267
47268     status: function(callback) {
47269         function done(xml$$1) {
47270             // update blacklists
47271             var elements = xml$$1.getElementsByTagName('blacklist'),
47272                 regexes = [];
47273             for (var i = 0; i < elements.length; i++) {
47274                 var regex = elements[i].getAttribute('regex');  // needs unencode?
47275                 if (regex) {
47276                     regexes.push(regex);
47277                 }
47278             }
47279             if (regexes.length) {
47280                 blacklists = regexes;
47281             }
47282
47283
47284             if (rateLimitError) {
47285                 callback(rateLimitError, 'rateLimited');
47286             } else {
47287                 var apiStatus = xml$$1.getElementsByTagName('status'),
47288                     val = apiStatus[0].getAttribute('api');
47289
47290                 callback(undefined, val);
47291             }
47292         }
47293
47294         xml(urlroot + '/api/capabilities').get()
47295             .on('load', done)
47296             .on('error', callback);
47297     },
47298
47299
47300     imageryBlacklists: function() {
47301         return blacklists;
47302     },
47303
47304
47305     tileZoom: function(_) {
47306         if (!arguments.length) return tileZoom$1;
47307         tileZoom$1 = _;
47308         return this;
47309     },
47310
47311
47312     loadTiles: function(projection, dimensions, callback) {
47313         if (off) return;
47314
47315         var that = this,
47316             s = projection.scale() * 2 * Math.PI,
47317             z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
47318             ts = 256 * Math.pow(2, z - tileZoom$1),
47319             origin = [
47320                 s / 2 - projection.translate()[0],
47321                 s / 2 - projection.translate()[1]
47322             ];
47323
47324         var tiles = d3geoTile()
47325             .scaleExtent([tileZoom$1, tileZoom$1])
47326             .scale(s)
47327             .size(dimensions)
47328             .translate(projection.translate())()
47329             .map(function(tile) {
47330                 var x = tile[0] * ts - origin[0],
47331                     y = tile[1] * ts - origin[1];
47332
47333                 return {
47334                     id: tile.toString(),
47335                     extent: geoExtent$$1(
47336                         projection.invert([x, y + ts]),
47337                         projection.invert([x + ts, y]))
47338                 };
47339             });
47340
47341         lodash.filter(inflight$1, function(v, i) {
47342             var wanted = lodash.find(tiles, function(tile) {
47343                 return i === tile.id;
47344             });
47345             if (!wanted) delete inflight$1[i];
47346             return !wanted;
47347         }).map(abortRequest$1);
47348
47349         tiles.forEach(function(tile) {
47350             var id = tile.id;
47351
47352             if (loadedTiles[id] || inflight$1[id]) return;
47353
47354             if (lodash.isEmpty(inflight$1)) {
47355                 dispatch$3.call('loading');
47356             }
47357
47358             inflight$1[id] = that.loadFromAPI(
47359                 '/api/0.6/map?bbox=' + tile.extent.toParam(),
47360                 function(err, parsed) {
47361                     delete inflight$1[id];
47362                     if (!err) {
47363                         loadedTiles[id] = true;
47364                     }
47365
47366                     if (callback) {
47367                         callback(err, lodash.extend({ data: parsed }, tile));
47368                     }
47369
47370                     if (lodash.isEmpty(inflight$1)) {
47371                         dispatch$3.call('loaded');
47372                     }
47373                 }
47374             );
47375         });
47376     },
47377
47378
47379     switch: function(options) {
47380         urlroot = options.urlroot;
47381
47382         oauth.options(lodash.extend({
47383             url: urlroot,
47384             loading: authLoading,
47385             done: authDone
47386         }, options));
47387
47388         dispatch$3.call('change');
47389         this.reset();
47390         this.userChangesets(function() {});  // eagerly load user details/changesets
47391         return this;
47392     },
47393
47394
47395     toggle: function(_) {
47396         off = !_;
47397         return this;
47398     },
47399
47400
47401     loadedTiles: function(_) {
47402         if (!arguments.length) return loadedTiles;
47403         loadedTiles = _;
47404         return this;
47405     },
47406
47407
47408     logout: function() {
47409         userChangesets = undefined;
47410         userDetails = undefined;
47411         oauth.logout();
47412         dispatch$3.call('change');
47413         return this;
47414     },
47415
47416
47417     authenticate: function(callback) {
47418         var that = this;
47419         userChangesets = undefined;
47420         userDetails = undefined;
47421
47422         function done(err, res) {
47423             rateLimitError = undefined;
47424             dispatch$3.call('change');
47425             if (callback) callback(err, res);
47426             that.userChangesets(function() {});  // eagerly load user details/changesets
47427         }
47428
47429         return oauth.authenticate(done);
47430     }
47431 };
47432
47433 var apibase$2 = 'https://taginfo.openstreetmap.org/api/4/';
47434 var inflight$2 = {};
47435 var popularKeys = {};
47436 var taginfoCache = {};
47437 var tag_sorts = {
47438         point: 'count_nodes',
47439         vertex: 'count_nodes',
47440         area: 'count_ways',
47441         line: 'count_ways'
47442     };
47443 var tag_sort_members = {
47444         point: 'count_node_members',
47445         vertex: 'count_node_members',
47446         area: 'count_way_members',
47447         line: 'count_way_members',
47448         relation: 'count_relation_members'
47449     };
47450 var tag_filters = {
47451         point: 'nodes',
47452         vertex: 'nodes',
47453         area: 'ways',
47454         line: 'ways'
47455     };
47456 var tag_members_fractions = {
47457         point: 'count_node_members_fraction',
47458         vertex: 'count_node_members_fraction',
47459         area: 'count_way_members_fraction',
47460         line: 'count_way_members_fraction',
47461         relation: 'count_relation_members_fraction'
47462     };
47463
47464
47465 function sets(params, n, o) {
47466     if (params.geometry && o[params.geometry]) {
47467         params[n] = o[params.geometry];
47468     }
47469     return params;
47470 }
47471
47472
47473 function setFilter(params) {
47474     return sets(params, 'filter', tag_filters);
47475 }
47476
47477
47478 function setSort(params) {
47479     return sets(params, 'sortname', tag_sorts);
47480 }
47481
47482
47483 function setSortMembers(params) {
47484     return sets(params, 'sortname', tag_sort_members);
47485 }
47486
47487
47488 function clean(params) {
47489     return lodash.omit(params, ['geometry', 'debounce']);
47490 }
47491
47492
47493 function filterKeys(type) {
47494     var count_type = type ? 'count_' + type : 'count_all';
47495     return function(d) {
47496         return parseFloat(d[count_type]) > 2500 || d.in_wiki;
47497     };
47498 }
47499
47500
47501 function filterMultikeys(prefix) {
47502     return function(d) {
47503         // d.key begins with prefix, and d.key contains no additional ':'s
47504         var re = new RegExp('^' + prefix + '(.*)$');
47505         var matches = d.key.match(re) || [];
47506         return (matches.length === 2 && matches[1].indexOf(':') === -1);
47507     };
47508 }
47509
47510
47511 function filterValues(allowUpperCase) {
47512     return function(d) {
47513         if (d.value.match(/[;,]/) !== null) return false;  // exclude some punctuation
47514         if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null) return false;  // exclude uppercase letters
47515         return parseFloat(d.fraction) > 0.0 || d.in_wiki;
47516     };
47517 }
47518
47519
47520 function filterRoles(geometry) {
47521     return function(d) {
47522         if (d.role === '') return false; // exclude empty role
47523         if (d.role.match(/[A-Z*;,]/) !== null) return false;  // exclude uppercase letters and some punctuation
47524         return parseFloat(d[tag_members_fractions[geometry]]) > 0.0;
47525     };
47526 }
47527
47528
47529 function valKey(d) {
47530     return {
47531         value: d.key,
47532         title: d.key
47533     };
47534 }
47535
47536
47537 function valKeyDescription(d) {
47538     return {
47539         value: d.value,
47540         title: d.description || d.value
47541     };
47542 }
47543
47544
47545 function roleKey(d) {
47546     return {
47547         value: d.role,
47548         title: d.role
47549     };
47550 }
47551
47552
47553 // sort keys with ':' lower than keys without ':'
47554 function sortKeys(a, b) {
47555     return (a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1) ? -1
47556         : (a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1) ? 1
47557         : 0;
47558 }
47559
47560
47561 var debouncedRequest = lodash.debounce(request$1, 500, { leading: false });
47562
47563 function request$1(url, params, exactMatch, callback, loaded) {
47564     if (inflight$2[url]) return;
47565
47566     if (checkCache(url, params, exactMatch, callback)) return;
47567
47568     inflight$2[url] = json(url, function (err, data) {
47569         delete inflight$2[url];
47570         loaded(err, data);
47571     });
47572 }
47573
47574
47575 function checkCache(url, params, exactMatch, callback) {
47576     var rp = params.rp || 25,
47577         testQuery = params.query || '',
47578         testUrl = url;
47579
47580     do {
47581         var hit = taginfoCache[testUrl];
47582
47583         // exact match, or shorter match yielding fewer than max results (rp)
47584         if (hit && (url === testUrl || hit.length < rp)) {
47585             callback(null, hit);
47586             return true;
47587         }
47588
47589         // don't try to shorten the query
47590         if (exactMatch || !testQuery.length) return false;
47591
47592         // do shorten the query to see if we already have a cached result
47593         // that has returned fewer than max results (rp)
47594         testQuery = testQuery.slice(0, -1);
47595         testUrl = url.replace(/&query=(.*?)&/, '&query=' + testQuery + '&');
47596     } while (testQuery.length >= 0);
47597
47598     return false;
47599 }
47600
47601
47602 var serviceTaginfo = {
47603
47604     init: function() {
47605         inflight$2 = {};
47606         taginfoCache = {};
47607         popularKeys = {};
47608
47609         // Fetch popular keys.  We'll exclude these from `values`
47610         // lookups because they stress taginfo, and they aren't likely
47611         // to yield meaningful autocomplete results.. see #3955
47612         var params = { rp: 100, sortname: 'values_all', sortorder: 'desc', page: 1, debounce: false };
47613         this.keys(params, function(err, data) {
47614             if (err) return;
47615             data.forEach(function(d) {
47616                 if (d.value === 'opening_hours') return;  // exception
47617                 popularKeys[d.value] = true;
47618             });
47619         });
47620     },
47621
47622
47623     reset: function() {
47624         lodash.forEach(inflight$2, function(req) { req.abort(); });
47625         inflight$2 = {};
47626     },
47627
47628
47629     keys: function(params, callback) {
47630         var doRequest = params.debounce ? debouncedRequest : request$1;
47631         params = clean(setSort(params));
47632         params = lodash.extend({ rp: 10, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
47633
47634         var url = apibase$2 + 'keys/all?' + utilQsString(params);
47635         doRequest(url, params, false, callback, function(err, d) {
47636             if (err) {
47637                 callback(err);
47638             } else {
47639                 var f = filterKeys(params.filter);
47640                 var result = d.data.filter(f).sort(sortKeys).map(valKey);
47641                 taginfoCache[url] = result;
47642                 callback(null, result);
47643             }
47644         });
47645     },
47646
47647
47648     multikeys: function(params, callback) {
47649         var doRequest = params.debounce ? debouncedRequest : request$1;
47650         params = clean(setSort(params));
47651         params = lodash.extend({ rp: 25, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
47652         var prefix = params.query;
47653
47654         var url = apibase$2 + 'keys/all?' + utilQsString(params);
47655         doRequest(url, params, true, callback, function(err, d) {
47656             if (err) {
47657                 callback(err);
47658             } else {
47659                 var f = filterMultikeys(prefix);
47660                 var result = d.data.filter(f).map(valKey);
47661                 taginfoCache[url] = result;
47662                 callback(null, result);
47663             }
47664         });
47665     },
47666
47667
47668     values: function(params, callback) {
47669         // Exclude popular keys from values lookups.. see #3955
47670         var key = params.key;
47671         if (key && popularKeys[key]) {
47672             callback(null, []);
47673             return;
47674         }
47675
47676         var doRequest = params.debounce ? debouncedRequest : request$1;
47677         params = clean(setSort(setFilter(params)));
47678         params = lodash.extend({ rp: 25, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
47679
47680         var url = apibase$2 + 'key/values?' + utilQsString(params);
47681         doRequest(url, params, false, callback, function(err, d) {
47682             if (err) {
47683                 callback(err);
47684             } else {
47685                 // In most cases we prefer taginfo value results with lowercase letters.
47686                 // A few OSM keys expect values to contain uppercase values (see #3377).
47687                 // This is not an exhaustive list (e.g. `name` also has uppercase values)
47688                 // but these are the fields where taginfo value lookup is most useful.
47689                 var re = /network|taxon|genus|species|brand|grape_variety|_hours|_times/;
47690                 var allowUpperCase = (params.key.match(re) !== null);
47691                 var f = filterValues(allowUpperCase);
47692
47693                 var result = d.data.filter(f).map(valKeyDescription);
47694                 taginfoCache[url] = result;
47695                 callback(null, result);
47696             }
47697         });
47698     },
47699
47700
47701     roles: function(params, callback) {
47702         var doRequest = params.debounce ? debouncedRequest : request$1;
47703         var geometry = params.geometry;
47704         params = clean(setSortMembers(params));
47705         params = lodash.extend({ rp: 25, sortname: 'count_all_members', sortorder: 'desc', page: 1 }, params);
47706
47707         var url = apibase$2 + 'relation/roles?' + utilQsString(params);
47708         doRequest(url, params, true, callback, function(err, d) {
47709             if (err) {
47710                 callback(err);
47711             } else {
47712                 var f = filterRoles(geometry);
47713                 var result = d.data.filter(f).map(roleKey);
47714                 taginfoCache[url] = result;
47715                 callback(null, result);
47716             }
47717         });
47718     },
47719
47720
47721     docs: function(params, callback) {
47722         var doRequest = params.debounce ? debouncedRequest : request$1;
47723         params = clean(setSort(params));
47724
47725         var path$$1 = 'key/wiki_pages?';
47726         if (params.value) path$$1 = 'tag/wiki_pages?';
47727         else if (params.rtype) path$$1 = 'relation/wiki_pages?';
47728
47729         var url = apibase$2 + path$$1 + utilQsString(params);
47730         doRequest(url, params, true, callback, function(err, d) {
47731             if (err) {
47732                 callback(err);
47733             } else {
47734                 taginfoCache[url] = d.data;
47735                 callback(null, d.data);
47736             }
47737         });
47738     },
47739
47740
47741     apibase: function(_) {
47742         if (!arguments.length) return apibase$2;
47743         apibase$2 = _;
47744         return this;
47745     }
47746
47747 };
47748
47749 var jsonpCache = {};
47750 window.jsonpCache = jsonpCache;
47751
47752 function jsonpRequest(url, callback) {
47753
47754   if (window.JSONP_FIX) {
47755     if (window.JSONP_DELAY === 0) {
47756       callback(window.JSONP_FIX);
47757     } else {
47758       setTimeout(function() {
47759         callback(window.JSONP_FIX);
47760       }, window.JSONP_DELAY || 0);
47761     }
47762     return;
47763   }
47764
47765   function rand() {
47766     var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
47767       c = '', i = -1;
47768     while (++i < 15) c += chars.charAt(Math.floor(Math.random() * 52));
47769     return c;
47770   }
47771
47772   function create(url) {
47773     var e = url.match(/callback=(\w+)/),
47774       c = e ? e[1] : rand();
47775     jsonpCache[c] = function(data) {
47776       callback(data);
47777       delete jsonpCache[c];
47778       script.remove();
47779     };
47780     return 'jsonpCache.' + c;
47781   }
47782
47783   var cb = create(url),
47784     script = select('head')
47785     .append('script')
47786     .attr('type', 'text/javascript')
47787     .attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
47788 }
47789
47790 var endpoint = 'https://www.wikidata.org/w/api.php?';
47791
47792 var serviceWikidata = {
47793
47794     init: function() {},
47795     reset: function() {},
47796
47797
47798     // Given a Wikipedia language and article title, return an array of
47799     // corresponding Wikidata entities.
47800     itemsByTitle: function(lang, title, callback) {
47801         if (!title) {
47802             callback('', {});
47803             return;
47804         }
47805
47806         lang = lang || 'en';
47807         jsonpRequest(endpoint + utilQsString({
47808             action: 'wbgetentities',
47809             format: 'json',
47810             sites: lang.replace(/-/g, '_') + 'wiki',
47811             titles: title,
47812             languages: 'en', // shrink response by filtering to one language
47813             callback: '{callback}'
47814         }), function(data) {
47815             if (!data || data.error) {
47816                 callback('', {});
47817             } else {
47818                 callback(title, data.entities || {});
47819             }
47820         });
47821     }
47822
47823 };
47824
47825 var endpoint$1 = 'https://en.wikipedia.org/w/api.php?';
47826
47827 var serviceWikipedia = {
47828
47829     init: function() {},
47830     reset: function() {},
47831
47832
47833     search: function(lang, query, callback) {
47834         if (!query) {
47835             callback('', []);
47836             return;
47837         }
47838
47839         lang = lang || 'en';
47840         jsonpRequest(endpoint$1.replace('en', lang) +
47841             utilQsString({
47842                 action: 'query',
47843                 list: 'search',
47844                 srlimit: '10',
47845                 srinfo: 'suggestion',
47846                 format: 'json',
47847                 callback: '{callback}',
47848                 srsearch: query
47849             }), function(data) {
47850                 if (!data || !data.query || !data.query.search || data.error) {
47851                     callback('', []);
47852                 } else {
47853                     var results = data.query.search.map(function(d) { return d.title; });
47854                     callback(query, results);
47855                 }
47856             }
47857         );
47858     },
47859
47860
47861     suggestions: function(lang, query, callback) {
47862         if (!query) {
47863             callback('', []);
47864             return;
47865         }
47866
47867         lang = lang || 'en';
47868         jsonpRequest(endpoint$1.replace('en', lang) +
47869             utilQsString({
47870                 action: 'opensearch',
47871                 namespace: 0,
47872                 suggest: '',
47873                 format: 'json',
47874                 callback: '{callback}',
47875                 search: query
47876             }), function(data) {
47877                 if (!data || data.error) {
47878                     callback('', []);
47879                 } else {
47880                     callback(data[0], data[1] || []);
47881                 }
47882             }
47883         );
47884     },
47885
47886
47887     translations: function(lang, title, callback) {
47888         if (!title) {
47889             callback({});
47890             return;
47891         }
47892
47893         jsonpRequest(endpoint$1.replace('en', lang) +
47894             utilQsString({
47895                 action: 'query',
47896                 prop: 'langlinks',
47897                 format: 'json',
47898                 callback: '{callback}',
47899                 lllimit: 500,
47900                 titles: title
47901             }), function(data) {
47902                 if (!data || !data.query || !data.query.pages || data.error) {
47903                     callback({});
47904                 } else {
47905                     var list = data.query.pages[Object.keys(data.query.pages)[0]],
47906                         translations = {};
47907                     if (list && list.langlinks) {
47908                         list.langlinks.forEach(function(d) {
47909                             translations[d.lang] = d['*'];
47910                         });
47911                     }
47912                     callback(translations);
47913                 }
47914             }
47915         );
47916     }
47917
47918 };
47919
47920 var services = {
47921     mapillary: serviceMapillary,
47922     geocoder: serviceNominatim,
47923     osm: serviceOsm,
47924     taginfo: serviceTaginfo,
47925     wikidata: serviceWikidata,
47926     wikipedia: serviceWikipedia
47927 };
47928
47929 function svgMapillaryImages(projection, context, dispatch$$1) {
47930     var throttledRedraw = lodash.throttle(function () { dispatch$$1.call('change'); }, 1000),
47931         minZoom = 12,
47932         minViewfieldZoom = 17,
47933         layer = select(null),
47934         _mapillary;
47935
47936
47937     function init() {
47938         if (svgMapillaryImages.initialized) return;  // run once
47939         svgMapillaryImages.enabled = false;
47940         svgMapillaryImages.initialized = true;
47941     }
47942
47943
47944     function getMapillary() {
47945         if (services.mapillary && !_mapillary) {
47946             _mapillary = services.mapillary;
47947             _mapillary.event.on('loadedImages', throttledRedraw);
47948         } else if (!services.mapillary && _mapillary) {
47949             _mapillary = null;
47950         }
47951
47952         return _mapillary;
47953     }
47954
47955
47956     function showLayer() {
47957         var mapillary = getMapillary();
47958         if (!mapillary) return;
47959
47960         mapillary.loadViewer(context);
47961         editOn();
47962
47963         layer
47964             .style('opacity', 0)
47965             .transition()
47966             .duration(500)
47967             .style('opacity', 1)
47968             .on('end', function () { dispatch$$1.call('change'); });
47969     }
47970
47971
47972     function hideLayer() {
47973         var mapillary = getMapillary();
47974         if (mapillary) {
47975             mapillary.hideViewer();
47976         }
47977
47978         throttledRedraw.cancel();
47979
47980         layer
47981             .transition()
47982             .duration(500)
47983             .style('opacity', 0)
47984             .on('end', editOff);
47985     }
47986
47987
47988     function editOn() {
47989         layer.style('display', 'block');
47990     }
47991
47992
47993     function editOff() {
47994         layer.selectAll('.viewfield-group').remove();
47995         layer.style('display', 'none');
47996     }
47997
47998
47999     function click(d) {
48000         var mapillary = getMapillary();
48001         if (!mapillary) return;
48002
48003         context.map().centerEase(d.loc);
48004
48005         mapillary
48006             .selectedImage(d.key, true)
48007             .updateViewer(d.key, context)
48008             .showViewer();
48009     }
48010
48011
48012     function transform(d) {
48013         var t = svgPointTransform(projection)(d);
48014         if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
48015         return t;
48016     }
48017
48018
48019     function update() {
48020         var mapillary = getMapillary(),
48021             data = (mapillary ? mapillary.images(projection) : []),
48022             imageKey = mapillary ? mapillary.selectedImage() : null;
48023
48024         var markers = layer.selectAll('.viewfield-group')
48025             .data(data, function(d) { return d.key; });
48026
48027         markers.exit()
48028             .remove();
48029
48030         var enter = markers.enter()
48031             .append('g')
48032             .attr('class', 'viewfield-group')
48033             .classed('selected', function(d) { return d.key === imageKey; })
48034             .on('click', click);
48035
48036         markers = markers
48037             .merge(enter)
48038             .attr('transform', transform);
48039
48040
48041        var viewfields = markers.selectAll('.viewfield')
48042             .data(~~context.map().zoom() >= minViewfieldZoom ? [0] : []);
48043
48044         viewfields.exit()
48045             .remove();
48046
48047         viewfields.enter()
48048             .append('path')
48049             .attr('class', 'viewfield')
48050             .attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
48051             .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');
48052
48053         markers.selectAll('circle')
48054             .data([0])
48055             .enter()
48056             .append('circle')
48057             .attr('dx', '0')
48058             .attr('dy', '0')
48059             .attr('r', '6');
48060     }
48061
48062
48063     function drawImages(selection$$1) {
48064         var enabled = svgMapillaryImages.enabled,
48065             mapillary = getMapillary();
48066
48067         layer = selection$$1.selectAll('.layer-mapillary-images')
48068             .data(mapillary ? [0] : []);
48069
48070         layer.exit()
48071             .remove();
48072
48073         layer = layer.enter()
48074             .append('g')
48075             .attr('class', 'layer-mapillary-images')
48076             .style('display', enabled ? 'block' : 'none')
48077             .merge(layer);
48078
48079         if (enabled) {
48080             if (mapillary && ~~context.map().zoom() >= minZoom) {
48081                 editOn();
48082                 update();
48083                 mapillary.loadImages(projection);
48084             } else {
48085                 editOff();
48086             }
48087         }
48088     }
48089
48090
48091     drawImages.enabled = function(_) {
48092         if (!arguments.length) return svgMapillaryImages.enabled;
48093         svgMapillaryImages.enabled = _;
48094         if (svgMapillaryImages.enabled) {
48095             showLayer();
48096         } else {
48097             hideLayer();
48098         }
48099         dispatch$$1.call('change');
48100         return this;
48101     };
48102
48103
48104     drawImages.supported = function() {
48105         return !!getMapillary();
48106     };
48107
48108
48109     init();
48110     return drawImages;
48111 }
48112
48113 function svgMapillarySigns(projection, context, dispatch$$1) {
48114     var throttledRedraw = lodash.throttle(function () { dispatch$$1.call('change'); }, 1000),
48115         minZoom = 12,
48116         layer = select(null),
48117         _mapillary;
48118
48119
48120     function init() {
48121         if (svgMapillarySigns.initialized) return;  // run once
48122         svgMapillarySigns.enabled = false;
48123         svgMapillarySigns.initialized = true;
48124     }
48125
48126
48127     function getMapillary() {
48128         if (services.mapillary && !_mapillary) {
48129             _mapillary = services.mapillary;
48130             _mapillary.event.on('loadedSigns', throttledRedraw);
48131         } else if (!services.mapillary && _mapillary) {
48132             _mapillary = null;
48133         }
48134         return _mapillary;
48135     }
48136
48137
48138     function showLayer() {
48139         editOn();
48140     }
48141
48142
48143     function hideLayer() {
48144         throttledRedraw.cancel();
48145         editOff();
48146     }
48147
48148
48149     function editOn() {
48150         layer.style('display', 'block');
48151     }
48152
48153
48154     function editOff() {
48155         layer.selectAll('.icon-sign').remove();
48156         layer.style('display', 'none');
48157     }
48158
48159
48160     function click(d) {
48161         var mapillary = getMapillary();
48162         if (!mapillary) return;
48163
48164         context.map().centerEase(d.loc);
48165
48166         mapillary
48167             .selectedImage(d.key, true)
48168             .updateViewer(d.key, context)
48169             .showViewer();
48170     }
48171
48172
48173     function update() {
48174         var mapillary = getMapillary(),
48175             data = (mapillary ? mapillary.signs(projection) : []),
48176             imageKey = mapillary ? mapillary.selectedImage() : null;
48177
48178         var signs = layer.selectAll('.icon-sign')
48179             .data(data, function(d) { return d.key; });
48180
48181         signs.exit()
48182             .remove();
48183
48184         var enter = signs.enter()
48185             .append('foreignObject')
48186             .attr('class', 'icon-sign')
48187             .attr('width', '32px')      // for Firefox
48188             .attr('height', '32px')     // for Firefox
48189             .classed('selected', function(d) { return d.key === imageKey; })
48190             .on('click', click);
48191
48192         enter
48193             .append('xhtml:body')
48194             .attr('class', 'icon-sign-body')
48195             .html(mapillary.signHTML);
48196
48197         signs
48198             .merge(enter)
48199             .attr('x', function(d) { return projection(d.loc)[0] - 16; })   // offset by -16px to
48200             .attr('y', function(d) { return projection(d.loc)[1] - 16; });  // center signs on loc
48201     }
48202
48203
48204     function drawSigns(selection$$1) {
48205         var enabled = svgMapillarySigns.enabled,
48206             mapillary = getMapillary();
48207
48208         layer = selection$$1.selectAll('.layer-mapillary-signs')
48209             .data(mapillary ? [0] : []);
48210
48211         layer.exit()
48212             .remove();
48213
48214         layer = layer.enter()
48215             .append('g')
48216             .attr('class', 'layer-mapillary-signs')
48217             .style('display', enabled ? 'block' : 'none')
48218             .merge(layer);
48219
48220         if (enabled) {
48221             if (mapillary && ~~context.map().zoom() >= minZoom) {
48222                 editOn();
48223                 update();
48224                 mapillary.loadSigns(context, projection);
48225             } else {
48226                 editOff();
48227             }
48228         }
48229     }
48230
48231
48232     drawSigns.enabled = function(_) {
48233         if (!arguments.length) return svgMapillarySigns.enabled;
48234         svgMapillarySigns.enabled = _;
48235         if (svgMapillarySigns.enabled) {
48236             showLayer();
48237         } else {
48238             hideLayer();
48239         }
48240         dispatch$$1.call('change');
48241         return this;
48242     };
48243
48244
48245     drawSigns.supported = function() {
48246         var mapillary = getMapillary();
48247         return (mapillary && mapillary.signsSupported());
48248     };
48249
48250
48251     init();
48252     return drawSigns;
48253 }
48254
48255 function svgOsm() {
48256     return function drawOsm(selection) {
48257         var layers = selection.selectAll('.layer-osm')
48258             .data(['areas', 'lines', 'hit', 'halo', 'label']);
48259
48260         layers.enter()
48261             .append('g')
48262             .attr('class', function(d) { return 'layer-osm layer-' + d; });
48263     };
48264 }
48265
48266 function svgLayers(projection, context) {
48267     var dispatch$$1 = dispatch('change'),
48268         svg = select(null),
48269         layers = [
48270             { id: 'osm', layer: svgOsm(projection, context, dispatch$$1) },
48271             { id: 'gpx', layer: svgGpx(projection, context, dispatch$$1) },
48272             { id: 'mapillary-images', layer: svgMapillaryImages(projection, context, dispatch$$1) },
48273             { id: 'mapillary-signs',  layer: svgMapillarySigns(projection, context, dispatch$$1) },
48274             { id: 'debug', layer: svgDebug(projection, context, dispatch$$1) }
48275         ];
48276
48277
48278     function drawLayers(selection$$1) {
48279         svg = selection$$1.selectAll('.surface')
48280             .data([0]);
48281
48282         svg = svg.enter()
48283             .append('svg')
48284             .attr('class', 'surface')
48285             .merge(svg);
48286
48287         var defs = svg.selectAll('.surface-defs')
48288             .data([0]);
48289
48290         defs.enter()
48291             .append('defs')
48292             .attr('class', 'surface-defs');
48293
48294         var groups = svg.selectAll('.data-layer')
48295             .data(layers);
48296
48297         groups.exit()
48298             .remove();
48299
48300         groups.enter()
48301             .append('g')
48302             .attr('class', function(d) { return 'data-layer data-layer-' + d.id; })
48303             .merge(groups)
48304             .each(function(d) { select(this).call(d.layer); });
48305     }
48306
48307
48308     drawLayers.all = function() {
48309         return layers;
48310     };
48311
48312
48313     drawLayers.layer = function(id) {
48314         var obj = lodash.find(layers, function(o) {return o.id === id;});
48315         return obj && obj.layer;
48316     };
48317
48318
48319     drawLayers.only = function(what) {
48320         var arr = [].concat(what);
48321         drawLayers.remove(lodash.difference(lodash.map(layers, 'id'), arr));
48322         return this;
48323     };
48324
48325
48326     drawLayers.remove = function(what) {
48327         var arr = [].concat(what);
48328         arr.forEach(function(id) {
48329             layers = lodash.reject(layers, function(o) {return o.id === id;});
48330         });
48331         dispatch$$1.call('change');
48332         return this;
48333     };
48334
48335
48336     drawLayers.add = function(what) {
48337         var arr = [].concat(what);
48338         arr.forEach(function(obj) {
48339             if ('id' in obj && 'layer' in obj) {
48340                 layers.push(obj);
48341             }
48342         });
48343         dispatch$$1.call('change');
48344         return this;
48345     };
48346
48347
48348     drawLayers.dimensions = function(_) {
48349         if (!arguments.length) return utilGetDimensions(svg);
48350         utilSetDimensions(svg, _);
48351         return this;
48352     };
48353
48354
48355     return utilRebind(drawLayers, dispatch$$1, 'on');
48356 }
48357
48358 function svgLines$$1(projection, context) {
48359     var detected = utilDetect();
48360
48361     var highway_stack = {
48362         motorway: 0,
48363         motorway_link: 1,
48364         trunk: 2,
48365         trunk_link: 3,
48366         primary: 4,
48367         primary_link: 5,
48368         secondary: 6,
48369         tertiary: 7,
48370         unclassified: 8,
48371         residential: 9,
48372         service: 10,
48373         footway: 11
48374     };
48375
48376
48377     function drawLines(selection$$1, graph, entities, filter) {
48378
48379
48380         function waystack(a, b) {
48381             var selected = context.selectedIDs(),
48382                 scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0,
48383                 scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
48384
48385             if (a.tags.highway) { scoreA -= highway_stack[a.tags.highway]; }
48386             if (b.tags.highway) { scoreB -= highway_stack[b.tags.highway]; }
48387             return scoreA - scoreB;
48388         }
48389
48390
48391         function drawLineGroup(selection$$1, klass, isSelected) {
48392             var lines = selection$$1
48393                 .selectAll('path')
48394                 .filter(filter)
48395                 .data(getPathData(isSelected), osmEntity$$1.key);
48396
48397             lines.exit()
48398                 .remove();
48399
48400             // Optimization: call simple TagClasses only on enter selection. This
48401             // works because osmEntity.key is defined to include the entity v attribute.
48402             lines.enter()
48403                 .append('path')
48404                 .attr('class', function(d) {
48405                     return 'way line ' + klass + ' ' + d.id + (isSelected ? ' selected' : '') +
48406                         (oldMultiPolygonOuters[d.id] ? ' old-multipolygon' : '');
48407                 })
48408                 .call(svgTagClasses())
48409                 .merge(lines)
48410                 .sort(waystack)
48411                 .attr('d', getPath)
48412                 .call(svgTagClasses().tags(svgRelationMemberTags(graph)));
48413
48414             return selection$$1;
48415         }
48416
48417
48418         function getPathData(isSelected) {
48419             return function() {
48420                 var layer = this.parentNode.__data__;
48421                 var data = pathdata[layer] || [];
48422                 return data.filter(function(d) {
48423                     if (isSelected)
48424                         return context.selectedIDs().indexOf(d.id) !== -1;
48425                     else
48426                         return context.selectedIDs().indexOf(d.id) === -1;
48427                 });
48428             };
48429         }
48430
48431
48432         var getPath = svgPath(projection, graph),
48433             ways = [],
48434             pathdata = {},
48435             onewaydata = {},
48436             oldMultiPolygonOuters = {};
48437
48438         for (var i = 0; i < entities.length; i++) {
48439             var entity = entities[i],
48440                 outer = osmSimpleMultipolygonOuterMember(entity, graph);
48441             if (outer) {
48442                 ways.push(entity.mergeTags(outer.tags));
48443                 oldMultiPolygonOuters[outer.id] = true;
48444             } else if (entity.geometry(graph) === 'line') {
48445                 ways.push(entity);
48446             }
48447         }
48448
48449         ways = ways.filter(getPath);
48450         pathdata = lodash.groupBy(ways, function(way) { return way.layer(); });
48451
48452         lodash.forOwn(pathdata, function(v, k) {
48453             onewaydata[k] = lodash(v)
48454                 .filter(function(d) { return d.isOneWay(); })
48455                 .map(svgOneWaySegments(projection, graph, 35))
48456                 .flatten()
48457                 .valueOf();
48458         });
48459
48460
48461         var layer = selection$$1.selectAll('.layer-lines');
48462
48463         var layergroup = layer
48464             .selectAll('g.layergroup')
48465             .data(sequence(-10, 11));
48466
48467         layergroup = layergroup.enter()
48468             .append('g')
48469             .attr('class', function(d) { return 'layergroup layer' + String(d); })
48470             .merge(layergroup);
48471
48472         layergroup
48473             .selectAll('g.linegroup')
48474             .data(['shadow', 'casing', 'stroke', 'shadow-highlighted', 'casing-highlighted', 'stroke-highlighted'])
48475             .enter()
48476             .append('g')
48477             .attr('class', function(d) { return 'linegroup line-' + d; });
48478
48479
48480         layergroup.selectAll('g.line-shadow')
48481             .call(drawLineGroup, 'shadow', false);
48482         layergroup.selectAll('g.line-casing')
48483             .call(drawLineGroup, 'casing', false);
48484         layergroup.selectAll('g.line-stroke')
48485             .call(drawLineGroup, 'stroke', false);
48486
48487         layergroup.selectAll('g.line-shadow-highlighted')
48488             .call(drawLineGroup, 'shadow', true);
48489         layergroup.selectAll('g.line-casing-highlighted')
48490             .call(drawLineGroup, 'casing', true);
48491         layergroup.selectAll('g.line-stroke-highlighted')
48492             .call(drawLineGroup, 'stroke', true);
48493
48494
48495         var onewaygroup = layergroup
48496             .selectAll('g.onewaygroup')
48497             .data(['oneway']);
48498
48499         onewaygroup = onewaygroup.enter()
48500             .append('g')
48501             .attr('class', 'onewaygroup')
48502             .merge(onewaygroup);
48503
48504         var oneways = onewaygroup
48505             .selectAll('path')
48506             .filter(filter)
48507             .data(
48508                 function() { return onewaydata[this.parentNode.__data__] || []; },
48509                 function(d) { return [d.id, d.index]; }
48510             );
48511
48512         oneways.exit()
48513             .remove();
48514
48515         oneways = oneways.enter()
48516             .append('path')
48517             .attr('class', 'oneway')
48518             .attr('marker-mid', 'url(#oneway-marker)')
48519             .merge(oneways)
48520             .attr('d', function(d) { return d.d; });
48521
48522         if (detected.ie) {
48523             oneways.each(function() { this.parentNode.insertBefore(this, this); });
48524         }
48525     }
48526
48527
48528     return drawLines;
48529 }
48530
48531 function svgMidpoints$$1(projection, context) {
48532
48533     return function drawMidpoints(selection, graph, entities, filter, extent) {
48534         var layer = selection.selectAll('.layer-hit');
48535
48536         var mode = context.mode();
48537         if (mode && mode.id !== 'select') {
48538             layer.selectAll('g.midpoint').remove();
48539             return;
48540         }
48541
48542         var poly = extent.polygon(),
48543             midpoints = {};
48544
48545         for (var i = 0; i < entities.length; i++) {
48546             var entity = entities[i];
48547
48548             if (entity.type !== 'way')
48549                 continue;
48550             if (!filter(entity))
48551                 continue;
48552             if (context.selectedIDs().indexOf(entity.id) < 0)
48553                 continue;
48554
48555             var nodes = graph.childNodes(entity);
48556             for (var j = 0; j < nodes.length - 1; j++) {
48557
48558                 var a = nodes[j],
48559                     b = nodes[j + 1],
48560                     id = [a.id, b.id].sort().join('-');
48561
48562                 if (midpoints[id]) {
48563                     midpoints[id].parents.push(entity);
48564                 } else {
48565                     if (geoEuclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
48566                         var point = geoInterp(a.loc, b.loc, 0.5),
48567                             loc = null;
48568
48569                         if (extent.intersects(point)) {
48570                             loc = point;
48571                         } else {
48572                             for (var k = 0; k < 4; k++) {
48573                                 point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
48574                                 if (point &&
48575                                     geoEuclideanDistance(projection(a.loc), projection(point)) > 20 &&
48576                                     geoEuclideanDistance(projection(b.loc), projection(point)) > 20)
48577                                 {
48578                                     loc = point;
48579                                     break;
48580                                 }
48581                             }
48582                         }
48583
48584                         if (loc) {
48585                             midpoints[id] = {
48586                                 type: 'midpoint',
48587                                 id: id,
48588                                 loc: loc,
48589                                 edge: [a.id, b.id],
48590                                 parents: [entity]
48591                             };
48592                         }
48593                     }
48594                 }
48595             }
48596         }
48597
48598
48599         function midpointFilter(d) {
48600             if (midpoints[d.id])
48601                 return true;
48602
48603             for (var i = 0; i < d.parents.length; i++) {
48604                 if (filter(d.parents[i])) {
48605                     return true;
48606                 }
48607             }
48608
48609             return false;
48610         }
48611
48612
48613         var groups = layer
48614             .selectAll('g.midpoint')
48615             .filter(midpointFilter)
48616             .data(lodash.values(midpoints), function(d) { return d.id; });
48617
48618         groups.exit()
48619             .remove();
48620
48621         var enter = groups.enter()
48622             .insert('g', ':first-child')
48623             .attr('class', 'midpoint');
48624
48625         enter.append('polygon')
48626             .attr('points', '-6,8 10,0 -6,-8')
48627             .attr('class', 'shadow');
48628
48629         enter.append('polygon')
48630             .attr('points', '-3,4 5,0 -3,-4')
48631             .attr('class', 'fill');
48632
48633         groups = groups
48634             .merge(enter)
48635             .attr('transform', function(d) {
48636                 var translate = svgPointTransform(projection),
48637                     a = graph.entity(d.edge[0]),
48638                     b = graph.entity(d.edge[1]),
48639                     angleVal = Math.round(geoAngle(a, b, projection) * (180 / Math.PI));
48640                 return translate(d) + ' rotate(' + angleVal + ')';
48641             })
48642             .call(svgTagClasses().tags(
48643                 function(d) { return d.parents[0].tags; }
48644             ));
48645
48646         // Propagate data bindings.
48647         groups.select('polygon.shadow');
48648         groups.select('polygon.fill');
48649
48650     };
48651 }
48652
48653 function svgOneWaySegments(projection, graph, dt) {
48654     return function(entity) {
48655         var a,
48656             b,
48657             i = 0,
48658             offset = dt,
48659             segments = [],
48660             clip = identity$5().clipExtent(projection.clipExtent()).stream,
48661             coordinates = graph.childNodes(entity).map(function(n) {
48662                 return n.loc;
48663             });
48664
48665         if (entity.tags.oneway === '-1') coordinates.reverse();
48666
48667         geoStream({
48668             type: 'LineString',
48669             coordinates: coordinates
48670         }, projection.stream(clip({
48671             lineStart: function() {},
48672             lineEnd: function() {
48673                 a = null;
48674             },
48675             point: function(x, y) {
48676                 b = [x, y];
48677
48678                 if (a) {
48679                     var span = geoEuclideanDistance(a, b) - offset;
48680
48681                     if (span >= 0) {
48682                         var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
48683                             dx = dt * Math.cos(angle),
48684                             dy = dt * Math.sin(angle),
48685                             p = [a[0] + offset * Math.cos(angle),
48686                                  a[1] + offset * Math.sin(angle)];
48687
48688                         var segment = 'M' + a[0] + ',' + a[1] +
48689                                       'L' + p[0] + ',' + p[1];
48690
48691                         for (span -= dt; span >= 0; span -= dt) {
48692                             p[0] += dx;
48693                             p[1] += dy;
48694                             segment += 'L' + p[0] + ',' + p[1];
48695                         }
48696
48697                         segment += 'L' + b[0] + ',' + b[1];
48698                         segments.push({id: entity.id, index: i, d: segment});
48699                     }
48700
48701                     offset = -span;
48702                     i++;
48703                 }
48704
48705                 a = b;
48706             }
48707         })));
48708
48709         return segments;
48710     };
48711 }
48712
48713 function svgPath(projection, graph, isArea) {
48714
48715     // Explanation of magic numbers:
48716     // "padding" here allows space for strokes to extend beyond the viewport,
48717     // so that the stroke isn't drawn along the edge of the viewport when
48718     // the shape is clipped.
48719     //
48720     // When drawing lines, pad viewport by 5px.
48721     // When drawing areas, pad viewport by 65px in each direction to allow
48722     // for 60px area fill stroke (see ".fill-partial path.fill" css rule)
48723
48724     var cache = {},
48725         padding = isArea ? 65 : 5,
48726         viewport = projection.clipExtent(),
48727         paddedExtent = [
48728             [viewport[0][0] - padding, viewport[0][1] - padding],
48729             [viewport[1][0] + padding, viewport[1][1] + padding]
48730         ],
48731         clip = identity$5().clipExtent(paddedExtent).stream,
48732         project = projection.stream,
48733         path$$1 = index$4()
48734             .projection({stream: function(output) { return project(clip(output)); }});
48735
48736     return function(entity) {
48737         if (entity.id in cache) {
48738             return cache[entity.id];
48739         } else {
48740             return cache[entity.id] = path$$1(entity.asGeoJSON(graph));
48741         }
48742     };
48743 }
48744
48745 function svgPoints$$1(projection, context) {
48746
48747     function markerPath(selection, klass) {
48748         selection
48749             .attr('class', klass)
48750             .attr('transform', 'translate(-8, -23)')
48751             .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');
48752     }
48753
48754     function sortY(a, b) {
48755         return b.loc[1] - a.loc[1];
48756     }
48757
48758
48759     return function drawPoints(selection, graph, entities, filter) {
48760         var wireframe = context.surface().classed('fill-wireframe'),
48761             points = wireframe ? [] : lodash.filter(entities, function(e) {
48762                 return e.geometry(graph) === 'point';
48763             });
48764
48765         points.sort(sortY);
48766
48767         var layer = selection.selectAll('.layer-hit');
48768
48769         var groups = layer.selectAll('g.point')
48770             .filter(filter)
48771             .data(points, osmEntity$$1.key);
48772
48773         groups.exit()
48774             .remove();
48775
48776         var enter = groups.enter()
48777             .append('g')
48778             .attr('class', function(d) { return 'node point ' + d.id; })
48779             .order();
48780
48781         enter.append('path')
48782             .call(markerPath, 'shadow');
48783
48784         enter.append('ellipse')
48785             .attr('cx', 0.5)
48786             .attr('cy', 1)
48787             .attr('rx', 6.5)
48788             .attr('ry', 3)
48789             .attr('class', 'stroke');
48790
48791         enter.append('path')
48792             .call(markerPath, 'stroke');
48793
48794         enter.append('use')
48795             .attr('transform', 'translate(-5, -19)')
48796             .attr('class', 'icon')
48797             .attr('width', '11px')
48798             .attr('height', '11px');
48799
48800         groups = groups
48801             .merge(enter)
48802             .attr('transform', svgPointTransform(projection))
48803             .call(svgTagClasses());
48804
48805         // Selecting the following implicitly
48806         // sets the data (point entity) on the element
48807         groups.select('.shadow');
48808         groups.select('.stroke');
48809         groups.select('.icon')
48810             .attr('xlink:href', function(entity) {
48811                 var preset = context.presets().match(entity, graph),
48812                     picon = preset && preset.icon;
48813
48814                 if (!picon)
48815                     return '';
48816                 else {
48817                     var isMaki = dataFeatureIcons.indexOf(picon) !== -1;
48818                     return '#' + picon + (isMaki ? '-11' : '');
48819                 }
48820             });
48821     };
48822 }
48823
48824 function svgRelationMemberTags(graph) {
48825     return function(entity) {
48826         var tags = entity.tags;
48827         graph.parentRelations(entity).forEach(function(relation) {
48828             var type = relation.tags.type;
48829             if (type === 'multipolygon' || type === 'boundary') {
48830                 tags = lodash.extend({}, relation.tags, tags);
48831             }
48832         });
48833         return tags;
48834     };
48835 }
48836
48837 function svgTagClasses() {
48838     var primaries = [
48839             'building', 'highway', 'railway', 'waterway', 'aeroway',
48840             'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
48841             'leisure', 'military', 'place'
48842         ],
48843         statuses = [
48844             'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
48845             'razed', 'demolished', 'obliterated'
48846         ],
48847         secondaries = [
48848             'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
48849             'surface', 'tracktype', 'crossing'
48850         ],
48851         tagClassRe = /^tag-/,
48852         tags = function(entity) { return entity.tags; };
48853
48854
48855     var tagClasses = function(selection$$1) {
48856         selection$$1.each(function tagClassesEach(entity) {
48857             var value = this.className,
48858                 classes, primary, status;
48859
48860             if (value.baseVal !== undefined) value = value.baseVal;
48861
48862             classes = value.trim().split(/\s+/).filter(function(name) {
48863                 return name.length && !tagClassRe.test(name);
48864             }).join(' ');
48865
48866             var t = tags(entity), i, k, v;
48867
48868             // pick at most one primary classification tag..
48869             for (i = 0; i < primaries.length; i++) {
48870                 k = primaries[i];
48871                 v = t[k];
48872                 if (!v || v === 'no') continue;
48873
48874                 primary = k;
48875                 if (statuses.indexOf(v) !== -1) {   // e.g. `railway=abandoned`
48876                     status = v;
48877                     classes += ' tag-' + k;
48878                 } else {
48879                     classes += ' tag-' + k + ' tag-' + k + '-' + v;
48880                 }
48881
48882                 break;
48883             }
48884
48885             // add at most one status tag, only if relates to primary tag..
48886             if (!status) {
48887                 for (i = 0; i < statuses.length; i++) {
48888                     k = statuses[i];
48889                     v = t[k];
48890                     if (!v || v === 'no') continue;
48891
48892                     if (v === 'yes') {   // e.g. `railway=rail + abandoned=yes`
48893                         status = k;
48894                     }
48895                     else if (primary && primary === v) {  // e.g. `railway=rail + abandoned=railway`
48896                         status = k;
48897                     } else if (!primary && primaries.indexOf(v) !== -1) {  // e.g. `abandoned=railway`
48898                         status = k;
48899                         primary = v;
48900                         classes += ' tag-' + v;
48901                     }  // else ignore e.g.  `highway=path + abandoned=railway`
48902
48903                     if (status) break;
48904                 }
48905             }
48906
48907             if (status) {
48908                 classes += ' tag-status tag-status-' + status;
48909             }
48910
48911             // add any secondary (structure) tags
48912             for (i = 0; i < secondaries.length; i++) {
48913                 k = secondaries[i];
48914                 v = t[k];
48915                 if (!v || v === 'no') continue;
48916                 classes += ' tag-' + k + ' tag-' + k + '-' + v;
48917             }
48918
48919             // For highways, look for surface tagging..
48920             if (primary === 'highway') {
48921                 var paved = (t.highway !== 'track');
48922                 for (k in t) {
48923                     v = t[k];
48924                     if (k in osmPavedTags) {
48925                         paved = !!osmPavedTags[k][v];
48926                         break;
48927                     }
48928                 }
48929                 if (!paved) {
48930                     classes += ' tag-unpaved';
48931                 }
48932             }
48933
48934             classes = classes.trim();
48935
48936             if (classes !== value) {
48937                 select(this).attr('class', classes);
48938             }
48939         });
48940     };
48941
48942
48943     tagClasses.tags = function(_) {
48944         if (!arguments.length) return tags;
48945         tags = _;
48946         return tagClasses;
48947     };
48948
48949     return tagClasses;
48950 }
48951
48952 function svgTurns(projection) {
48953
48954     return function drawTurns(selection, graph, turns) {
48955
48956         function key(turn) {
48957             return [turn.from.node + turn.via.node + turn.to.node].join('-');
48958         }
48959
48960         function icon(turn) {
48961             var u = turn.u ? '-u' : '';
48962             if (!turn.restriction)
48963                 return '#turn-yes' + u;
48964             var restriction = graph.entity(turn.restriction).tags.restriction;
48965             return '#turn-' +
48966                 (!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
48967         }
48968
48969         var groups = selection.selectAll('.layer-hit').selectAll('g.turn')
48970             .data(turns, key);
48971
48972         groups.exit()
48973             .remove();
48974
48975
48976         var enter = groups.enter()
48977             .append('g')
48978             .attr('class', 'turn');
48979
48980         var nEnter = enter
48981             .filter(function (turn) { return !turn.u; });
48982
48983         nEnter.append('rect')
48984             .attr('transform', 'translate(-22, -12)')
48985             .attr('width', '44')
48986             .attr('height', '24');
48987
48988         nEnter.append('use')
48989             .attr('transform', 'translate(-22, -12)')
48990             .attr('width', '44')
48991             .attr('height', '24');
48992
48993
48994         var uEnter = enter
48995             .filter(function (turn) { return turn.u; });
48996
48997         uEnter.append('circle')
48998             .attr('r', '16');
48999
49000         uEnter.append('use')
49001             .attr('transform', 'translate(-16, -16)')
49002             .attr('width', '32')
49003             .attr('height', '32');
49004
49005
49006         groups = groups
49007             .merge(enter);
49008
49009         groups
49010             .attr('transform', function (turn) {
49011                 var v = graph.entity(turn.via.node),
49012                     t = graph.entity(turn.to.node),
49013                     a = geoAngle(v, t, projection),
49014                     p = projection(v.loc),
49015                     r = turn.u ? 0 : 60;
49016
49017                 return 'translate(' + (r * Math.cos(a) + p[0]) + ',' + (r * Math.sin(a) + p[1]) + ') ' +
49018                     'rotate(' + a * 180 / Math.PI + ')';
49019             });
49020
49021         groups.select('use')
49022             .attr('xlink:href', icon);
49023
49024         groups.select('rect');
49025         groups.select('circle');
49026
49027         return this;
49028     };
49029 }
49030
49031 function svgVertices$$1(projection, context) {
49032     var radiuses = {
49033         //       z16-, z17, z18+, tagged
49034         shadow: [6,    7.5,   7.5,  11.5],
49035         stroke: [2.5,  3.5,   3.5,  7],
49036         fill:   [1,    1.5,   1.5,  1.5]
49037     };
49038
49039     var hover;
49040
49041
49042     function siblingAndChildVertices(ids, graph, extent$$1) {
49043         var vertices = {};
49044
49045         function addChildVertices(entity) {
49046             if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) {
49047                 var i;
49048                 if (entity.type === 'way') {
49049                     for (i = 0; i < entity.nodes.length; i++) {
49050                         addChildVertices(graph.entity(entity.nodes[i]));
49051                     }
49052                 } else if (entity.type === 'relation') {
49053                     for (i = 0; i < entity.members.length; i++) {
49054                         var member = context.hasEntity(entity.members[i].id);
49055                         if (member) {
49056                             addChildVertices(member);
49057                         }
49058                     }
49059                 } else if (entity.intersects(extent$$1, graph)) {
49060                     vertices[entity.id] = entity;
49061                 }
49062             }
49063         }
49064
49065         ids.forEach(function(id) {
49066             var entity = context.hasEntity(id);
49067             if (entity && entity.type === 'node') {
49068                 vertices[entity.id] = entity;
49069                 context.graph().parentWays(entity).forEach(function(entity) {
49070                     addChildVertices(entity);
49071                 });
49072             } else if (entity) {
49073                 addChildVertices(entity);
49074             }
49075         });
49076
49077         return vertices;
49078     }
49079
49080
49081     function draw(selection$$1, vertices, klass, graph, zoom$$1, siblings) {
49082
49083         function icon(entity) {
49084             if (entity.id in icons) return icons[entity.id];
49085             icons[entity.id] =
49086                 entity.hasInterestingTags() &&
49087                 context.presets().match(entity, graph).icon;
49088             return icons[entity.id];
49089         }
49090
49091         function setClass(klass) {
49092             return function(entity) {
49093                 this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
49094             };
49095         }
49096
49097         function setAttributes(selection$$1) {
49098             ['shadow','stroke','fill'].forEach(function(klass) {
49099                 var rads = radiuses[klass];
49100                 selection$$1.selectAll('.' + klass)
49101                     .each(function(entity) {
49102                         var i = z && icon(entity),
49103                             c = i ? 0.5 : 0,
49104                             r = rads[i ? 3 : z];
49105
49106                         // slightly increase the size of unconnected endpoints #3775
49107                         if (entity.isEndpoint(graph) && !entity.isConnected(graph)) {
49108                             r += 1.5;
49109                         }
49110
49111                         this.setAttribute('cx', c);
49112                         this.setAttribute('cy', -c);
49113                         this.setAttribute('r', r);
49114                         if (i && klass === 'fill') {
49115                             this.setAttribute('visibility', 'hidden');
49116                         } else {
49117                             this.removeAttribute('visibility');
49118                         }
49119                     });
49120             });
49121
49122             selection$$1.selectAll('use')
49123                 .each(function() {
49124                     if (z) {
49125                         this.removeAttribute('visibility');
49126                     } else {
49127                         this.setAttribute('visibility', 'hidden');
49128                     }
49129                 });
49130         }
49131
49132
49133         siblings = siblings || {};
49134
49135         var icons = {},
49136             z = (zoom$$1 < 17 ? 0 : zoom$$1 < 18 ? 1 : 2);
49137
49138         var groups = selection$$1
49139             .data(vertices, osmEntity$$1.key);
49140
49141         groups.exit()
49142             .remove();
49143
49144         var enter = groups.enter()
49145             .append('g')
49146             .attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });
49147
49148         enter.append('circle')
49149             .each(setClass('shadow'));
49150
49151         enter.append('circle')
49152             .each(setClass('stroke'));
49153
49154         // Vertices with icons get a `use`.
49155         enter.filter(function(d) { return icon(d); })
49156             .append('use')
49157             .attr('transform', 'translate(-5, -6)')
49158             .attr('xlink:href', function(d) {
49159                 var picon = icon(d),
49160                     isMaki = dataFeatureIcons.indexOf(picon) !== -1;
49161                 return '#' + picon + (isMaki ? '-11' : '');
49162             })
49163             .attr('width', '11px')
49164             .attr('height', '11px')
49165             .each(setClass('icon'));
49166
49167         // Vertices with tags get a fill.
49168         enter.filter(function(d) { return d.hasInterestingTags(); })
49169             .append('circle')
49170             .each(setClass('fill'));
49171
49172         groups
49173             .merge(enter)
49174             .attr('transform', svgPointTransform(projection))
49175             .classed('sibling', function(entity) { return entity.id in siblings; })
49176             .classed('shared', function(entity) { return graph.isShared(entity); })
49177             .classed('endpoint', function(entity) { return entity.isEndpoint(graph); })
49178             .call(setAttributes);
49179     }
49180
49181
49182     function drawVertices(selection$$1, graph, entities, filter, extent$$1, zoom$$1) {
49183         var siblings = siblingAndChildVertices(context.selectedIDs(), graph, extent$$1),
49184             wireframe = context.surface().classed('fill-wireframe'),
49185             vertices = [];
49186
49187         for (var i = 0; i < entities.length; i++) {
49188             var entity = entities[i],
49189                 geometry = entity.geometry(graph);
49190
49191             if (wireframe && geometry === 'point') {
49192                 vertices.push(entity);
49193                 continue;
49194             }
49195
49196             if (geometry !== 'vertex')
49197                 continue;
49198
49199             if (entity.id in siblings ||
49200                 entity.hasInterestingTags() ||
49201                 entity.isEndpoint(graph) ||
49202                 entity.isConnected(graph)) {
49203                 vertices.push(entity);
49204             }
49205         }
49206
49207         var layer = selection$$1.selectAll('.layer-hit');
49208         layer.selectAll('g.vertex.vertex-persistent')
49209             .filter(filter)
49210             .call(draw, vertices, 'vertex-persistent', graph, zoom$$1, siblings);
49211
49212         drawHover(selection$$1, graph, extent$$1, zoom$$1);
49213     }
49214
49215
49216     function drawHover(selection$$1, graph, extent$$1, zoom$$1) {
49217         var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent$$1) : {};
49218         var layer = selection$$1.selectAll('.layer-hit');
49219
49220         layer.selectAll('g.vertex.vertex-hover')
49221             .call(draw, values(hovered), 'vertex-hover', graph, zoom$$1);
49222     }
49223
49224
49225     drawVertices.drawHover = function(selection$$1, graph, target, extent$$1, zoom$$1) {
49226         if (target === hover) return;
49227         hover = target;
49228         drawHover(selection$$1, graph, extent$$1, zoom$$1);
49229     };
49230
49231     return drawVertices;
49232 }
49233
49234 function behaviorEdit(context) {
49235
49236     function edit() {
49237         context.map()
49238             .minzoom(context.minEditableZoom());
49239     }
49240
49241
49242     edit.off = function() {
49243         context.map()
49244             .minzoom(0);
49245     };
49246
49247
49248     return edit;
49249 }
49250
49251 /*
49252    The hover behavior adds the `.hover` class on mouseover to all elements to which
49253    the identical datum is bound, and removes it on mouseout.
49254
49255    The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
49256    representation may consist of several elements scattered throughout the DOM hierarchy.
49257    Only one of these elements can have the :hover pseudo-class, but all of them will
49258    have the .hover class.
49259  */
49260 function behaviorHover(context) {
49261     var dispatch$$1 = dispatch('hover'),
49262         _selection = select(null),
49263         newId = null,
49264         buttonDown,
49265         altDisables,
49266         target;
49267
49268
49269     function keydown() {
49270         if (altDisables && event.keyCode === d3keybinding.modifierCodes.alt) {
49271             _selection.selectAll('.hover')
49272                 .classed('hover-suppressed', true)
49273                 .classed('hover', false);
49274
49275             _selection
49276                 .classed('hover-disabled', true);
49277
49278             dispatch$$1.call('hover', this, null);
49279         }
49280     }
49281
49282
49283     function keyup() {
49284         if (altDisables && event.keyCode === d3keybinding.modifierCodes.alt) {
49285             _selection.selectAll('.hover-suppressed')
49286                 .classed('hover-suppressed', false)
49287                 .classed('hover', true);
49288
49289             _selection
49290                 .classed('hover-disabled', false);
49291
49292             dispatch$$1.call('hover', this, target ? target.id : null);
49293         }
49294     }
49295
49296
49297     var hover = function(selection$$1) {
49298         _selection = selection$$1;
49299         newId = null;
49300
49301         _selection
49302             .on('mouseover.hover', mouseover)
49303             .on('mouseout.hover', mouseout)
49304             .on('mousedown.hover', mousedown);
49305
49306         select(window)
49307             .on('keydown.hover', keydown)
49308             .on('keyup.hover', keyup);
49309
49310
49311         function mouseover() {
49312             if (buttonDown) return;
49313             var target = event.target;
49314             enter(target ? target.__data__ : null);
49315         }
49316
49317
49318         function mouseout() {
49319             if (buttonDown) return;
49320             var target = event.relatedTarget;
49321             enter(target ? target.__data__ : null);
49322         }
49323
49324
49325         function mousedown() {
49326             buttonDown = true;
49327             select(window)
49328                 .on('mouseup.hover', mouseup, true);
49329         }
49330
49331
49332         function mouseup() {
49333             buttonDown = false;
49334             select(window)
49335                 .on('mouseup.hover', null, true);
49336         }
49337
49338
49339         function enter(d) {
49340             if (d === target) return;
49341             target = d;
49342
49343             _selection.selectAll('.hover')
49344                 .classed('hover', false);
49345             _selection.selectAll('.hover-suppressed')
49346                 .classed('hover-suppressed', false);
49347
49348             if (target instanceof osmEntity$$1 && target.id !== newId) {
49349
49350                 // If drawing a way, don't hover on a node that was just placed. #3974
49351                 var mode = context.mode() && context.mode().id;
49352                 if ((mode === 'draw-line' || mode === 'draw-area') && !newId && target.type === 'node') {
49353                     newId = target.id;
49354                     return;
49355                 }
49356
49357                 var selector$$1 = '.' + target.id;
49358
49359                 if (target.type === 'relation') {
49360                     target.members.forEach(function(member) {
49361                         selector$$1 += ', .' + member.id;
49362                     });
49363                 }
49364
49365                 var suppressed = altDisables && event && event.altKey;
49366
49367                 _selection.selectAll(selector$$1)
49368                     .classed(suppressed ? 'hover-suppressed' : 'hover', true);
49369
49370                 dispatch$$1.call('hover', this, !suppressed && target.id);
49371
49372             } else {
49373                 dispatch$$1.call('hover', this, null);
49374             }
49375         }
49376
49377     };
49378
49379
49380     hover.off = function(selection$$1) {
49381         selection$$1.selectAll('.hover')
49382             .classed('hover', false);
49383         selection$$1.selectAll('.hover-suppressed')
49384             .classed('hover-suppressed', false);
49385         selection$$1
49386             .classed('hover-disabled', false);
49387
49388
49389         selection$$1
49390             .on('mouseover.hover', null)
49391             .on('mouseout.hover', null)
49392             .on('mousedown.hover', null);
49393
49394         select(window)
49395             .on('keydown.hover', null)
49396             .on('keyup.hover', null);
49397     };
49398
49399
49400     hover.altDisables = function(_) {
49401         if (!arguments.length) return altDisables;
49402         altDisables = _;
49403         return hover;
49404     };
49405
49406
49407     return utilRebind(hover, dispatch$$1, 'on');
49408 }
49409
49410 function behaviorTail() {
49411     var text$$1,
49412         container,
49413         xmargin = 25,
49414         tooltipSize = [0, 0],
49415         selectionSize = [0, 0];
49416
49417
49418     function tail(selection$$1) {
49419         if (!text$$1) return;
49420
49421         select(window)
49422             .on('resize.tail', function() { selectionSize = utilGetDimensions(selection$$1); });
49423
49424         container = select(document.body)
49425             .append('div')
49426             .style('display', 'none')
49427             .attr('class', 'tail tooltip-inner');
49428
49429         container.append('div')
49430             .text(text$$1);
49431
49432         selection$$1
49433             .on('mousemove.tail', mousemove)
49434             .on('mouseenter.tail', mouseenter)
49435             .on('mouseleave.tail', mouseleave);
49436
49437         container
49438             .on('mousemove.tail', mousemove);
49439
49440         tooltipSize = utilGetDimensions(container);
49441         selectionSize = utilGetDimensions(selection$$1);
49442
49443
49444         function show() {
49445             container.style('display', 'block');
49446             tooltipSize = utilGetDimensions(container);
49447         }
49448
49449
49450         function mousemove() {
49451             if (container.style('display') === 'none') show();
49452             var xoffset = ((event.clientX + tooltipSize[0] + xmargin) > selectionSize[0]) ?
49453                 -tooltipSize[0] - xmargin : xmargin;
49454             container.classed('left', xoffset > 0);
49455             utilSetTransform(container, event.clientX + xoffset, event.clientY);
49456         }
49457
49458
49459         function mouseleave() {
49460             if (event.relatedTarget !== container.node()) {
49461                 container.style('display', 'none');
49462             }
49463         }
49464
49465
49466         function mouseenter() {
49467             if (event.relatedTarget !== container.node()) {
49468                 show();
49469             }
49470         }
49471     }
49472
49473
49474     tail.off = function(selection$$1) {
49475         if (!text$$1) return;
49476
49477         container
49478             .on('mousemove.tail', null)
49479             .remove();
49480
49481         selection$$1
49482             .on('mousemove.tail', null)
49483             .on('mouseenter.tail', null)
49484             .on('mouseleave.tail', null);
49485
49486         select(window)
49487             .on('resize.tail', null);
49488     };
49489
49490
49491     tail.text = function(_) {
49492         if (!arguments.length) return text$$1;
49493         text$$1 = _;
49494         return tail;
49495     };
49496
49497
49498     return tail;
49499 }
49500
49501 var usedTails = {};
49502 var disableSpace = false;
49503 var lastSpace = null;
49504
49505
49506 function behaviorDraw(context) {
49507     var dispatch$$1 = dispatch('move', 'click', 'clickWay',
49508             'clickNode', 'undo', 'cancel', 'finish'),
49509         keybinding = d3keybinding('draw'),
49510         hover = behaviorHover(context)
49511             .altDisables(true)
49512             .on('hover', context.ui().sidebar.hover),
49513         tail = behaviorTail(),
49514         edit = behaviorEdit(context),
49515         closeTolerance = 4,
49516         tolerance = 12,
49517         mouseLeave = false,
49518         lastMouse = null;
49519
49520
49521     function datum() {
49522         if (event.altKey) return {};
49523
49524         if (event.type === 'keydown') {
49525             return (lastMouse && lastMouse.target.__data__) || {};
49526         } else {
49527             return event.target.__data__ || {};
49528         }
49529     }
49530
49531
49532     function mousedown() {
49533
49534         function point() {
49535             var p = context.container().node();
49536             return touchId !== null ? touches(p).filter(function(p) {
49537                 return p.identifier === touchId;
49538             })[0] : mouse(p);
49539         }
49540
49541         var element = select(this),
49542             touchId = event.touches ? event.changedTouches[0].identifier : null,
49543             t1 = +new Date(),
49544             p1 = point();
49545
49546         element.on('mousemove.draw', null);
49547
49548         select(window).on('mouseup.draw', function() {
49549             var t2 = +new Date(),
49550                 p2 = point(),
49551                 dist = geoEuclideanDistance(p1, p2);
49552
49553             element.on('mousemove.draw', mousemove);
49554             select(window).on('mouseup.draw', null);
49555
49556             if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) {
49557                 // Prevent a quick second click
49558                 select(window).on('click.draw-block', function() {
49559                     event.stopPropagation();
49560                 }, true);
49561
49562                 context.map().dblclickEnable(false);
49563
49564                 window.setTimeout(function() {
49565                     context.map().dblclickEnable(true);
49566                     select(window).on('click.draw-block', null);
49567                 }, 500);
49568
49569                 click();
49570             }
49571         }, true);
49572     }
49573
49574
49575     function mousemove() {
49576         lastMouse = event;
49577         dispatch$$1.call('move', this, datum());
49578     }
49579
49580
49581     function mouseenter() {
49582         mouseLeave = false;
49583     }
49584
49585
49586     function mouseleave() {
49587         mouseLeave = true;
49588     }
49589
49590
49591     function click() {
49592         var d = datum();
49593         if (d.type === 'way') {
49594             var dims = context.map().dimensions(),
49595                 mouse$$1 = context.mouse(),
49596                 pad = 5,
49597                 trySnap = mouse$$1[0] > pad && mouse$$1[0] < dims[0] - pad &&
49598                     mouse$$1[1] > pad && mouse$$1[1] < dims[1] - pad;
49599
49600             if (trySnap) {
49601                 var choice = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection),
49602                     edge = [d.nodes[choice.index - 1], d.nodes[choice.index]];
49603                 dispatch$$1.call('clickWay', this, choice.loc, edge);
49604             } else {
49605                 dispatch$$1.call('click', this, context.map().mouseCoordinates());
49606             }
49607
49608         } else if (d.type === 'node') {
49609             dispatch$$1.call('clickNode', this, d);
49610
49611         } else {
49612             dispatch$$1.call('click', this, context.map().mouseCoordinates());
49613         }
49614     }
49615
49616
49617     function space() {
49618         event.preventDefault();
49619         event.stopPropagation();
49620
49621         var currSpace = context.mouse();
49622         if (disableSpace && lastSpace) {
49623             var dist = geoEuclideanDistance(lastSpace, currSpace);
49624             if (dist > tolerance) {
49625                 disableSpace = false;
49626             }
49627         }
49628
49629         if (disableSpace || mouseLeave || !lastMouse) return;
49630
49631         // user must move mouse or release space bar to allow another click
49632         lastSpace = currSpace;
49633         disableSpace = true;
49634
49635         select(window).on('keyup.space-block', function() {
49636             event.preventDefault();
49637             event.stopPropagation();
49638             disableSpace = false;
49639             select(window).on('keyup.space-block', null);
49640         });
49641
49642         click();
49643     }
49644
49645
49646     function backspace() {
49647         event.preventDefault();
49648         dispatch$$1.call('undo');
49649     }
49650
49651
49652     function del() {
49653         event.preventDefault();
49654         dispatch$$1.call('cancel');
49655     }
49656
49657
49658     function ret() {
49659         event.preventDefault();
49660         dispatch$$1.call('finish');
49661     }
49662
49663
49664     function draw(selection$$1) {
49665         context.install(hover);
49666         context.install(edit);
49667
49668         if (!context.inIntro() && !usedTails[tail.text()]) {
49669             context.install(tail);
49670         }
49671
49672         keybinding
49673             .on('⌫', backspace)
49674             .on('⌦', del)
49675             .on('⎋', ret)
49676             .on('↩', ret)
49677             .on('space', space)
49678             .on('⌥space', space);
49679
49680         selection$$1
49681             .on('mouseenter.draw', mouseenter)
49682             .on('mouseleave.draw', mouseleave)
49683             .on('mousedown.draw', mousedown)
49684             .on('mousemove.draw', mousemove);
49685
49686         select(document)
49687             .call(keybinding);
49688
49689         return draw;
49690     }
49691
49692
49693     draw.off = function(selection$$1) {
49694         context.ui().sidebar.hover.cancel();
49695         context.uninstall(hover);
49696         context.uninstall(edit);
49697
49698         if (!context.inIntro() && !usedTails[tail.text()]) {
49699             context.uninstall(tail);
49700             usedTails[tail.text()] = true;
49701         }
49702
49703         selection$$1
49704             .on('mouseenter.draw', null)
49705             .on('mouseleave.draw', null)
49706             .on('mousedown.draw', null)
49707             .on('mousemove.draw', null);
49708
49709         select(window)
49710             .on('mouseup.draw', null);
49711             // note: keyup.space-block, click.draw-block should remain
49712
49713         select(document)
49714             .call(keybinding.off);
49715     };
49716
49717
49718     draw.tail = function(_) {
49719         tail.text(_);
49720         return draw;
49721     };
49722
49723
49724     return utilRebind(draw, dispatch$$1, 'on');
49725 }
49726
49727 function behaviorAddWay(context) {
49728     var dispatch$$1 = dispatch('start', 'startFromWay', 'startFromNode'),
49729         draw = behaviorDraw(context);
49730
49731     var addWay = function(surface) {
49732         draw.on('click', function() { dispatch$$1.apply('start', this, arguments); })
49733             .on('clickWay', function() { dispatch$$1.apply('startFromWay', this, arguments); })
49734             .on('clickNode', function() { dispatch$$1.apply('startFromNode', this, arguments); })
49735             .on('cancel', addWay.cancel)
49736             .on('finish', addWay.cancel);
49737
49738         context.map()
49739             .dblclickEnable(false);
49740
49741         surface.call(draw);
49742     };
49743
49744
49745     addWay.off = function(surface) {
49746         surface.call(draw.off);
49747     };
49748
49749
49750     addWay.cancel = function() {
49751         window.setTimeout(function() {
49752             context.map().dblclickEnable(true);
49753         }, 1000);
49754
49755         context.enter(modeBrowse(context));
49756     };
49757
49758
49759     addWay.tail = function(text$$1) {
49760         draw.tail(text$$1);
49761         return addWay;
49762     };
49763
49764
49765     return utilRebind(addWay, dispatch$$1, 'on');
49766 }
49767
49768 function behaviorBreathe() {
49769     var duration = 800,
49770         steps = 4,
49771         selector$$1 = '.selected.shadow, .selected .shadow',
49772         selected = select(null),
49773         classed = '',
49774         params = {},
49775         done = false,
49776         timer$$1;
49777
49778
49779     function ratchetyInterpolator(a, b, steps, units) {
49780         a = parseFloat(a);
49781         b = parseFloat(b);
49782         var sample = quantize$1()
49783             .domain([0, 1])
49784             .range(quantize(reinterpolate(a, b), steps));
49785
49786         return function(t) {
49787             return String(sample(t)) + (units || '');
49788         };
49789     }
49790
49791
49792     function reset(selection$$1) {
49793         selection$$1
49794             .style('stroke-opacity', null)
49795             .style('stroke-width', null)
49796             .style('fill-opacity', null)
49797             .style('r', null);
49798     }
49799
49800
49801     function setAnimationParams(transition$$1, fromTo) {
49802         var toFrom = (fromTo === 'from' ? 'to' : 'from');
49803
49804         transition$$1
49805             .styleTween('stroke-opacity', function(d) {
49806                 return ratchetyInterpolator(
49807                     params[d.id][toFrom].opacity,
49808                     params[d.id][fromTo].opacity,
49809                     steps
49810                 );
49811             })
49812             .styleTween('stroke-width', function(d) {
49813                 return ratchetyInterpolator(
49814                     params[d.id][toFrom].width,
49815                     params[d.id][fromTo].width,
49816                     steps,
49817                     'px'
49818                 );
49819             })
49820             .styleTween('fill-opacity', function(d) {
49821                 return ratchetyInterpolator(
49822                     params[d.id][toFrom].opacity,
49823                     params[d.id][fromTo].opacity,
49824                     steps
49825                 );
49826             })
49827             .styleTween('r', function(d) {
49828                 return ratchetyInterpolator(
49829                     params[d.id][toFrom].width,
49830                     params[d.id][fromTo].width,
49831                     steps,
49832                     'px'
49833                 );
49834             });
49835     }
49836
49837
49838     function calcAnimationParams(selection$$1) {
49839         selection$$1
49840             .call(reset)
49841             .each(function(d) {
49842                 var s = select(this),
49843                     tag = s.node().tagName,
49844                     p = {'from': {}, 'to': {}},
49845                     opacity, width;
49846
49847                 // determine base opacity and width
49848                 if (tag === 'circle') {
49849                     opacity = parseFloat(s.style('fill-opacity') || 0.5);
49850                     width = parseFloat(s.style('r') || 15.5);
49851                 } else {
49852                     opacity = parseFloat(s.style('stroke-opacity') || 0.7);
49853                     width = parseFloat(s.style('stroke-width') || 10);
49854                 }
49855
49856                 // calculate from/to interpolation params..
49857                 p.tag = tag;
49858                 p.from.opacity = opacity * 0.6;
49859                 p.to.opacity = opacity * 1.25;
49860                 p.from.width = width * 0.7;
49861                 p.to.width = width * (tag === 'circle' ? 1.5 : 1);
49862                 params[d.id] = p;
49863             });
49864     }
49865
49866
49867     function run(surface, fromTo) {
49868         var toFrom = (fromTo === 'from' ? 'to' : 'from'),
49869             currSelected = surface.selectAll(selector$$1),
49870             currClassed = surface.attr('class');
49871
49872         if (done || currSelected.empty()) {
49873             selected.call(reset);
49874             return;
49875         }
49876
49877         if (!lodash.isEqual(currSelected.data(), selected.data()) || currClassed !== classed) {
49878             selected.call(reset);
49879             classed = currClassed;
49880             selected = currSelected.call(calcAnimationParams);
49881         }
49882
49883         selected
49884             .transition()
49885             .duration(duration)
49886             .call(setAnimationParams, fromTo)
49887             .on('end', function() {
49888                 surface.call(run, toFrom);
49889             });
49890     }
49891
49892
49893     var breathe = function(surface) {
49894         done = false;
49895         timer$$1 = timer(function() {
49896             // wait for elements to actually become selected
49897             if (surface.selectAll(selector$$1).empty()) {
49898                 return false;
49899             }
49900
49901             surface.call(run, 'from');
49902             timer$$1.stop();
49903             return true;
49904         }, 20);
49905     };
49906
49907
49908     breathe.off = function() {
49909         done = true;
49910         if (timer$$1) {
49911             timer$$1.stop();
49912         }
49913         selected
49914             .interrupt()
49915             .call(reset);
49916     };
49917
49918
49919     return breathe;
49920 }
49921
49922 function behaviorCopy(context) {
49923     var keybinding = d3keybinding('copy');
49924
49925
49926     function groupEntities(ids, graph) {
49927         var entities = ids.map(function (id) { return graph.entity(id); });
49928         return lodash.extend({relation: [], way: [], node: []},
49929             lodash.groupBy(entities, function(entity) { return entity.type; }));
49930     }
49931
49932
49933     function getDescendants(id, graph, descendants) {
49934         var entity = graph.entity(id),
49935             i, children;
49936
49937         descendants = descendants || {};
49938
49939         if (entity.type === 'relation') {
49940             children = lodash.map(entity.members, 'id');
49941         } else if (entity.type === 'way') {
49942             children = entity.nodes;
49943         } else {
49944             children = [];
49945         }
49946
49947         for (i = 0; i < children.length; i++) {
49948             if (!descendants[children[i]]) {
49949                 descendants[children[i]] = true;
49950                 descendants = getDescendants(children[i], graph, descendants);
49951             }
49952         }
49953
49954         return descendants;
49955     }
49956
49957
49958     function doCopy() {
49959         event.preventDefault();
49960
49961         var graph = context.graph(),
49962             selected = groupEntities(context.selectedIDs(), graph),
49963             canCopy = [],
49964             skip = {},
49965             i, entity;
49966
49967         for (i = 0; i < selected.relation.length; i++) {
49968             entity = selected.relation[i];
49969             if (!skip[entity.id] && entity.isComplete(graph)) {
49970                 canCopy.push(entity.id);
49971                 skip = getDescendants(entity.id, graph, skip);
49972             }
49973         }
49974         for (i = 0; i < selected.way.length; i++) {
49975             entity = selected.way[i];
49976             if (!skip[entity.id]) {
49977                 canCopy.push(entity.id);
49978                 skip = getDescendants(entity.id, graph, skip);
49979             }
49980         }
49981         for (i = 0; i < selected.node.length; i++) {
49982             entity = selected.node[i];
49983             if (!skip[entity.id]) {
49984                 canCopy.push(entity.id);
49985             }
49986         }
49987
49988         context.copyIDs(canCopy);
49989     }
49990
49991
49992     function copy() {
49993         keybinding.on(uiCmd('⌘C'), doCopy);
49994         select(document).call(keybinding);
49995         return copy;
49996     }
49997
49998
49999     copy.off = function() {
50000         select(document).call(keybinding.off);
50001     };
50002
50003
50004     return copy;
50005 }
50006
50007 /*
50008     `behaviorDrag` is like `d3.behavior.drag`, with the following differences:
50009
50010     * The `origin` function is expected to return an [x, y] tuple rather than an
50011       {x, y} object.
50012     * The events are `start`, `move`, and `end`.
50013       (https://github.com/mbostock/d3/issues/563)
50014     * The `start` event is not dispatched until the first cursor movement occurs.
50015       (https://github.com/mbostock/d3/pull/368)
50016     * The `move` event has a `point` and `delta` [x, y] tuple properties rather
50017       than `x`, `y`, `dx`, and `dy` properties.
50018     * The `end` event is not dispatched if no movement occurs.
50019     * An `off` function is available that unbinds the drag's internal event handlers.
50020  */
50021
50022 function behaviorDrag() {
50023     var event$$1 = dispatch('start', 'move', 'end'),
50024         origin = null,
50025         selector$$1 = '',
50026         filter = null,
50027         event_, target, surface;
50028
50029
50030     var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect'),
50031         d3_event_userSelectSuppress = function() {
50032             var selection$$1 = selection(),
50033                 select$$1 = selection$$1.style(d3_event_userSelectProperty);
50034             selection$$1.style(d3_event_userSelectProperty, 'none');
50035             return function() {
50036                 selection$$1.style(d3_event_userSelectProperty, select$$1);
50037             };
50038         };
50039
50040
50041     function d3_eventCancel() {
50042         event.stopPropagation();
50043         event.preventDefault();
50044     }
50045
50046
50047     function eventOf(thiz, argumentz) {
50048         return function(e1) {
50049             e1.target = drag$$1;
50050             customEvent(e1, event$$1.apply, event$$1, [e1.type, thiz, argumentz]);
50051         };
50052     }
50053
50054
50055     function dragstart() {
50056         target = this;
50057         event_ = eventOf(target, arguments);
50058
50059         var eventTarget = event.target,
50060             touchId = event.touches ? event.changedTouches[0].identifier : null,
50061             offset,
50062             origin_ = point(),
50063             started = false,
50064             selectEnable = d3_event_userSelectSuppress(touchId !== null ? 'drag-' + touchId : 'drag');
50065
50066         select(window)
50067             .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', dragmove)
50068             .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', dragend, true);
50069
50070         if (origin) {
50071             offset = origin.apply(target, arguments);
50072             offset = [offset[0] - origin_[0], offset[1] - origin_[1]];
50073         } else {
50074             offset = [0, 0];
50075         }
50076
50077         if (touchId === null) {
50078             event.stopPropagation();
50079         }
50080
50081
50082         function point() {
50083             var p = surface || target.parentNode;
50084             return touchId !== null ? touches(p).filter(function(p) {
50085                 return p.identifier === touchId;
50086             })[0] : mouse(p);
50087         }
50088
50089
50090         function dragmove() {
50091             var p = point(),
50092                 dx = p[0] - origin_[0],
50093                 dy = p[1] - origin_[1];
50094
50095             if (dx === 0 && dy === 0)
50096                 return;
50097
50098             if (!started) {
50099                 started = true;
50100                 event_({ type: 'start' });
50101             }
50102
50103             origin_ = p;
50104             d3_eventCancel();
50105
50106             event_({
50107                 type: 'move',
50108                 point: [p[0] + offset[0],  p[1] + offset[1]],
50109                 delta: [dx, dy]
50110             });
50111         }
50112
50113
50114         function dragend() {
50115             if (started) {
50116                 event_({ type: 'end' });
50117
50118                 d3_eventCancel();
50119                 if (event.target === eventTarget) {
50120                     select(window)
50121                         .on('click.drag', click, true);
50122                 }
50123             }
50124
50125             select(window)
50126                 .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', null)
50127                 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', null);
50128
50129             selectEnable();
50130         }
50131
50132
50133         function click() {
50134             d3_eventCancel();
50135             select(window)
50136                 .on('click.drag', null);
50137         }
50138     }
50139
50140
50141     function drag$$1(selection$$1) {
50142         var matchesSelector = utilPrefixDOMProperty('matchesSelector'),
50143             delegate = dragstart;
50144
50145         if (selector$$1) {
50146             delegate = function() {
50147                 var root = this,
50148                     target = event.target;
50149                 for (; target && target !== root; target = target.parentNode) {
50150                     if (target[matchesSelector](selector$$1) &&
50151                             (!filter || filter(target.__data__))) {
50152                         return dragstart.call(target, target.__data__);
50153                     }
50154                 }
50155             };
50156         }
50157
50158         selection$$1
50159             .on('mousedown.drag' + selector$$1, delegate)
50160             .on('touchstart.drag' + selector$$1, delegate);
50161     }
50162
50163
50164     drag$$1.off = function(selection$$1) {
50165         selection$$1
50166             .on('mousedown.drag' + selector$$1, null)
50167             .on('touchstart.drag' + selector$$1, null);
50168     };
50169
50170
50171     drag$$1.selector = function(_) {
50172         if (!arguments.length) return selector$$1;
50173         selector$$1 = _;
50174         return drag$$1;
50175     };
50176
50177
50178     drag$$1.filter = function(_) {
50179         if (!arguments.length) return origin;
50180         filter = _;
50181         return drag$$1;
50182     };
50183
50184
50185     drag$$1.origin = function (_) {
50186         if (!arguments.length) return origin;
50187         origin = _;
50188         return drag$$1;
50189     };
50190
50191
50192     drag$$1.cancel = function() {
50193         select(window)
50194             .on('mousemove.drag', null)
50195             .on('mouseup.drag', null);
50196         return drag$$1;
50197     };
50198
50199
50200     drag$$1.target = function() {
50201         if (!arguments.length) return target;
50202         target = arguments[0];
50203         event_ = eventOf(target, Array.prototype.slice.call(arguments, 1));
50204         return drag$$1;
50205     };
50206
50207
50208     drag$$1.surface = function() {
50209         if (!arguments.length) return surface;
50210         surface = arguments[0];
50211         return drag$$1;
50212     };
50213
50214
50215     return utilRebind(drag$$1, event$$1, 'on');
50216 }
50217
50218 function behaviorDrawWay(context, wayId, index, mode, startGraph) {
50219
50220     var origWay = context.entity(wayId),
50221         isArea = context.geometry(wayId) === 'area',
50222         tempEdits = 0,
50223         annotation = t((origWay.isDegenerate() ?
50224             'operations.start.annotation.' :
50225             'operations.continue.annotation.') + context.geometry(wayId)),
50226         draw = behaviorDraw(context),
50227         startIndex,
50228         start,
50229         end,
50230         segment;
50231
50232
50233     // initialize the temporary drawing entities
50234     if (!isArea) {
50235         startIndex = typeof index === 'undefined' ? origWay.nodes.length - 1 : 0;
50236         start = osmNode({ id: 'nStart', loc: context.entity(origWay.nodes[startIndex]).loc });
50237         end = osmNode({ id: 'nEnd', loc: context.map().mouseCoordinates() });
50238         segment = osmWay({ id: 'wTemp',
50239             nodes: typeof index === 'undefined' ? [start.id, end.id] : [end.id, start.id],
50240             tags: lodash.clone(origWay.tags)
50241         });
50242     } else {
50243         end = osmNode({ loc: context.map().mouseCoordinates() });
50244     }
50245
50246     // Push an annotated state for undo to return back to.
50247     // We must make sure to remove this edit later.
50248     context.perform(actionNoop(), annotation);
50249     tempEdits++;
50250
50251     // Add the temporary drawing entities to the graph.
50252     // We must make sure to remove this edit later.
50253     context.perform(AddDrawEntities());
50254     tempEdits++;
50255
50256
50257     function move(datum) {
50258         var loc;
50259
50260         if (datum.type === 'node' && datum.id !== end.id) {
50261             loc = datum.loc;
50262
50263         } else if (datum.type === 'way') {
50264             var dims = context.map().dimensions(),
50265                 mouse = context.mouse(),
50266                 pad = 5,
50267                 trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad &&
50268                     mouse[1] > pad && mouse[1] < dims[1] - pad;
50269
50270             if (trySnap) {
50271                 loc = geoChooseEdge(context.childNodes(datum), context.mouse(), context.projection).loc;
50272             }
50273         }
50274
50275         if (!loc) {
50276             loc = context.map().mouseCoordinates();
50277         }
50278
50279         context.replace(actionMoveNode(end.id, loc));
50280         end = context.entity(end.id);
50281     }
50282
50283
50284     function undone() {
50285         // Undo popped the history back to the initial annotated no-op edit.
50286         // Remove initial no-op edit and whatever edit happened immediately before it.
50287         context.pop(2);
50288         tempEdits = 0;
50289
50290         if (context.hasEntity(wayId)) {
50291             context.enter(mode);
50292         } else {
50293             context.enter(modeBrowse(context));
50294         }
50295     }
50296
50297
50298     function setActiveElements() {
50299         var active = isArea ? [wayId, end.id] : [segment.id, start.id, end.id];
50300         context.surface().selectAll(utilEntitySelector(active))
50301             .classed('active', true);
50302     }
50303
50304
50305     var drawWay = function(surface) {
50306         draw.on('move', move)
50307             .on('click', drawWay.add)
50308             .on('clickWay', drawWay.addWay)
50309             .on('clickNode', drawWay.addNode)
50310             .on('undo', context.undo)
50311             .on('cancel', drawWay.cancel)
50312             .on('finish', drawWay.finish);
50313
50314         context.map()
50315             .dblclickEnable(false)
50316             .on('drawn.draw', setActiveElements);
50317
50318         setActiveElements();
50319
50320         surface.call(draw);
50321
50322         context.history()
50323             .on('undone.draw', undone);
50324     };
50325
50326
50327     drawWay.off = function(surface) {
50328         // Drawing was interrupted unexpectedly.
50329         // This can happen if the user changes modes,
50330         // clicks geolocate button, a hashchange event occurs, etc.
50331         if (tempEdits) {
50332             context.pop(tempEdits);
50333             while (context.graph() !== startGraph) {
50334                 context.pop();
50335             }
50336         }
50337
50338         context.map()
50339             .on('drawn.draw', null);
50340
50341         surface.call(draw.off)
50342             .selectAll('.active')
50343             .classed('active', false);
50344
50345         context.history()
50346             .on('undone.draw', null);
50347     };
50348
50349
50350     function AddDrawEntities() {
50351         return function(graph) {
50352             if (isArea) {
50353                 // For area drawing, there is no need for a temporary node.
50354                 // `end` gets inserted into the way as the penultimate node.
50355                 return graph
50356                     .replace(end)
50357                     .replace(origWay.addNode(end.id));
50358             } else {
50359                 // For line drawing, add a temporary start, end, and segment to the graph.
50360                 // This allows us to class the new segment as `active`, but still
50361                 // connect it back to parts of the way that have already been drawn.
50362                 return graph
50363                     .replace(start)
50364                     .replace(end)
50365                     .replace(segment);
50366             }
50367         };
50368     }
50369
50370
50371     function ReplaceDrawEntities(newNode) {
50372         return function(graph) {
50373             if (isArea) {
50374                 // For area drawing, we didn't create a temporary node.
50375                 // `newNode` gets inserted into the _original_ way as the penultimate node.
50376                 return graph
50377                     .replace(origWay.addNode(newNode.id))
50378                     .remove(end);
50379             } else {
50380                 // For line drawing, add the `newNode` to the way at specified index,
50381                 // and remove the temporary start, end, and segment.
50382                 return graph
50383                     .replace(origWay.addNode(newNode.id, index))
50384                     .remove(end)
50385                     .remove(segment)
50386                     .remove(start);
50387             }
50388         };
50389     }
50390
50391
50392     // Accept the current position of the temporary node and continue drawing.
50393     drawWay.add = function(loc) {
50394         // prevent duplicate nodes
50395         var last = context.hasEntity(origWay.nodes[origWay.nodes.length - (isArea ? 2 : 1)]);
50396         if (last && last.loc[0] === loc[0] && last.loc[1] === loc[1]) return;
50397
50398         context.pop(tempEdits);
50399
50400         if (isArea) {
50401             context.perform(
50402                 AddDrawEntities(),
50403                 annotation
50404             );
50405         } else {
50406             var newNode = osmNode({loc: loc});
50407             context.perform(
50408                 actionAddEntity(newNode),
50409                 ReplaceDrawEntities(newNode),
50410                 annotation
50411             );
50412         }
50413
50414         tempEdits = 0;
50415         context.enter(mode);
50416     };
50417
50418
50419     // Connect the way to an existing way.
50420     drawWay.addWay = function(loc, edge) {
50421         if (isArea) {
50422             context.pop(tempEdits);
50423
50424             context.perform(
50425                 AddDrawEntities(),
50426                 actionAddMidpoint({ loc: loc, edge: edge}, end),
50427                 annotation
50428             );
50429         } else {
50430             var previousEdge = startIndex ?
50431                 [origWay.nodes[startIndex], origWay.nodes[startIndex - 1]] :
50432                 [origWay.nodes[0], origWay.nodes[1]];
50433
50434             // Avoid creating duplicate segments
50435             if (geoEdgeEqual(edge, previousEdge))
50436                 return;
50437
50438             context.pop(tempEdits);
50439
50440             var newNode = osmNode({ loc: loc });
50441             context.perform(
50442                 actionAddMidpoint({ loc: loc, edge: edge}, newNode),
50443                 ReplaceDrawEntities(newNode),
50444                 annotation
50445             );
50446         }
50447
50448         tempEdits = 0;
50449         context.enter(mode);
50450     };
50451
50452
50453     // Connect the way to an existing node and continue drawing.
50454     drawWay.addNode = function(node) {
50455         // Avoid creating duplicate segments
50456         if (origWay.areAdjacent(node.id, origWay.nodes[origWay.nodes.length - 1])) return;
50457
50458         // Clicks should not occur on the drawing node, however a space keypress can
50459         // sometimes grab that node's datum (before it gets classed as `active`?)  #4016
50460         if (node.id === end.id) {
50461             drawWay.add(node.loc);
50462             return;
50463         }
50464
50465         context.pop(tempEdits);
50466
50467         context.perform(
50468             ReplaceDrawEntities(node),
50469             annotation
50470         );
50471
50472         tempEdits = 0;
50473         context.enter(mode);
50474     };
50475
50476
50477     // Finish the draw operation, removing the temporary edits.
50478     // If the way has enough nodes to be valid, it's selected.
50479     // Otherwise, delete everything and return to browse mode.
50480     drawWay.finish = function() {
50481         context.pop(tempEdits);
50482         tempEdits = 0;
50483
50484         var way = context.hasEntity(wayId);
50485         if (!way || way.isDegenerate()) {
50486             drawWay.cancel();
50487             return;
50488         }
50489
50490         window.setTimeout(function() {
50491             context.map().dblclickEnable(true);
50492         }, 1000);
50493
50494         context.enter(modeSelect(context, [wayId]).newFeature(true));
50495     };
50496
50497
50498     // Cancel the draw operation, delete everything, and return to browse mode.
50499     drawWay.cancel = function() {
50500         context.pop(tempEdits);
50501         tempEdits = 0;
50502
50503         while (context.graph() !== startGraph) {
50504             context.pop();
50505         }
50506
50507         window.setTimeout(function() {
50508             context.map().dblclickEnable(true);
50509         }, 1000);
50510
50511         context.enter(modeBrowse(context));
50512     };
50513
50514
50515     drawWay.tail = function(text) {
50516         draw.tail(text);
50517         return drawWay;
50518     };
50519
50520
50521     return drawWay;
50522 }
50523
50524 function behaviorHash(context) {
50525     var s0 = null, // cached window.location.hash
50526         lat = 90 - 1e-8; // allowable latitude range
50527
50528
50529     var parser = function(map$$1, s) {
50530         var q = utilStringQs(s);
50531         var args = (q.map || '').split('/').map(Number);
50532         if (args.length < 3 || args.some(isNaN)) {
50533             return true; // replace bogus hash
50534         } else if (s !== formatter(map$$1).slice(1)) {
50535             var mode = context.mode();
50536             if (mode && mode.id.match(/^draw/) !== null) {
50537                 context.enter(modeBrowse(context));
50538             }
50539             map$$1.centerZoom([args[2], Math.min(lat, Math.max(-lat, args[1]))], args[0]);
50540         }
50541     };
50542
50543
50544     var formatter = function(map$$1) {
50545         var center = map$$1.center(),
50546             zoom$$1 = map$$1.zoom(),
50547             precision = Math.max(0, Math.ceil(Math.log(zoom$$1) / Math.LN2)),
50548             q = lodash.omit(utilStringQs(window.location.hash.substring(1)), 'comment'),
50549             newParams = {};
50550
50551         delete q.id;
50552         var selected = context.selectedIDs().filter(function(id) {
50553             return !context.entity(id).isNew();
50554         });
50555         if (selected.length) {
50556             newParams.id = selected.join(',');
50557         }
50558
50559         newParams.map = zoom$$1.toFixed(2) +
50560             '/' + center[1].toFixed(precision) +
50561             '/' + center[0].toFixed(precision);
50562
50563         return '#' + utilQsString(lodash.assign(q, newParams), true);
50564     };
50565
50566
50567     function update() {
50568         if (context.inIntro()) return;
50569         var s1 = formatter(context.map());
50570         if (s0 !== s1) {
50571             window.location.replace(s0 = s1);  // don't recenter the map!
50572         }
50573     }
50574
50575
50576     var throttledUpdate = lodash.throttle(update, 500);
50577
50578
50579     function hashchange() {
50580         if (window.location.hash === s0) return;  // ignore spurious hashchange events
50581         if (parser(context.map(), (s0 = window.location.hash).substring(1))) {
50582             update(); // replace bogus hash
50583         }
50584     }
50585
50586
50587     function hash() {
50588         context.map()
50589             .on('move.hash', throttledUpdate);
50590
50591         context
50592             .on('enter.hash', throttledUpdate);
50593
50594         select(window)
50595             .on('hashchange.hash', hashchange);
50596
50597         if (window.location.hash) {
50598             var q = utilStringQs(window.location.hash.substring(1));
50599             if (q.id) {
50600                 context.zoomToEntity(q.id.split(',')[0], !q.map);
50601             }
50602             if (q.comment) {
50603                 context.storage('comment', q.comment);
50604                 context.storage('commentDate', Date.now());
50605             }
50606             hashchange();
50607             if (q.map) hash.hadHash = true;
50608         }
50609     }
50610
50611
50612     hash.off = function() {
50613         throttledUpdate.cancel();
50614
50615         context.map()
50616             .on('move.hash', null);
50617
50618         context
50619             .on('enter.hash', null);
50620
50621         select(window)
50622             .on('hashchange.hash', null);
50623
50624         window.location.hash = '';
50625     };
50626
50627
50628     return hash;
50629 }
50630
50631 function behaviorLasso(context) {
50632
50633     var behavior = function(selection$$1) {
50634         var lasso;
50635
50636
50637         function mousedown() {
50638             var button = 0;  // left
50639             if (event.button === button && event.shiftKey === true) {
50640                 lasso = null;
50641
50642                 select(window)
50643                     .on('mousemove.lasso', mousemove)
50644                     .on('mouseup.lasso', mouseup);
50645
50646                 event.stopPropagation();
50647             }
50648         }
50649
50650
50651         function mousemove() {
50652             if (!lasso) {
50653                 lasso = uiLasso(context);
50654                 context.surface().call(lasso);
50655             }
50656
50657             lasso.p(context.mouse());
50658         }
50659
50660
50661         function normalize(a, b) {
50662             return [
50663                 [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
50664                 [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
50665         }
50666
50667
50668         function lassoed() {
50669             if (!lasso) return [];
50670
50671             var graph = context.graph(),
50672                 bounds = lasso.extent().map(context.projection.invert),
50673                 extent$$1 = geoExtent$$1(normalize(bounds[0], bounds[1]));
50674
50675             return lodash.map(context.intersects(extent$$1).filter(function(entity) {
50676                 return entity.type === 'node' &&
50677                     geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) &&
50678                     !context.features().isHidden(entity, graph, entity.geometry(graph));
50679             }), 'id');
50680         }
50681
50682
50683         function mouseup() {
50684             select(window)
50685                 .on('mousemove.lasso', null)
50686                 .on('mouseup.lasso', null);
50687
50688             if (!lasso) return;
50689
50690             var ids = lassoed();
50691             lasso.close();
50692
50693             if (ids.length) {
50694                 context.enter(modeSelect(context, ids));
50695             }
50696         }
50697
50698         selection$$1
50699             .on('mousedown.lasso', mousedown);
50700     };
50701
50702
50703     behavior.off = function(selection$$1) {
50704         selection$$1.on('mousedown.lasso', null);
50705     };
50706
50707
50708     return behavior;
50709 }
50710
50711 /* Creates a keybinding behavior for an operation */
50712 function behaviorOperation() {
50713     var which, keybinding;
50714
50715
50716     function drawIcon(selection$$1) {
50717         var button = selection$$1
50718             .append('svg')
50719             .attr('class', 'operation-icon')
50720             .append('g')
50721             .attr('class', 'radial-menu-item radial-menu-item-' + which.id)
50722             .attr('transform', 'translate(10,10)')
50723             .classed('disabled', which.disabled());
50724
50725         button
50726             .append('circle')
50727             .attr('r', 9);
50728
50729         button
50730             .append('use')
50731             .attr('transform', 'translate(-7,-7)')
50732             .attr('width', '14')
50733             .attr('height', '14')
50734             .attr('xlink:href', '#operation-' + which.id);
50735
50736         return selection$$1;
50737     }
50738
50739
50740     var behavior = function () {
50741         if (which && which.available()) {
50742             keybinding = d3keybinding('behavior.key.' + which.id);
50743             keybinding.on(which.keys, function() {
50744                 event.preventDefault();
50745                 var disabled = which.disabled();
50746
50747                 if (disabled) {
50748                     uiFlash(3000)
50749                         .html('')
50750                         .call(drawIcon)
50751                         .append('div')
50752                         .attr('class', 'operation-tip')
50753                         .text(which.tooltip);
50754
50755                 } else {
50756                     uiFlash(1500)
50757                         .html('')
50758                         .call(drawIcon)
50759                         .append('div')
50760                         .attr('class', 'operation-tip')
50761                         .text(which.annotation() || which.title);
50762
50763                     which();
50764                 }
50765             });
50766             select(document).call(keybinding);
50767         }
50768         return behavior;
50769     };
50770
50771
50772     behavior.off = function() {
50773         if (keybinding) {
50774             select(document).call(keybinding.off);
50775         }
50776     };
50777
50778
50779     behavior.which = function (_) {
50780         if (!arguments.length) return which;
50781         which = _;
50782         return behavior;
50783     };
50784
50785
50786     return behavior;
50787 }
50788
50789 function behaviorPaste(context) {
50790     var keybinding = d3keybinding('paste');
50791
50792     function omitTag(v, k) {
50793         return (
50794             k === 'phone' ||
50795             k === 'fax' ||
50796             k === 'email' ||
50797             k === 'website' ||
50798             k === 'url' ||
50799             k === 'note' ||
50800             k === 'description' ||
50801             k.indexOf('name') !== -1 ||
50802             k.indexOf('wiki') === 0 ||
50803             k.indexOf('addr:') === 0 ||
50804             k.indexOf('contact:') === 0
50805         );
50806     }
50807
50808
50809     function doPaste() {
50810         event.preventDefault();
50811
50812         var baseGraph = context.graph(),
50813             mouse$$1 = context.mouse(),
50814             projection = context.projection,
50815             viewport = geoExtent$$1(projection.clipExtent()).polygon();
50816
50817         if (!geoPointInPolygon(mouse$$1, viewport)) return;
50818
50819         var extent$$1 = geoExtent$$1(),
50820             oldIDs = context.copyIDs(),
50821             oldGraph = context.copyGraph(),
50822             newIDs = [];
50823
50824         if (!oldIDs.length) return;
50825
50826         var action = actionCopyEntities(oldIDs, oldGraph);
50827         context.perform(action);
50828
50829         var copies = action.copies();
50830         var originals = lodash.invert(lodash.mapValues(copies, 'id'));
50831         for (var id in copies) {
50832             var oldEntity = oldGraph.entity(id),
50833                 newEntity = copies[id];
50834
50835             extent$$1._extend(oldEntity.extent(oldGraph));
50836             context.perform(
50837                 actionChangeTags(newEntity.id, lodash.omitBy(newEntity.tags, omitTag))
50838             );
50839
50840             // Exclude child nodes from newIDs if their parent way was also copied.
50841             var parents = context.graph().parentWays(newEntity),
50842                 parentCopied = false;
50843             for (var i = 0; i < parents.length; i++) {
50844                 if (originals[parents[i].id]) {
50845                     parentCopied = true;
50846                     break;
50847                 }
50848             }
50849
50850             if (!parentCopied) {
50851                 newIDs.push(newEntity.id);
50852             }
50853         }
50854
50855         // Put pasted objects where mouse pointer is..
50856         var center = projection(extent$$1.center()),
50857             delta = [ mouse$$1[0] - center[0], mouse$$1[1] - center[1] ];
50858
50859         context.perform(actionMove(newIDs, delta, projection));
50860         context.enter(modeMove$$1(context, newIDs, baseGraph));
50861     }
50862
50863
50864     function paste() {
50865         keybinding.on(uiCmd('⌘V'), doPaste);
50866         select(document).call(keybinding);
50867         return paste;
50868     }
50869
50870
50871     paste.off = function() {
50872         select(document).call(keybinding.off);
50873     };
50874
50875
50876     return paste;
50877 }
50878
50879 function behaviorSelect(context) {
50880     var lastMouse = null,
50881         suppressMenu = true,
50882         tolerance = 4,
50883         p1 = null;
50884
50885
50886     function point() {
50887         return mouse(context.container().node());
50888     }
50889
50890
50891     function keydown() {
50892         var e = event;
50893         if (e && e.shiftKey) {
50894             context.surface()
50895                 .classed('behavior-multiselect', true);
50896         }
50897
50898         if (e && e.keyCode === 93) {  // context menu
50899             e.preventDefault();
50900             e.stopPropagation();
50901         }
50902     }
50903
50904
50905     function keyup() {
50906         var e = event;
50907         if (!e || !e.shiftKey) {
50908             context.surface()
50909                 .classed('behavior-multiselect', false);
50910         }
50911
50912
50913         if (e && e.keyCode === 93) {  // context menu
50914             e.preventDefault();
50915             e.stopPropagation();
50916             contextmenu();
50917         }
50918     }
50919
50920
50921     function mousedown() {
50922         if (!p1) p1 = point();
50923         select(window)
50924             .on('mouseup.select', mouseup, true);
50925
50926         var isShowAlways = +context.storage('edit-menu-show-always') === 1;
50927         suppressMenu = !isShowAlways;
50928     }
50929
50930
50931     function mousemove() {
50932         if (event) lastMouse = event;
50933     }
50934
50935
50936     function mouseup() {
50937         click();
50938     }
50939
50940
50941     function contextmenu() {
50942         var e = event;
50943         e.preventDefault();
50944         e.stopPropagation();
50945
50946         if (!+e.clientX && !+e.clientY) {
50947             if (lastMouse) {
50948                 e.sourceEvent = lastMouse;
50949             } else {
50950                 return;
50951             }
50952         }
50953
50954         if (!p1) p1 = point();
50955         suppressMenu = false;
50956         click();
50957     }
50958
50959
50960     function click() {
50961         select(window)
50962             .on('mouseup.select', null, true);
50963
50964         if (!p1) return;
50965         var p2 = point(),
50966             dist = geoEuclideanDistance(p1, p2);
50967
50968         p1 = null;
50969         if (dist > tolerance) {
50970             return;
50971         }
50972
50973         var isMultiselect = event.shiftKey || select('#surface .lasso').node(),
50974             isShowAlways = +context.storage('edit-menu-show-always') === 1,
50975             datum = event.target.__data__ || (lastMouse && lastMouse.target.__data__),
50976             mode = context.mode();
50977
50978
50979         if (datum && datum.type === 'midpoint') {
50980             datum = datum.parents[0];
50981         }
50982
50983         if (!(datum instanceof osmEntity$$1)) {
50984             // clicked nothing..
50985             if (!isMultiselect && mode.id !== 'browse') {
50986                 context.enter(modeBrowse(context));
50987             }
50988
50989         } else {
50990             // clicked an entity..
50991             var selectedIDs = context.selectedIDs();
50992
50993             if (!isMultiselect) {
50994                 if (selectedIDs.length > 1 && (!suppressMenu && !isShowAlways)) {
50995                     // multiple things already selected, just show the menu...
50996                     mode.suppressMenu(false).reselect();
50997                 } else {
50998                     // select a single thing..
50999                     context.enter(modeSelect(context, [datum.id]).suppressMenu(suppressMenu));
51000                 }
51001
51002             } else {
51003                 if (selectedIDs.indexOf(datum.id) !== -1) {
51004                     // clicked entity is already in the selectedIDs list..
51005                     if (!suppressMenu && !isShowAlways) {
51006                         // don't deselect clicked entity, just show the menu.
51007                         mode.suppressMenu(false).reselect();
51008                     } else {
51009                         // deselect clicked entity, then reenter select mode or return to browse mode..
51010                         selectedIDs = lodash.without(selectedIDs, datum.id);
51011                         context.enter(selectedIDs.length ? modeSelect(context, selectedIDs) : modeBrowse(context));
51012                     }
51013                 } else {
51014                     // clicked entity is not in the selected list, add it..
51015                     selectedIDs = selectedIDs.concat([datum.id]);
51016                     context.enter(modeSelect(context, selectedIDs).suppressMenu(suppressMenu));
51017                 }
51018             }
51019         }
51020
51021         // reset for next time..
51022         suppressMenu = true;
51023     }
51024
51025
51026     var behavior = function(selection$$1) {
51027         lastMouse = null;
51028         suppressMenu = true;
51029         p1 = null;
51030
51031         select(window)
51032             .on('keydown.select', keydown)
51033             .on('keyup.select', keyup)
51034             .on('contextmenu.select-window', function() {
51035                 // Edge and IE really like to show the contextmenu on the
51036                 // menubar when user presses a keyboard menu button
51037                 // even after we've already preventdefaulted the key event.
51038                 var e = event;
51039                 if (+e.clientX === 0 && +e.clientY === 0) {
51040                     event.preventDefault();
51041                     event.stopPropagation();
51042                 }
51043             });
51044
51045         selection$$1
51046             .on('mousedown.select', mousedown)
51047             .on('mousemove.select', mousemove)
51048             .on('contextmenu.select', contextmenu);
51049
51050         if (event && event.shiftKey) {
51051             context.surface()
51052                 .classed('behavior-multiselect', true);
51053         }
51054     };
51055
51056
51057     behavior.off = function(selection$$1) {
51058         select(window)
51059             .on('keydown.select', null)
51060             .on('keyup.select', null)
51061             .on('contextmenu.select-window', null)
51062             .on('mouseup.select', null, true);
51063
51064         selection$$1
51065             .on('mousedown.select', null)
51066             .on('mousemove.select', null)
51067             .on('contextmenu.select', null);
51068
51069         context.surface()
51070             .classed('behavior-multiselect', false);
51071     };
51072
51073
51074     return behavior;
51075 }
51076
51077 function modeAddArea$$1(context) {
51078     var mode = {
51079         id: 'add-area',
51080         button: 'area',
51081         title: t('modes.add_area.title'),
51082         description: t('modes.add_area.description'),
51083         key: '3'
51084     };
51085
51086     var behavior = behaviorAddWay(context)
51087             .tail(t('modes.add_area.tail'))
51088             .on('start', start)
51089             .on('startFromWay', startFromWay)
51090             .on('startFromNode', startFromNode),
51091         defaultTags = { area: 'yes' };
51092
51093
51094     function actionClose(wayId) {
51095         return function (graph) {
51096             return graph.replace(graph.entity(wayId).close());
51097         };
51098     }
51099
51100
51101     function start(loc) {
51102         var startGraph = context.graph(),
51103             node = osmNode({ loc: loc }),
51104             way = osmWay({ tags: defaultTags });
51105
51106         context.perform(
51107             actionAddEntity(node),
51108             actionAddEntity(way),
51109             actionAddVertex(way.id, node.id),
51110             actionClose(way.id)
51111         );
51112
51113         context.enter(modeDrawArea(context, way.id, startGraph));
51114     }
51115
51116
51117     function startFromWay(loc, edge) {
51118         var startGraph = context.graph(),
51119             node = osmNode({ loc: loc }),
51120             way = osmWay({ tags: defaultTags });
51121
51122         context.perform(
51123             actionAddEntity(node),
51124             actionAddEntity(way),
51125             actionAddVertex(way.id, node.id),
51126             actionClose(way.id),
51127             actionAddMidpoint({ loc: loc, edge: edge }, node)
51128         );
51129
51130         context.enter(modeDrawArea(context, way.id, startGraph));
51131     }
51132
51133
51134     function startFromNode(node) {
51135         var startGraph = context.graph(),
51136             way = osmWay({ tags: defaultTags });
51137
51138         context.perform(
51139             actionAddEntity(way),
51140             actionAddVertex(way.id, node.id),
51141             actionClose(way.id)
51142         );
51143
51144         context.enter(modeDrawArea(context, way.id, startGraph));
51145     }
51146
51147
51148     mode.enter = function() {
51149         context.install(behavior);
51150     };
51151
51152
51153     mode.exit = function() {
51154         context.uninstall(behavior);
51155     };
51156
51157
51158     return mode;
51159 }
51160
51161 function modeAddLine$$1(context) {
51162     var mode = {
51163         id: 'add-line',
51164         button: 'line',
51165         title: t('modes.add_line.title'),
51166         description: t('modes.add_line.description'),
51167         key: '2'
51168     };
51169
51170     var behavior = behaviorAddWay(context)
51171         .tail(t('modes.add_line.tail'))
51172         .on('start', start)
51173         .on('startFromWay', startFromWay)
51174         .on('startFromNode', startFromNode);
51175
51176
51177     function start(loc) {
51178         var startGraph = context.graph(),
51179             node = osmNode({ loc: loc }),
51180             way = osmWay();
51181
51182         context.perform(
51183             actionAddEntity(node),
51184             actionAddEntity(way),
51185             actionAddVertex(way.id, node.id)
51186         );
51187
51188         context.enter(modeDrawLine(context, way.id, startGraph));
51189     }
51190
51191
51192     function startFromWay(loc, edge) {
51193         var startGraph = context.graph(),
51194             node = osmNode({ loc: loc }),
51195             way = osmWay();
51196
51197         context.perform(
51198             actionAddEntity(node),
51199             actionAddEntity(way),
51200             actionAddVertex(way.id, node.id),
51201             actionAddMidpoint({ loc: loc, edge: edge }, node)
51202         );
51203
51204         context.enter(modeDrawLine(context, way.id, startGraph));
51205     }
51206
51207
51208     function startFromNode(node) {
51209         var startGraph = context.graph(),
51210             way = osmWay();
51211
51212         context.perform(
51213             actionAddEntity(way),
51214             actionAddVertex(way.id, node.id)
51215         );
51216
51217         context.enter(modeDrawLine(context, way.id, startGraph));
51218     }
51219
51220
51221     mode.enter = function() {
51222         context.install(behavior);
51223     };
51224
51225
51226     mode.exit = function() {
51227         context.uninstall(behavior);
51228     };
51229
51230     return mode;
51231 }
51232
51233 function modeAddPoint$$1(context) {
51234     var mode = {
51235         id: 'add-point',
51236         button: 'point',
51237         title: t('modes.add_point.title'),
51238         description: t('modes.add_point.description'),
51239         key: '1'
51240     };
51241
51242     var behavior = behaviorDraw(context)
51243         .tail(t('modes.add_point.tail'))
51244         .on('click', add)
51245         .on('clickWay', addWay)
51246         .on('clickNode', addNode)
51247         .on('cancel', cancel)
51248         .on('finish', cancel);
51249
51250
51251     function add(loc) {
51252         var node = osmNode({ loc: loc });
51253
51254         context.perform(
51255             actionAddEntity(node),
51256             t('operations.add.annotation.point')
51257         );
51258
51259         context.enter(
51260             modeSelect(context, [node.id]).newFeature(true)
51261         );
51262     }
51263
51264
51265     function addWay(loc) {
51266         add(loc);
51267     }
51268
51269
51270     function addNode(node) {
51271         add(node.loc);
51272     }
51273
51274
51275     function cancel() {
51276         context.enter(modeBrowse(context));
51277     }
51278
51279
51280     mode.enter = function() {
51281         context.install(behavior);
51282     };
51283
51284
51285     mode.exit = function() {
51286         context.uninstall(behavior);
51287     };
51288
51289
51290     return mode;
51291 }
51292
51293 function modeDragNode$$1(context) {
51294     var mode = {
51295         id: 'drag-node',
51296         button: 'browse'
51297     };
51298
51299     var nudgeInterval,
51300         activeIDs,
51301         wasMidpoint,
51302         isCancelled,
51303         lastLoc,
51304         selectedIDs = [],
51305         hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover),
51306         edit = behaviorEdit(context);
51307
51308
51309     function vecSub(a, b) {
51310         return [a[0] - b[0], a[1] - b[1]];
51311     }
51312
51313     function edge(point, size) {
51314         var pad = [80, 20, 50, 20],   // top, right, bottom, left
51315             x = 0,
51316             y = 0;
51317
51318         if (point[0] > size[0] - pad[1])
51319             x = -10;
51320         if (point[0] < pad[3])
51321             x = 10;
51322         if (point[1] > size[1] - pad[2])
51323             y = -10;
51324         if (point[1] < pad[0])
51325             y = 10;
51326
51327         if (x || y) {
51328             return [x, y];
51329         } else {
51330             return null;
51331         }
51332     }
51333
51334
51335     function startNudge(entity, nudge) {
51336         if (nudgeInterval) window.clearInterval(nudgeInterval);
51337         nudgeInterval = window.setInterval(function() {
51338             context.pan(nudge);
51339             doMove(entity, nudge);
51340         }, 50);
51341     }
51342
51343
51344     function stopNudge() {
51345         if (nudgeInterval) {
51346             window.clearInterval(nudgeInterval);
51347             nudgeInterval = null;
51348         }
51349     }
51350
51351
51352     function moveAnnotation(entity) {
51353         return t('operations.move.annotation.' + entity.geometry(context.graph()));
51354     }
51355
51356
51357     function connectAnnotation(entity) {
51358         return t('operations.connect.annotation.' + entity.geometry(context.graph()));
51359     }
51360
51361
51362     function origin(entity) {
51363         return context.projection(entity.loc);
51364     }
51365
51366
51367     function start(entity) {
51368         wasMidpoint = entity.type === 'midpoint';
51369
51370         isCancelled = event.sourceEvent.shiftKey ||
51371             context.features().hasHiddenConnections(entity, context.graph());
51372
51373         if (isCancelled) {
51374             return behavior.cancel();
51375         }
51376
51377         if (wasMidpoint) {
51378             var midpoint = entity;
51379             entity = osmNode();
51380             context.perform(actionAddMidpoint(midpoint, entity));
51381
51382             var vertex = context.surface().selectAll('.' + entity.id);
51383             behavior.target(vertex.node(), entity);
51384
51385         } else {
51386             context.perform(actionNoop());
51387         }
51388
51389         // activeIDs generate no pointer events.  This prevents the node or vertex
51390         // being dragged from trying to connect to itself or its parent element.
51391         activeIDs = lodash.map(context.graph().parentWays(entity), 'id');
51392         activeIDs.push(entity.id);
51393         setActiveElements();
51394
51395         context.enter(mode);
51396     }
51397
51398
51399     function datum() {
51400         var event$$1 = event && event.sourceEvent;
51401         if (!event$$1 || event$$1.altKey) {
51402             return {};
51403         } else {
51404             return event$$1.target.__data__ || {};
51405         }
51406     }
51407
51408
51409     function doMove(entity, nudge) {
51410         nudge = nudge || [0, 0];
51411
51412         var currPoint = (event && event.point) || context.projection(lastLoc),
51413             currMouse = vecSub(currPoint, nudge),
51414             loc = context.projection.invert(currMouse),
51415             d = datum();
51416
51417         if (!nudgeInterval) {
51418             if (d.type === 'node' && d.id !== entity.id) {
51419                 loc = d.loc;
51420             } else if (d.type === 'way' && !select(event.sourceEvent.target).classed('fill')) {
51421                 loc = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection).loc;
51422             }
51423         }
51424
51425         context.replace(
51426             actionMoveNode(entity.id, loc),
51427             moveAnnotation(entity)
51428         );
51429
51430         lastLoc = loc;
51431     }
51432
51433
51434     function move(entity) {
51435         if (isCancelled) return;
51436         event.sourceEvent.stopPropagation();
51437         lastLoc = context.projection.invert(event.point);
51438
51439         doMove(entity);
51440         var nudge = edge(event.point, context.map().dimensions());
51441         if (nudge) {
51442             startNudge(entity, nudge);
51443         } else {
51444             stopNudge();
51445         }
51446     }
51447
51448
51449     function end(entity) {
51450         if (isCancelled) return;
51451
51452         var d = datum();
51453
51454         if (d.type === 'way') {
51455             var choice = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection);
51456             context.replace(
51457                 actionAddMidpoint({ loc: choice.loc, edge: [d.nodes[choice.index - 1], d.nodes[choice.index]] }, entity),
51458                 connectAnnotation(d)
51459             );
51460
51461         } else if (d.type === 'node' && d.id !== entity.id) {
51462             context.replace(
51463                 actionConnect([d.id, entity.id]),
51464                 connectAnnotation(d)
51465             );
51466
51467         } else if (wasMidpoint) {
51468             context.replace(
51469                 actionNoop(),
51470                 t('operations.add.annotation.vertex')
51471             );
51472
51473         } else {
51474             context.replace(
51475                 actionNoop(),
51476                 moveAnnotation(entity)
51477             );
51478         }
51479
51480         var reselection = selectedIDs.filter(function(id) {
51481             return context.graph().hasEntity(id);
51482         });
51483
51484         if (reselection.length) {
51485             context.enter(modeSelect(context, reselection));
51486         } else {
51487             context.enter(modeBrowse(context));
51488         }
51489     }
51490
51491
51492     function cancel() {
51493         behavior.cancel();
51494         context.enter(modeBrowse(context));
51495     }
51496
51497
51498     function setActiveElements() {
51499         context.surface().selectAll(utilEntitySelector(activeIDs))
51500             .classed('active', true);
51501     }
51502
51503
51504     var behavior = behaviorDrag()
51505         .selector('g.node, g.point, g.midpoint')
51506         .surface(select('#map').node())
51507         .origin(origin)
51508         .on('start', start)
51509         .on('move', move)
51510         .on('end', end);
51511
51512
51513     mode.enter = function() {
51514         context.install(hover);
51515         context.install(edit);
51516
51517         context.history()
51518             .on('undone.drag-node', cancel);
51519
51520         context.map()
51521             .on('drawn.drag-node', setActiveElements);
51522
51523         setActiveElements();
51524     };
51525
51526
51527     mode.exit = function() {
51528         context.ui().sidebar.hover.cancel();
51529         context.uninstall(hover);
51530         context.uninstall(edit);
51531
51532         context.history()
51533             .on('undone.drag-node', null);
51534
51535         context.map()
51536             .on('drawn.drag-node', null);
51537
51538         context.surface()
51539             .selectAll('.active')
51540             .classed('active', false);
51541
51542         stopNudge();
51543     };
51544
51545
51546     mode.selectedIDs = function(_) {
51547         if (!arguments.length) return selectedIDs;
51548         selectedIDs = _;
51549         return mode;
51550     };
51551
51552
51553     mode.behavior = behavior;
51554
51555
51556     return mode;
51557 }
51558
51559 function modeBrowse(context) {
51560     var mode = {
51561         button: 'browse',
51562         id: 'browse',
51563         title: t('modes.browse.title'),
51564         description: t('modes.browse.description')
51565     }, sidebar;
51566
51567     var behaviors = [
51568         behaviorPaste(context),
51569         behaviorHover(context).on('hover', context.ui().sidebar.hover),
51570         behaviorSelect(context),
51571         behaviorLasso(context),
51572         modeDragNode$$1(context).behavior
51573     ];
51574
51575
51576     mode.enter = function() {
51577         behaviors.forEach(function(behavior) {
51578             context.install(behavior);
51579         });
51580
51581         // Get focus on the body.
51582         if (document.activeElement && document.activeElement.blur) {
51583             document.activeElement.blur();
51584         }
51585
51586         if (sidebar) {
51587             context.ui().sidebar.show(sidebar);
51588         } else {
51589             context.ui().sidebar.select(null);
51590         }
51591     };
51592
51593
51594     mode.exit = function() {
51595         context.ui().sidebar.hover.cancel();
51596         behaviors.forEach(function(behavior) {
51597             context.uninstall(behavior);
51598         });
51599
51600         if (sidebar) {
51601             context.ui().sidebar.hide();
51602         }
51603     };
51604
51605
51606     mode.sidebar = function(_) {
51607         if (!arguments.length) return sidebar;
51608         sidebar = _;
51609         return mode;
51610     };
51611
51612
51613     return mode;
51614 }
51615
51616 function modeDrawArea(context, wayId, startGraph) {
51617     var mode = {
51618         button: 'area',
51619         id: 'draw-area'
51620     };
51621
51622     var behavior;
51623
51624
51625     mode.enter = function() {
51626         var way = context.entity(wayId);
51627
51628         behavior = behaviorDrawWay(context, wayId, undefined, mode, startGraph)
51629             .tail(t('modes.draw_area.tail'));
51630
51631         var addNode = behavior.addNode;
51632
51633         behavior.addNode = function(node) {
51634             var length = way.nodes.length,
51635                 penultimate = length > 2 ? way.nodes[length - 2] : null;
51636
51637             if (node.id === way.first() || node.id === penultimate) {
51638                 behavior.finish();
51639             } else {
51640                 addNode(node);
51641             }
51642         };
51643
51644         context.install(behavior);
51645     };
51646
51647
51648     mode.exit = function() {
51649         context.uninstall(behavior);
51650     };
51651
51652
51653     mode.selectedIDs = function() {
51654         return [wayId];
51655     };
51656
51657
51658     return mode;
51659 }
51660
51661 function modeDrawLine(context, wayId, startGraph, affix) {
51662     var mode = {
51663         button: 'line',
51664         id: 'draw-line'
51665     };
51666
51667     var behavior;
51668
51669
51670     mode.enter = function() {
51671         var way = context.entity(wayId),
51672             index = (affix === 'prefix') ? 0 : undefined,
51673             headId = (affix === 'prefix') ? way.first() : way.last();
51674
51675         behavior = behaviorDrawWay(context, wayId, index, mode, startGraph)
51676             .tail(t('modes.draw_line.tail'));
51677
51678         var addNode = behavior.addNode;
51679
51680         behavior.addNode = function(node) {
51681             if (node.id === headId) {
51682                 behavior.finish();
51683             } else {
51684                 addNode(node);
51685             }
51686         };
51687
51688         context.install(behavior);
51689     };
51690
51691
51692     mode.exit = function() {
51693         context.uninstall(behavior);
51694     };
51695
51696
51697     mode.selectedIDs = function() {
51698         return [wayId];
51699     };
51700
51701
51702     return mode;
51703 }
51704
51705 function operationCircularize(selectedIDs, context) {
51706     var entityId = selectedIDs[0],
51707         entity = context.entity(entityId),
51708         extent = entity.extent(context.graph()),
51709         geometry = context.geometry(entityId),
51710         action = actionCircularize(entityId, context.projection);
51711
51712
51713     var operation = function() {
51714         context.perform(action, operation.annotation());
51715     };
51716
51717
51718     operation.available = function() {
51719         return selectedIDs.length === 1 &&
51720             entity.type === 'way' &&
51721             lodash.uniq(entity.nodes).length > 1;
51722     };
51723
51724
51725     operation.disabled = function() {
51726         var reason;
51727         if (extent.percentContainedIn(context.extent()) < 0.8) {
51728             reason = 'too_large';
51729         } else if (context.hasHiddenConnections(entityId)) {
51730             reason = 'connected_to_hidden';
51731         }
51732         return action.disabled(context.graph()) || reason;
51733     };
51734
51735
51736     operation.tooltip = function() {
51737         var disable = operation.disabled();
51738         return disable ?
51739             t('operations.circularize.' + disable) :
51740             t('operations.circularize.description.' + geometry);
51741     };
51742
51743
51744     operation.annotation = function() {
51745         return t('operations.circularize.annotation.' + geometry);
51746     };
51747
51748
51749     operation.id = 'circularize';
51750     operation.keys = [t('operations.circularize.key')];
51751     operation.title = t('operations.circularize.title');
51752     operation.behavior = behaviorOperation(context).which(operation);
51753
51754     return operation;
51755 }
51756
51757 function operationContinue(selectedIDs, context) {
51758     var graph = context.graph(),
51759         entities = selectedIDs.map(function(id) { return graph.entity(id); }),
51760         geometries = lodash.extend({ line: [], vertex: [] },
51761             lodash.groupBy(entities, function(entity) { return entity.geometry(graph); })),
51762         vertex = geometries.vertex[0];
51763
51764
51765     function candidateWays() {
51766         return graph.parentWays(vertex).filter(function(parent) {
51767             return parent.geometry(graph) === 'line' &&
51768                 !parent.isClosed() &&
51769                 parent.affix(vertex.id) &&
51770                 (geometries.line.length === 0 || geometries.line[0] === parent);
51771         });
51772     }
51773
51774
51775     var operation = function() {
51776         var candidate = candidateWays()[0];
51777         context.enter(
51778             modeDrawLine(context, candidate.id, context.graph(), candidate.affix(vertex.id))
51779         );
51780     };
51781
51782
51783     operation.available = function() {
51784         return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
51785             !context.features().hasHiddenConnections(vertex, context.graph());
51786     };
51787
51788
51789     operation.disabled = function() {
51790         var candidates = candidateWays();
51791         if (candidates.length === 0)
51792             return 'not_eligible';
51793         if (candidates.length > 1)
51794             return 'multiple';
51795     };
51796
51797
51798     operation.tooltip = function() {
51799         var disable = operation.disabled();
51800         return disable ?
51801             t('operations.continue.' + disable) :
51802             t('operations.continue.description');
51803     };
51804
51805
51806     operation.annotation = function() {
51807         return t('operations.continue.annotation.line');
51808     };
51809
51810
51811     operation.id = 'continue';
51812     operation.keys = [t('operations.continue.key')];
51813     operation.title = t('operations.continue.title');
51814     operation.behavior = behaviorOperation(context).which(operation);
51815
51816     return operation;
51817 }
51818
51819 function operationDelete(selectedIDs, context) {
51820     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
51821         action = actionDeleteMultiple(selectedIDs),
51822         extent = selectedIDs.reduce(function(extent, id) {
51823                 return extent.extend(context.entity(id).extent(context.graph()));
51824             }, geoExtent$$1());
51825
51826
51827     var operation = function() {
51828         var nextSelectedID;
51829
51830         if (selectedIDs.length === 1) {
51831             var id = selectedIDs[0],
51832                 entity = context.entity(id),
51833                 geometry = context.geometry(id),
51834                 parents = context.graph().parentWays(entity),
51835                 parent = parents[0];
51836
51837             // Select the next closest node in the way.
51838             if (geometry === 'vertex' && parent.nodes.length > 2) {
51839                 var nodes = parent.nodes,
51840                     i = nodes.indexOf(id);
51841
51842                 if (i === 0) {
51843                     i++;
51844                 } else if (i === nodes.length - 1) {
51845                     i--;
51846                 } else {
51847                     var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
51848                         b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
51849                     i = a < b ? i - 1 : i + 1;
51850                 }
51851
51852                 nextSelectedID = nodes[i];
51853             }
51854         }
51855
51856         context.perform(action, operation.annotation());
51857
51858         if (nextSelectedID && context.hasEntity(nextSelectedID)) {
51859             context.enter(modeSelect(context, [nextSelectedID]).follow(true));
51860         } else {
51861             context.enter(modeBrowse(context));
51862         }
51863
51864     };
51865
51866
51867     operation.available = function() {
51868         return true;
51869     };
51870
51871
51872     operation.disabled = function() {
51873         var reason;
51874         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
51875             reason = 'too_large';
51876         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
51877             reason = 'connected_to_hidden';
51878         } else if (lodash.some(selectedIDs, protectedMember)) {
51879             reason = 'part_of_relation';
51880         } else if (lodash.some(selectedIDs, incompleteRelation)) {
51881             reason = 'incomplete_relation';
51882         }
51883         return reason;
51884
51885         function incompleteRelation(id) {
51886             var entity = context.entity(id);
51887             return entity.type === 'relation' && !entity.isComplete(context.graph());
51888         }
51889
51890         function protectedMember(id) {
51891             var entity = context.entity(id);
51892             if (entity.type !== 'way') return false;
51893
51894             var parents = context.graph().parentRelations(entity);
51895             for (var i = 0; i < parents.length; i++) {
51896                 var parent = parents[i],
51897                     type = parent.tags.type,
51898                     role = parent.memberById(id).role || 'outer';
51899                 if (type === 'route' || type === 'boundary' || (type === 'multipolygon' && role === 'outer')) {
51900                     return true;
51901                 }
51902             }
51903             return false;
51904         }
51905
51906     };
51907
51908
51909     operation.tooltip = function() {
51910         var disable = operation.disabled();
51911         return disable ?
51912             t('operations.delete.' + disable + '.' + multi) :
51913             t('operations.delete.description' + '.' + multi);
51914     };
51915
51916
51917     operation.annotation = function() {
51918         return selectedIDs.length === 1 ?
51919             t('operations.delete.annotation.' + context.geometry(selectedIDs[0])) :
51920             t('operations.delete.annotation.multiple', { n: selectedIDs.length });
51921     };
51922
51923
51924     operation.id = 'delete';
51925     operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
51926     operation.title = t('operations.delete.title');
51927     operation.behavior = behaviorOperation(context).which(operation);
51928
51929     return operation;
51930 }
51931
51932 function operationDisconnect(selectedIDs, context) {
51933     var vertices = lodash.filter(selectedIDs, function(entityId) {
51934         return context.geometry(entityId) === 'vertex';
51935     });
51936
51937     var entityId = vertices[0],
51938         action = actionDisconnect(entityId);
51939
51940     if (selectedIDs.length > 1) {
51941         action.limitWays(lodash.without(selectedIDs, entityId));
51942     }
51943
51944
51945     var operation = function() {
51946         context.perform(action, operation.annotation());
51947     };
51948
51949
51950     operation.available = function() {
51951         return vertices.length === 1;
51952     };
51953
51954
51955     operation.disabled = function() {
51956         var reason;
51957         if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
51958             reason = 'connected_to_hidden';
51959         }
51960         return action.disabled(context.graph()) || reason;
51961     };
51962
51963
51964     operation.tooltip = function() {
51965         var disable = operation.disabled();
51966         return disable ?
51967             t('operations.disconnect.' + disable) :
51968             t('operations.disconnect.description');
51969     };
51970
51971
51972     operation.annotation = function() {
51973         return t('operations.disconnect.annotation');
51974     };
51975
51976
51977     operation.id = 'disconnect';
51978     operation.keys = [t('operations.disconnect.key')];
51979     operation.title = t('operations.disconnect.title');
51980     operation.behavior = behaviorOperation(context).which(operation);
51981
51982     return operation;
51983 }
51984
51985 function operationMerge(selectedIDs, context) {
51986
51987     function updatePresetTags(oldGraph, newGraph, ids) {
51988         var id = ids[0],
51989             oldEntity = oldGraph.hasEntity(id),
51990             newEntity = newGraph.hasEntity(id);
51991
51992         if (!oldEntity || !newEntity) return;
51993
51994         var oldPreset = context.presets().match(oldEntity, oldGraph),
51995             newPreset = context.presets().match(newEntity, newGraph);
51996
51997         context.replace(actionChangePreset(id, oldPreset, newPreset));
51998     }
51999
52000
52001     var join = actionJoin(selectedIDs),
52002         merge = actionMerge(selectedIDs),
52003         mergePolygon = actionMergePolygon(selectedIDs);
52004
52005
52006     var operation = function() {
52007         var origGraph = context.graph(),
52008             action;
52009
52010         if (!join.disabled(origGraph)) {
52011             action = join;
52012         } else if (!merge.disabled(origGraph)) {
52013             action = merge;
52014         } else {
52015             action = mergePolygon;
52016         }
52017
52018         context.perform(action, operation.annotation());
52019
52020         var ids = selectedIDs.filter(function(id) {
52021             var entity = context.hasEntity(id);
52022             return entity && entity.type !== 'node';
52023         });
52024
52025         // if we merged tags, rematch preset and update tags if necessary (#3851)
52026         if (action === merge) {
52027             updatePresetTags(origGraph, context.graph(), ids);
52028         }
52029
52030         context.enter(modeSelect(context, ids));
52031     };
52032
52033
52034     operation.available = function() {
52035         return selectedIDs.length >= 2;
52036     };
52037
52038
52039     operation.disabled = function() {
52040         return join.disabled(context.graph()) &&
52041             merge.disabled(context.graph()) &&
52042             mergePolygon.disabled(context.graph());
52043     };
52044
52045
52046     operation.tooltip = function() {
52047         var j = join.disabled(context.graph()),
52048             m = merge.disabled(context.graph()),
52049             p = mergePolygon.disabled(context.graph());
52050
52051         if (j === 'restriction' && m && p) {
52052             return t('operations.merge.restriction',
52053                 { relation: context.presets().item('type/restriction').name() });
52054         }
52055
52056         if (p === 'incomplete_relation' && j && m) {
52057             return t('operations.merge.incomplete_relation');
52058         }
52059
52060         if (j && m && p) {
52061             return t('operations.merge.' + j);
52062         }
52063
52064         return t('operations.merge.description');
52065     };
52066
52067
52068     operation.annotation = function() {
52069         return t('operations.merge.annotation', { n: selectedIDs.length });
52070     };
52071
52072
52073     operation.id = 'merge';
52074     operation.keys = [t('operations.merge.key')];
52075     operation.title = t('operations.merge.title');
52076     operation.behavior = behaviorOperation(context).which(operation);
52077
52078     return operation;
52079 }
52080
52081 function operationMove(selectedIDs, context) {
52082     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
52083         extent = selectedIDs.reduce(function(extent, id) {
52084             return extent.extend(context.entity(id).extent(context.graph()));
52085         }, geoExtent$$1());
52086
52087
52088     var operation = function() {
52089         context.enter(modeMove$$1(context, selectedIDs));
52090     };
52091
52092
52093     operation.available = function() {
52094         return selectedIDs.length > 1 ||
52095             context.entity(selectedIDs[0]).type !== 'node';
52096     };
52097
52098
52099     operation.disabled = function() {
52100         var reason;
52101         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
52102             reason = 'too_large';
52103         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52104             reason = 'connected_to_hidden';
52105         } else if (lodash.some(selectedIDs, incompleteRelation)) {
52106             reason = 'incomplete_relation';
52107         }
52108         return reason;
52109
52110         function incompleteRelation(id) {
52111             var entity = context.entity(id);
52112             return entity.type === 'relation' && !entity.isComplete(context.graph());
52113         }
52114     };
52115
52116
52117     operation.tooltip = function() {
52118         var disable = operation.disabled();
52119         return disable ?
52120             t('operations.move.' + disable + '.' + multi) :
52121             t('operations.move.description.' + multi);
52122     };
52123
52124
52125     operation.annotation = function() {
52126         return selectedIDs.length === 1 ?
52127             t('operations.move.annotation.' + context.geometry(selectedIDs[0])) :
52128             t('operations.move.annotation.multiple');
52129     };
52130
52131
52132     operation.id = 'move';
52133     operation.keys = [t('operations.move.key')];
52134     operation.title = t('operations.move.title');
52135     operation.behavior = behaviorOperation(context).which(operation);
52136
52137     return operation;
52138 }
52139
52140 function operationOrthogonalize(selectedIDs, context) {
52141     var entityId = selectedIDs[0],
52142         entity = context.entity(entityId),
52143         extent = entity.extent(context.graph()),
52144         geometry = context.geometry(entityId),
52145         action = actionOrthogonalize(entityId, context.projection);
52146
52147
52148     var operation = function() {
52149         context.perform(action, operation.annotation());
52150     };
52151
52152
52153     operation.available = function() {
52154         return selectedIDs.length === 1 &&
52155             entity.type === 'way' &&
52156             entity.isClosed() &&
52157             lodash.uniq(entity.nodes).length > 2;
52158     };
52159
52160
52161     operation.disabled = function() {
52162         var reason;
52163         if (extent.percentContainedIn(context.extent()) < 0.8) {
52164             reason = 'too_large';
52165         } else if (context.hasHiddenConnections(entityId)) {
52166             reason = 'connected_to_hidden';
52167         }
52168         return action.disabled(context.graph()) || reason;
52169     };
52170
52171
52172     operation.tooltip = function() {
52173         var disable = operation.disabled();
52174         return disable ?
52175             t('operations.orthogonalize.' + disable) :
52176             t('operations.orthogonalize.description.' + geometry);
52177     };
52178
52179
52180     operation.annotation = function() {
52181         return t('operations.orthogonalize.annotation.' + geometry);
52182     };
52183
52184
52185     operation.id = 'orthogonalize';
52186     operation.keys = [t('operations.orthogonalize.key')];
52187     operation.title = t('operations.orthogonalize.title');
52188     operation.behavior = behaviorOperation(context).which(operation);
52189
52190     return operation;
52191 }
52192
52193 function operationReflectShort(selectedIDs, context) {
52194     return operationReflect(selectedIDs, context, 'short');
52195 }
52196
52197
52198 function operationReflectLong(selectedIDs, context) {
52199     return operationReflect(selectedIDs, context, 'long');
52200 }
52201
52202
52203 function operationReflect(selectedIDs, context, axis) {
52204     axis = axis || 'long';
52205     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
52206         extent = selectedIDs.reduce(function(extent, id) {
52207             return extent.extend(context.entity(id).extent(context.graph()));
52208         }, geoExtent$$1());
52209
52210
52211     var operation = function() {
52212         var action = actionReflect(selectedIDs, context.projection)
52213             .useLongAxis(Boolean(axis === 'long'));
52214         context.perform(action, operation.annotation());
52215     };
52216
52217
52218     operation.available = function() {
52219         return lodash.some(selectedIDs, hasArea);
52220
52221         function hasArea(id) {
52222             var entity = context.entity(id);
52223             return (entity.type === 'way' && entity.isClosed()) ||
52224                 (entity.type ==='relation' && entity.isMultipolygon());
52225         }
52226     };
52227
52228
52229     operation.disabled = function() {
52230         var reason;
52231         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
52232             reason = 'too_large';
52233         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52234             reason = 'connected_to_hidden';
52235         } else if (lodash.some(selectedIDs, incompleteRelation)) {
52236             reason = 'incomplete_relation';
52237         }
52238         return reason;
52239
52240         function incompleteRelation(id) {
52241             var entity = context.entity(id);
52242             return entity.type === 'relation' && !entity.isComplete(context.graph());
52243         }
52244     };
52245
52246
52247     operation.tooltip = function() {
52248         var disable = operation.disabled();
52249         return disable ?
52250             t('operations.reflect.' + disable + '.' + multi) :
52251             t('operations.reflect.description.' + axis + '.' + multi);
52252     };
52253
52254
52255     operation.annotation = function() {
52256         return t('operations.reflect.annotation.' + axis + '.' + multi);
52257     };
52258
52259
52260     operation.id = 'reflect-' + axis;
52261     operation.keys = [t('operations.reflect.key.' + axis)];
52262     operation.title = t('operations.reflect.title.' + axis);
52263     operation.behavior = behaviorOperation(context).which(operation);
52264
52265     return operation;
52266 }
52267
52268 function operationReverse(selectedIDs, context) {
52269     var entityId = selectedIDs[0];
52270
52271     var operation = function() {
52272         context.perform(actionReverse(entityId), operation.annotation());
52273     };
52274
52275
52276     operation.available = function() {
52277         return selectedIDs.length === 1 && context.geometry(entityId) === 'line';
52278     };
52279
52280
52281     operation.disabled = function() {
52282         return false;
52283     };
52284
52285
52286     operation.tooltip = function() {
52287         return t('operations.reverse.description');
52288     };
52289
52290
52291     operation.annotation = function() {
52292         return t('operations.reverse.annotation');
52293     };
52294
52295
52296     operation.id = 'reverse';
52297     operation.keys = [t('operations.reverse.key')];
52298     operation.title = t('operations.reverse.title');
52299     operation.behavior = behaviorOperation(context).which(operation);
52300
52301     return operation;
52302 }
52303
52304 function operationRotate(selectedIDs, context) {
52305     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
52306         extent = selectedIDs.reduce(function(extent, id) {
52307             return extent.extend(context.entity(id).extent(context.graph()));
52308         }, geoExtent$$1());
52309
52310
52311     var operation = function() {
52312         context.enter(modeRotate$$1(context, selectedIDs));
52313     };
52314
52315
52316     operation.available = function() {
52317         return lodash.some(selectedIDs, hasArea);
52318
52319         function hasArea(id) {
52320             var entity = context.entity(id);
52321             return (entity.type === 'way' && entity.isClosed()) ||
52322                 (entity.type ==='relation' && entity.isMultipolygon());
52323         }
52324     };
52325
52326
52327     operation.disabled = function() {
52328         var reason;
52329         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
52330             reason = 'too_large';
52331         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52332             reason = 'connected_to_hidden';
52333         } else if (lodash.some(selectedIDs, incompleteRelation)) {
52334             reason = 'incomplete_relation';
52335         }
52336         return reason;
52337
52338         function incompleteRelation(id) {
52339             var entity = context.entity(id);
52340             return entity.type === 'relation' && !entity.isComplete(context.graph());
52341         }
52342     };
52343
52344
52345     operation.tooltip = function() {
52346         var disable = operation.disabled();
52347         return disable ?
52348             t('operations.rotate.' + disable + '.' + multi) :
52349             t('operations.rotate.description.' + multi);
52350     };
52351
52352
52353     operation.annotation = function() {
52354         return selectedIDs.length === 1 ?
52355             t('operations.rotate.annotation.' + context.geometry(selectedIDs[0])) :
52356             t('operations.rotate.annotation.multiple');
52357     };
52358
52359
52360     operation.id = 'rotate';
52361     operation.keys = [t('operations.rotate.key')];
52362     operation.title = t('operations.rotate.title');
52363     operation.behavior = behaviorOperation(context).which(operation);
52364
52365     return operation;
52366 }
52367
52368 function operationSplit(selectedIDs, context) {
52369     var vertices = lodash.filter(selectedIDs, function(entityId) {
52370         return context.geometry(entityId) === 'vertex';
52371     });
52372
52373     var entityId = vertices[0],
52374         action = actionSplit(entityId),
52375         ways = [];
52376
52377     if (vertices.length === 1) {
52378         if (selectedIDs.length > 1) {
52379             action.limitWays(lodash.without(selectedIDs, entityId));
52380         }
52381         ways = action.ways(context.graph());
52382     }
52383
52384
52385     var operation = function() {
52386         var difference = context.perform(action, operation.annotation());
52387         context.enter(modeSelect(context, difference.extantIDs()));
52388     };
52389
52390
52391     operation.available = function() {
52392         return vertices.length === 1;
52393     };
52394
52395
52396     operation.disabled = function() {
52397         var reason;
52398         if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52399             reason = 'connected_to_hidden';
52400         }
52401         return action.disabled(context.graph()) || reason;
52402     };
52403
52404
52405     operation.tooltip = function() {
52406         var disable = operation.disabled();
52407         if (disable) {
52408             return t('operations.split.' + disable);
52409         }
52410         if (ways.length === 1) {
52411             return t('operations.split.description.' + context.geometry(ways[0].id));
52412         } else {
52413             return t('operations.split.description.multiple');
52414         }
52415     };
52416
52417
52418     operation.annotation = function() {
52419         return ways.length === 1 ?
52420             t('operations.split.annotation.' + context.geometry(ways[0].id)) :
52421             t('operations.split.annotation.multiple', { n: ways.length });
52422     };
52423
52424
52425     operation.id = 'split';
52426     operation.keys = [t('operations.split.key')];
52427     operation.title = t('operations.split.title');
52428     operation.behavior = behaviorOperation(context).which(operation);
52429
52430     return operation;
52431 }
52432
52433 function operationStraighten(selectedIDs, context) {
52434     var entityId = selectedIDs[0],
52435         action = actionStraighten(entityId, context.projection);
52436
52437
52438     function operation() {
52439         context.perform(action, operation.annotation());
52440     }
52441
52442
52443     operation.available = function() {
52444         var entity = context.entity(entityId);
52445         return selectedIDs.length === 1 &&
52446             entity.type === 'way' &&
52447             !entity.isClosed() &&
52448             lodash.uniq(entity.nodes).length > 2;
52449     };
52450
52451
52452     operation.disabled = function() {
52453         var reason;
52454         if (context.hasHiddenConnections(entityId)) {
52455             reason = 'connected_to_hidden';
52456         }
52457         return action.disabled(context.graph()) || reason;
52458     };
52459
52460
52461     operation.tooltip = function() {
52462         var disable = operation.disabled();
52463         return disable ?
52464             t('operations.straighten.' + disable) :
52465             t('operations.straighten.description');
52466     };
52467
52468
52469     operation.annotation = function() {
52470         return t('operations.straighten.annotation');
52471     };
52472
52473
52474     operation.id = 'straighten';
52475     operation.keys = [t('operations.straighten.key')];
52476     operation.title = t('operations.straighten.title');
52477     operation.behavior = behaviorOperation(context).which(operation);
52478
52479     return operation;
52480 }
52481
52482
52483
52484 var Operations = Object.freeze({
52485         operationCircularize: operationCircularize,
52486         operationContinue: operationContinue,
52487         operationDelete: operationDelete,
52488         operationDisconnect: operationDisconnect,
52489         operationMerge: operationMerge,
52490         operationMove: operationMove,
52491         operationOrthogonalize: operationOrthogonalize,
52492         operationReflectShort: operationReflectShort,
52493         operationReflectLong: operationReflectLong,
52494         operationReverse: operationReverse,
52495         operationRotate: operationRotate,
52496         operationSplit: operationSplit,
52497         operationStraighten: operationStraighten
52498 });
52499
52500 function modeMove$$1(context, entityIDs, baseGraph) {
52501     var mode = {
52502         id: 'move',
52503         button: 'browse'
52504     };
52505
52506     var keybinding = d3keybinding('move'),
52507         behaviors = [
52508             behaviorEdit(context),
52509             operationCircularize(entityIDs, context).behavior,
52510             operationDelete(entityIDs, context).behavior,
52511             operationOrthogonalize(entityIDs, context).behavior,
52512             operationReflectLong(entityIDs, context).behavior,
52513             operationReflectShort(entityIDs, context).behavior,
52514             operationRotate(entityIDs, context).behavior
52515         ],
52516         annotation = entityIDs.length === 1 ?
52517             t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
52518             t('operations.move.annotation.multiple'),
52519         prevGraph,
52520         cache,
52521         origin,
52522         nudgeInterval;
52523
52524
52525     function vecSub(a, b) {
52526         return [a[0] - b[0], a[1] - b[1]];
52527     }
52528
52529
52530     function edge(point, size) {
52531         var pad = [80, 20, 50, 20],   // top, right, bottom, left
52532             x = 0,
52533             y = 0;
52534
52535         if (point[0] > size[0] - pad[1])
52536             x = -10;
52537         if (point[0] < pad[3])
52538             x = 10;
52539         if (point[1] > size[1] - pad[2])
52540             y = -10;
52541         if (point[1] < pad[0])
52542             y = 10;
52543
52544         if (x || y) {
52545             return [x, y];
52546         } else {
52547             return null;
52548         }
52549     }
52550
52551
52552     function doMove(nudge) {
52553         nudge = nudge || [0, 0];
52554
52555         var fn;
52556         if (prevGraph !== context.graph()) {
52557             cache = {};
52558             origin = context.map().mouseCoordinates();
52559             fn = context.perform;
52560         } else {
52561             fn = context.overwrite;
52562         }
52563
52564         var currMouse = context.mouse(),
52565             origMouse = context.projection(origin),
52566             delta = vecSub(vecSub(currMouse, origMouse), nudge);
52567
52568         fn(actionMove(entityIDs, delta, context.projection, cache), annotation);
52569         prevGraph = context.graph();
52570     }
52571
52572
52573     function startNudge(nudge) {
52574         if (nudgeInterval) window.clearInterval(nudgeInterval);
52575         nudgeInterval = window.setInterval(function() {
52576             context.pan(nudge);
52577             doMove(nudge);
52578         }, 50);
52579     }
52580
52581
52582     function stopNudge() {
52583         if (nudgeInterval) {
52584             window.clearInterval(nudgeInterval);
52585             nudgeInterval = null;
52586         }
52587     }
52588
52589
52590     function move() {
52591         doMove();
52592         var nudge = edge(context.mouse(), context.map().dimensions());
52593         if (nudge) {
52594             startNudge(nudge);
52595         } else {
52596             stopNudge();
52597         }
52598     }
52599
52600
52601     function finish() {
52602         event.stopPropagation();
52603         context.enter(modeSelect(context, entityIDs));
52604         stopNudge();
52605     }
52606
52607
52608     function cancel() {
52609         if (baseGraph) {
52610             while (context.graph() !== baseGraph) context.pop();
52611             context.enter(modeBrowse(context));
52612         } else {
52613             context.pop();
52614             context.enter(modeSelect(context, entityIDs));
52615         }
52616         stopNudge();
52617     }
52618
52619
52620     function undone() {
52621         context.enter(modeBrowse(context));
52622     }
52623
52624
52625     mode.enter = function() {
52626         origin = context.map().mouseCoordinates();
52627         prevGraph = null;
52628         cache = {};
52629
52630         behaviors.forEach(function(behavior) {
52631             context.install(behavior);
52632         });
52633
52634         context.surface()
52635             .on('mousemove.move', move)
52636             .on('click.move', finish);
52637
52638         context.history()
52639             .on('undone.move', undone);
52640
52641         keybinding
52642             .on('⎋', cancel)
52643             .on('↩', finish);
52644
52645         select(document)
52646             .call(keybinding);
52647     };
52648
52649
52650     mode.exit = function() {
52651         stopNudge();
52652
52653         behaviors.forEach(function(behavior) {
52654             context.uninstall(behavior);
52655         });
52656
52657         context.surface()
52658             .on('mousemove.move', null)
52659             .on('click.move', null);
52660
52661         context.history()
52662             .on('undone.move', null);
52663
52664         keybinding.off();
52665     };
52666
52667
52668     return mode;
52669 }
52670
52671 function modeRotate$$1(context, entityIDs) {
52672     var mode = {
52673         id: 'rotate',
52674         button: 'browse'
52675     };
52676
52677     var keybinding = d3keybinding('rotate'),
52678         behaviors = [
52679             behaviorEdit(context),
52680             operationCircularize(entityIDs, context).behavior,
52681             operationDelete(entityIDs, context).behavior,
52682             operationMove(entityIDs, context).behavior,
52683             operationOrthogonalize(entityIDs, context).behavior,
52684             operationReflectLong(entityIDs, context).behavior,
52685             operationReflectShort(entityIDs, context).behavior
52686         ],
52687         annotation = entityIDs.length === 1 ?
52688             t('operations.rotate.annotation.' + context.geometry(entityIDs[0])) :
52689             t('operations.rotate.annotation.multiple'),
52690         prevGraph,
52691         prevAngle,
52692         prevTransform,
52693         pivot;
52694
52695
52696     function doRotate() {
52697         var fn;
52698         if (context.graph() !== prevGraph) {
52699             fn = context.perform;
52700         } else {
52701             fn = context.replace;
52702         }
52703
52704         // projection changed, recalculate pivot
52705         var projection = context.projection;
52706         var currTransform = projection.transform();
52707         if (!prevTransform ||
52708             currTransform.k !== prevTransform.k ||
52709             currTransform.x !== prevTransform.x ||
52710             currTransform.y !== prevTransform.y) {
52711
52712             var nodes = utilGetAllNodes(entityIDs, context.graph()),
52713                 points = nodes.map(function(n) { return projection(n.loc); });
52714
52715             pivot = d3polygonCentroid(d3polygonHull(points));
52716             prevAngle = undefined;
52717         }
52718
52719
52720         var currMouse = context.mouse(),
52721             currAngle = Math.atan2(currMouse[1] - pivot[1], currMouse[0] - pivot[0]);
52722
52723         if (typeof prevAngle === 'undefined') prevAngle = currAngle;
52724         var delta = currAngle - prevAngle;
52725
52726         fn(actionRotate(entityIDs, pivot, delta, projection), annotation);
52727
52728         prevTransform = currTransform;
52729         prevAngle = currAngle;
52730         prevGraph = context.graph();
52731     }
52732
52733
52734     function finish() {
52735         event.stopPropagation();
52736         context.enter(modeSelect(context, entityIDs));
52737     }
52738
52739
52740     function cancel() {
52741         context.pop();
52742         context.enter(modeSelect(context, entityIDs));
52743     }
52744
52745
52746     function undone() {
52747         context.enter(modeBrowse(context));
52748     }
52749
52750
52751     mode.enter = function() {
52752         behaviors.forEach(function(behavior) {
52753             context.install(behavior);
52754         });
52755
52756         context.surface()
52757             .on('mousemove.rotate', doRotate)
52758             .on('click.rotate', finish);
52759
52760         context.history()
52761             .on('undone.rotate', undone);
52762
52763         keybinding
52764             .on('⎋', cancel)
52765             .on('↩', finish);
52766
52767         select(document)
52768             .call(keybinding);
52769     };
52770
52771
52772     mode.exit = function() {
52773         behaviors.forEach(function(behavior) {
52774             context.uninstall(behavior);
52775         });
52776
52777         context.surface()
52778             .on('mousemove.rotate', null)
52779             .on('click.rotate', null);
52780
52781         context.history()
52782             .on('undone.rotate', null);
52783
52784         keybinding.off();
52785     };
52786
52787
52788     return mode;
52789 }
52790
52791 function modeSave$$1(context) {
52792     var mode = {
52793         id: 'save'
52794     };
52795
52796     var commit = uiCommit(context)
52797             .on('cancel', cancel)
52798             .on('save', save);
52799
52800
52801     function cancel() {
52802         context.enter(modeBrowse(context));
52803     }
52804
52805
52806     function save(changeset, tryAgain) {
52807
52808         var loading = uiLoading(context).message(t('save.uploading')).blocking(true),
52809             history = context.history(),
52810             origChanges = history.changes(actionDiscardTags(history.difference())),
52811             localGraph = context.graph(),
52812             remoteGraph = coreGraph$$1(history.base(), true),
52813             modified = lodash.filter(history.difference().summary(), {changeType: 'modified'}),
52814             toCheck = lodash.map(lodash.map(modified, 'entity'), 'id'),
52815             toLoad = withChildNodes(toCheck, localGraph),
52816             conflicts = [],
52817             errors = [];
52818
52819         if (!tryAgain) {
52820             history.perform(actionNoop());  // checkpoint
52821         }
52822
52823         context.container().call(loading);
52824
52825         if (toCheck.length) {
52826             context.connection().loadMultiple(toLoad, loaded);
52827         } else {
52828             upload();
52829         }
52830
52831
52832         function withChildNodes(ids, graph) {
52833             return lodash.uniq(lodash.reduce(ids, function(result, id) {
52834                 var entity = graph.entity(id);
52835                 if (entity.type === 'way') {
52836                     try {
52837                         var cn = graph.childNodes(entity);
52838                         result.push.apply(result, lodash.map(lodash.filter(cn, 'version'), 'id'));
52839                     } catch (err) {
52840                         /* eslint-disable no-console */
52841                         if (typeof console !== 'undefined') console.error(err);
52842                         /* eslint-enable no-console */
52843                     }
52844                 }
52845                 return result;
52846             }, lodash.clone(ids)));
52847         }
52848
52849
52850         // Reload modified entities into an alternate graph and check for conflicts..
52851         function loaded(err, result) {
52852             if (errors.length) return;
52853
52854             if (err) {
52855                 errors.push({
52856                     msg: err.responseText,
52857                     details: [ t('save.status_code', { code: err.status }) ]
52858                 });
52859                 showErrors();
52860
52861             } else {
52862                 var loadMore = [];
52863                 lodash.each(result.data, function(entity) {
52864                     remoteGraph.replace(entity);
52865                     toLoad = lodash.without(toLoad, entity.id);
52866
52867                     // Because loadMultiple doesn't download /full like loadEntity,
52868                     // need to also load children that aren't already being checked..
52869                     if (!entity.visible) return;
52870                     if (entity.type === 'way') {
52871                         loadMore.push.apply(loadMore,
52872                             lodash.difference(entity.nodes, toCheck, toLoad, loadMore));
52873                     } else if (entity.type === 'relation' && entity.isMultipolygon()) {
52874                         loadMore.push.apply(loadMore,
52875                             lodash.difference(lodash.map(entity.members, 'id'), toCheck, toLoad, loadMore));
52876                     }
52877                 });
52878
52879                 if (loadMore.length) {
52880                     toLoad.push.apply(toLoad, loadMore);
52881                     context.connection().loadMultiple(loadMore, loaded);
52882                 }
52883
52884                 if (!toLoad.length) {
52885                     checkConflicts();
52886                 }
52887             }
52888         }
52889
52890
52891         function checkConflicts() {
52892             function choice(id, text$$1, action) {
52893                 return { id: id, text: text$$1, action: function() { history.replace(action); } };
52894             }
52895             function formatUser(d) {
52896                 return '<a href="' + context.connection().userURL(d) + '" target="_blank">' + d + '</a>';
52897             }
52898             function entityName(entity) {
52899                 return utilDisplayName(entity) || (utilDisplayType(entity.id) + ' ' + entity.id);
52900             }
52901
52902             function compareVersions(local$$1, remote) {
52903                 if (local$$1.version !== remote.version) return false;
52904
52905                 if (local$$1.type === 'way') {
52906                     var children = lodash.union(local$$1.nodes, remote.nodes);
52907
52908                     for (var i = 0; i < children.length; i++) {
52909                         var a = localGraph.hasEntity(children[i]),
52910                             b = remoteGraph.hasEntity(children[i]);
52911
52912                         if (a && b && a.version !== b.version) return false;
52913                     }
52914                 }
52915
52916                 return true;
52917             }
52918
52919             lodash.each(toCheck, function(id) {
52920                 var local$$1 = localGraph.entity(id),
52921                     remote = remoteGraph.entity(id);
52922
52923                 if (compareVersions(local$$1, remote)) return;
52924
52925                 var action = actionMergeRemoteChanges,
52926                     merge$$1 = action(id, localGraph, remoteGraph, formatUser);
52927
52928                 history.replace(merge$$1);
52929
52930                 var mergeConflicts = merge$$1.conflicts();
52931                 if (!mergeConflicts.length) return;  // merged safely
52932
52933                 var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
52934                     forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
52935                     keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
52936                     keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
52937
52938                 conflicts.push({
52939                     id: id,
52940                     name: entityName(local$$1),
52941                     details: mergeConflicts,
52942                     chosen: 1,
52943                     choices: [
52944                         choice(id, keepMine, forceLocal),
52945                         choice(id, keepTheirs, forceRemote)
52946                     ]
52947                 });
52948             });
52949
52950             upload();
52951         }
52952
52953
52954         function upload() {
52955             if (conflicts.length) {
52956                 conflicts.sort(function(a,b) { return b.id.localeCompare(a.id); });
52957                 showConflicts();
52958             } else if (errors.length) {
52959                 showErrors();
52960             } else {
52961                 var changes = history.changes(actionDiscardTags(history.difference()));
52962                 if (changes.modified.length || changes.created.length || changes.deleted.length) {
52963                     context.connection().putChangeset(changeset, changes, uploadCallback);
52964                 } else {        // changes were insignificant or reverted by user
52965                     select('.inspector-wrap *').remove();
52966                     loading.close();
52967                     context.flush();
52968                     cancel();
52969                 }
52970             }
52971         }
52972
52973
52974         function uploadCallback(err, changeset) {
52975             if (err) {
52976                 errors.push({
52977                     msg: err.responseText,
52978                     details: [ t('save.status_code', { code: err.status }) ]
52979                 });
52980                 showErrors();
52981             } else {
52982                 history.clearSaved();
52983                 success(changeset);
52984                 // Add delay to allow for postgres replication #1646 #2678
52985                 window.setTimeout(function() {
52986                     select('.inspector-wrap *').remove();
52987                     loading.close();
52988                     context.flush();
52989                 }, 2500);
52990             }
52991         }
52992
52993
52994         function showConflicts() {
52995             var selection$$1 = context.container()
52996                 .select('#sidebar')
52997                 .append('div')
52998                 .attr('class','sidebar-component');
52999
53000             loading.close();
53001
53002             selection$$1.call(uiConflicts(context)
53003                 .list(conflicts)
53004                 .on('download', function() {
53005                     var data = JXON.stringify(changeset.update({ id: 'CHANGEME' }).osmChangeJXON(origChanges)),
53006                         win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank');
53007                     win.focus();
53008                 })
53009                 .on('cancel', function() {
53010                     history.pop();
53011                     selection$$1.remove();
53012                 })
53013                 .on('save', function() {
53014                     for (var i = 0; i < conflicts.length; i++) {
53015                         if (conflicts[i].chosen === 1) {  // user chose "keep theirs"
53016                             var entity = context.hasEntity(conflicts[i].id);
53017                             if (entity && entity.type === 'way') {
53018                                 var children = lodash.uniq(entity.nodes);
53019                                 for (var j = 0; j < children.length; j++) {
53020                                     history.replace(actionRevert(children[j]));
53021                                 }
53022                             }
53023                             history.replace(actionRevert(conflicts[i].id));
53024                         }
53025                     }
53026
53027                     selection$$1.remove();
53028                     save(changeset, true);
53029                 })
53030             );
53031         }
53032
53033
53034         function showErrors() {
53035             var selection$$1 = uiConfirm(context.container());
53036
53037             history.pop();
53038             loading.close();
53039
53040             selection$$1
53041                 .select('.modal-section.header')
53042                 .append('h3')
53043                 .text(t('save.error'));
53044
53045             addErrors(selection$$1, errors);
53046             selection$$1.okButton();
53047         }
53048
53049
53050         function addErrors(selection$$1, data) {
53051             var message = selection$$1
53052                 .select('.modal-section.message-text');
53053
53054             var items = message
53055                 .selectAll('.error-container')
53056                 .data(data);
53057
53058             var enter = items.enter()
53059                 .append('div')
53060                 .attr('class', 'error-container');
53061
53062             enter
53063                 .append('a')
53064                 .attr('class', 'error-description')
53065                 .attr('href', '#')
53066                 .classed('hide-toggle', true)
53067                 .text(function(d) { return d.msg || t('save.unknown_error_details'); })
53068                 .on('click', function() {
53069                     var error = select(this),
53070                         detail = select(this.nextElementSibling),
53071                         exp = error.classed('expanded');
53072
53073                     detail.style('display', exp ? 'none' : 'block');
53074                     error.classed('expanded', !exp);
53075
53076                     event.preventDefault();
53077                 });
53078
53079             var details = enter
53080                 .append('div')
53081                 .attr('class', 'error-detail-container')
53082                 .style('display', 'none');
53083
53084             details
53085                 .append('ul')
53086                 .attr('class', 'error-detail-list')
53087                 .selectAll('li')
53088                 .data(function(d) { return d.details || []; })
53089                 .enter()
53090                 .append('li')
53091                 .attr('class', 'error-detail-item')
53092                 .text(function(d) { return d; });
53093
53094             items.exit()
53095                 .remove();
53096         }
53097
53098     }
53099
53100
53101     function success(changeset) {
53102         commit.reset();
53103         context.enter(modeBrowse(context)
53104             .sidebar(uiSuccess(context)
53105                 .changeset(changeset)
53106                 .on('cancel', function() {
53107                     context.ui().sidebar.hide();
53108                 })
53109             )
53110         );
53111     }
53112
53113
53114     mode.enter = function() {
53115         function done() {
53116             context.ui().sidebar.show(commit);
53117         }
53118
53119         context.container().selectAll('#content')
53120             .attr('class', 'inactive');
53121
53122         if (context.connection().authenticated()) {
53123             done();
53124         } else {
53125             context.connection().authenticate(function(err) {
53126                 if (err) {
53127                     cancel();
53128                 } else {
53129                     done();
53130                 }
53131             });
53132         }
53133     };
53134
53135
53136     mode.exit = function() {
53137         context.container().selectAll('#content')
53138             .attr('class', 'active');
53139
53140         context.ui().sidebar.hide();
53141     };
53142
53143     return mode;
53144 }
53145
53146 // Translate a MacOS key command into the appropriate Windows/Linux equivalent.
53147 // For example, ⌘Z -> Ctrl+Z
53148 function uiCmd(code) {
53149     var detected = utilDetect();
53150
53151     if (detected.os === 'mac') {
53152         return code;
53153     }
53154
53155     if (detected.os === 'win') {
53156         if (code === '⌘⇧Z') return 'Ctrl+Y';
53157     }
53158
53159     var result = '',
53160         replacements = {
53161             '⌘': 'Ctrl',
53162             '⇧': 'Shift',
53163             '⌥': 'Alt',
53164             '⌫': 'Backspace',
53165             '⌦': 'Delete'
53166         };
53167
53168     for (var i = 0; i < code.length; i++) {
53169         if (code[i] in replacements) {
53170             result += replacements[code[i]] + (i < code.length - 1 ? '+' : '');
53171         } else {
53172             result += code[i];
53173         }
53174     }
53175
53176     return result;
53177 }
53178
53179 // deprecation warning - Radial Menu to be removed in iD v3
53180 var relatedParent;
53181
53182
53183 function modeSelect(context, selectedIDs) {
53184     var mode = {
53185         id: 'select',
53186         button: 'browse'
53187     };
53188
53189     var keybinding = d3keybinding('select'),
53190         timeout$$1 = null,
53191         behaviors = [
53192             behaviorCopy(context),
53193             behaviorPaste(context),
53194             behaviorBreathe(context),
53195             behaviorHover(context),
53196             behaviorSelect(context),
53197             behaviorLasso(context),
53198             modeDragNode$$1(context).selectedIDs(selectedIDs).behavior
53199         ],
53200         inspector,
53201         editMenu,
53202         newFeature = false,
53203         suppressMenu = true,
53204         follow = false;
53205
53206
53207     var wrap = context.container()
53208         .select('.inspector-wrap');
53209
53210
53211     function singular() {
53212         if (selectedIDs.length === 1) {
53213             return context.hasEntity(selectedIDs[0]);
53214         }
53215     }
53216
53217
53218     function checkSelectedIDs() {
53219         var ids = [];
53220         if (Array.isArray(selectedIDs)) {
53221             ids = selectedIDs.filter(function(id) {
53222                 return context.hasEntity(id);
53223             });
53224         }
53225
53226         if (ids.length) {
53227             selectedIDs = ids;
53228         } else {
53229             context.enter(modeBrowse(context));
53230         }
53231         return !!ids.length;
53232     }
53233
53234
53235     // find the common parent ways for nextVertex, previousVertex
53236     function commonParents() {
53237         var graph = context.graph(),
53238             commonParents = [];
53239
53240         for (var i = 0; i < selectedIDs.length; i++) {
53241             var entity = context.hasEntity(selectedIDs[i]);
53242             if (!entity || entity.geometry(graph) !== 'vertex') {
53243                 return [];  // selection includes some not vertexes
53244             }
53245
53246             var currParents = lodash.map(graph.parentWays(entity), 'id');
53247             if (!commonParents.length) {
53248                 commonParents = currParents;
53249                 continue;
53250             }
53251
53252             commonParents = lodash.intersection(commonParents, currParents);
53253             if (!commonParents.length) {
53254                 return [];
53255             }
53256         }
53257
53258         return commonParents;
53259     }
53260
53261
53262     function singularParent() {
53263         var parents = commonParents();
53264         if (!parents || parents.length === 0) {
53265             relatedParent = null;
53266             return null;
53267         }
53268
53269         // relatedParent is used when we visit a vertex with multiple
53270         // parents, and we want to remember which parent line we started on.
53271
53272         if (parents.length === 1) {
53273             relatedParent = parents[0];  // remember this parent for later
53274             return relatedParent;
53275         }
53276
53277         if (parents.indexOf(relatedParent) !== -1) {
53278             return relatedParent;   // prefer the previously seen parent
53279         }
53280
53281         return parents[0];
53282     }
53283
53284
53285     function closeMenu() {
53286         if (editMenu) {
53287             context.surface().call(editMenu.close);
53288         }
53289     }
53290
53291
53292     function positionMenu() {
53293         if (!editMenu) { return; }
53294
53295         var entity = singular();
53296         if (entity && context.geometry(entity.id) === 'relation') {
53297             suppressMenu = true;
53298         } else {
53299             var point = context.mouse(),
53300                 viewport = geoExtent$$1(context.projection.clipExtent()).polygon();
53301
53302             if (point && geoPointInPolygon(point, viewport)) {
53303                 editMenu.center(point);
53304             } else {
53305                 suppressMenu = true;
53306             }
53307         }
53308     }
53309
53310
53311     function showMenu() {
53312         closeMenu();
53313         if (editMenu) {
53314             context.surface().call(editMenu);
53315         }
53316     }
53317
53318
53319     function toggleMenu() {
53320         // deprecation warning - Radial Menu to be removed in iD v3
53321         if (select('.edit-menu, .radial-menu').empty()) {
53322             positionMenu();
53323             showMenu();
53324         } else {
53325             closeMenu();
53326         }
53327     }
53328
53329
53330     mode.selectedIDs = function() {
53331         return selectedIDs;
53332     };
53333
53334
53335     mode.reselect = function() {
53336         if (!checkSelectedIDs()) return;
53337
53338         var surfaceNode = context.surface().node();
53339         if (surfaceNode.focus) {   // FF doesn't support it
53340             surfaceNode.focus();
53341         }
53342
53343         positionMenu();
53344         if (!suppressMenu) {
53345             showMenu();
53346         }
53347     };
53348
53349
53350     mode.newFeature = function(_) {
53351         if (!arguments.length) return newFeature;
53352         newFeature = _;
53353         return mode;
53354     };
53355
53356
53357     mode.suppressMenu = function(_) {
53358         if (!arguments.length) return suppressMenu;
53359         suppressMenu = _;
53360         return mode;
53361     };
53362
53363
53364     mode.follow = function(_) {
53365         if (!arguments.length) return follow;
53366         follow = _;
53367         return mode;
53368     };
53369
53370
53371     mode.enter = function() {
53372
53373         function update() {
53374             closeMenu();
53375             checkSelectedIDs();
53376         }
53377
53378
53379         function dblclick() {
53380             var target = select(event.target),
53381                 datum = target.datum();
53382
53383             if (datum instanceof osmWay && !target.classed('fill')) {
53384                 var choice = geoChooseEdge(context.childNodes(datum), context.mouse(), context.projection),
53385                     prev = datum.nodes[choice.index - 1],
53386                     next = datum.nodes[choice.index];
53387
53388                 context.perform(
53389                     actionAddMidpoint({loc: choice.loc, edge: [prev, next]}, osmNode()),
53390                     t('operations.add.annotation.vertex')
53391                 );
53392
53393                 event.preventDefault();
53394                 event.stopPropagation();
53395
53396             } else if (datum.type === 'midpoint') {
53397                 context.perform(
53398                     actionAddMidpoint({loc: datum.loc, edge: datum.edge}, osmNode()),
53399                     t('operations.add.annotation.vertex'));
53400
53401                 event.preventDefault();
53402                 event.stopPropagation();
53403             }
53404         }
53405
53406
53407         function selectElements(drawn) {
53408             if (!checkSelectedIDs()) return;
53409
53410             var surface = context.surface(),
53411                 entity = singular();
53412
53413             if (entity && context.geometry(entity.id) === 'relation') {
53414                 suppressMenu = true;
53415                 return;
53416             }
53417
53418             surface.selectAll('.related')
53419                 .classed('related', false);
53420
53421             singularParent();
53422             if (relatedParent) {
53423                 surface.selectAll(utilEntitySelector([relatedParent]))
53424                     .classed('related', true);
53425             }
53426
53427             var selection$$1 = context.surface()
53428                 .selectAll(utilEntityOrMemberSelector(selectedIDs, context.graph()));
53429
53430             if (selection$$1.empty()) {
53431                 // Return to browse mode if selected DOM elements have
53432                 // disappeared because the user moved them out of view..
53433                 var source = event && event.type === 'zoom' && event.sourceEvent;
53434                 if (drawn && source && (source.type === 'mousemove' || source.type === 'touchmove')) {
53435                     context.enter(modeBrowse(context));
53436                 }
53437             } else {
53438                 selection$$1
53439                     .classed('selected', true);
53440             }
53441         }
53442
53443
53444         function esc() {
53445             context.enter(modeBrowse(context));
53446         }
53447
53448
53449         function firstVertex() {
53450             event.preventDefault();
53451             var parent = singularParent();
53452             if (parent) {
53453                 var way = context.entity(parent);
53454                 context.enter(
53455                     modeSelect(context, [way.first()]).follow(true)
53456                 );
53457             }
53458         }
53459
53460
53461         function lastVertex() {
53462             event.preventDefault();
53463             var parent = singularParent();
53464             if (parent) {
53465                 var way = context.entity(parent);
53466                 context.enter(
53467                     modeSelect(context, [way.last()]).follow(true)
53468                 );
53469             }
53470         }
53471
53472
53473         function previousVertex() {
53474             event.preventDefault();
53475             var parent = singularParent();
53476             if (!parent) return;
53477
53478             var way = context.entity(parent),
53479                 length = way.nodes.length,
53480                 curr = way.nodes.indexOf(selectedIDs[0]),
53481                 index = -1;
53482
53483             if (curr > 0) {
53484                 index = curr - 1;
53485             } else if (way.isClosed()) {
53486                 index = length - 2;
53487             }
53488
53489             if (index !== -1) {
53490                 context.enter(
53491                     modeSelect(context, [way.nodes[index]]).follow(true)
53492                 );
53493             }
53494         }
53495
53496
53497         function nextVertex() {
53498             event.preventDefault();
53499             var parent = singularParent();
53500             if (!parent) return;
53501
53502             var way = context.entity(parent),
53503                 length = way.nodes.length,
53504                 curr = way.nodes.indexOf(selectedIDs[0]),
53505                 index = -1;
53506
53507             if (curr < length - 1) {
53508                 index = curr + 1;
53509             } else if (way.isClosed()) {
53510                 index = 0;
53511             }
53512
53513             if (index !== -1) {
53514                 context.enter(
53515                     modeSelect(context, [way.nodes[index]]).follow(true)
53516                 );
53517             }
53518         }
53519
53520
53521         function nextParent() {
53522             event.preventDefault();
53523             var parents = lodash.uniq(commonParents());
53524             if (!parents || parents.length < 2) return;
53525
53526             var index = parents.indexOf(relatedParent);
53527             if (index < 0 || index > parents.length - 2) {
53528                 relatedParent = parents[0];
53529             } else {
53530                 relatedParent = parents[index + 1];
53531             }
53532
53533             var surface = context.surface();
53534             surface.selectAll('.related')
53535                 .classed('related', false);
53536
53537             if (relatedParent) {
53538                 surface.selectAll(utilEntitySelector([relatedParent]))
53539                     .classed('related', true);
53540             }
53541         }
53542
53543
53544         if (!checkSelectedIDs()) return;
53545
53546         var operations = lodash.without(values(Operations), operationDelete)
53547                 .map(function(o) { return o(selectedIDs, context); })
53548                 .filter(function(o) { return o.available(); });
53549
53550         // deprecation warning - Radial Menu to be removed in iD v3
53551         var isRadialMenu = context.storage('edit-menu-style') === 'radial';
53552         if (isRadialMenu) {
53553             operations = operations.slice(0,7);
53554             operations.unshift(operationDelete(selectedIDs, context));
53555         } else {
53556             operations.push(operationDelete(selectedIDs, context));
53557         }
53558
53559         operations.forEach(function(operation) {
53560             if (operation.behavior) {
53561                 behaviors.push(operation.behavior);
53562             }
53563         });
53564
53565         behaviors.forEach(function(behavior) {
53566             context.install(behavior);
53567         });
53568
53569         keybinding
53570             .on(['[','pgup'], previousVertex)
53571             .on([']', 'pgdown'], nextVertex)
53572             .on([uiCmd('⌘['), 'home'], firstVertex)
53573             .on([uiCmd('⌘]'), 'end'], lastVertex)
53574             .on(['\\', 'pause'], nextParent)
53575             .on('⎋', esc, true)
53576             .on('space', toggleMenu);
53577
53578         select(document)
53579             .call(keybinding);
53580
53581
53582         // deprecation warning - Radial Menu to be removed in iD v3
53583         editMenu = isRadialMenu
53584             ? uiRadialMenu(context, operations)
53585             : uiEditMenu(context, operations);
53586
53587         context.ui().sidebar
53588             .select(singular() ? singular().id : null, newFeature);
53589
53590         context.history()
53591             .on('undone.select', update)
53592             .on('redone.select', update);
53593
53594         context.map()
53595             .on('move.select', closeMenu)
53596             .on('drawn.select', selectElements);
53597
53598         context.surface()
53599             .on('dblclick.select', dblclick);
53600
53601
53602         selectElements();
53603
53604         if (selectedIDs.length > 1) {
53605             var entities = uiSelectionList(context, selectedIDs);
53606             context.ui().sidebar.show(entities);
53607         }
53608
53609         if (follow) {
53610             var extent$$1 = geoExtent$$1(),
53611                 graph = context.graph();
53612             selectedIDs.forEach(function(id) {
53613                 var entity = context.entity(id);
53614                 extent$$1._extend(entity.extent(graph));
53615             });
53616
53617             var loc = extent$$1.center();
53618             context.map().centerEase(loc);
53619         } else if (singular() && singular().type === 'way') {
53620             context.map().pan([0,0]);  // full redraw, to adjust z-sorting #2914
53621         }
53622
53623         timeout$$1 = window.setTimeout(function() {
53624             positionMenu();
53625             if (!suppressMenu) {
53626                 showMenu();
53627             }
53628         }, 270);  /* after any centerEase completes */
53629
53630     };
53631
53632
53633     mode.exit = function() {
53634         if (timeout$$1) window.clearTimeout(timeout$$1);
53635
53636         if (inspector) wrap.call(inspector.close);
53637
53638         behaviors.forEach(function(behavior) {
53639             context.uninstall(behavior);
53640         });
53641
53642         keybinding.off();
53643         closeMenu();
53644         editMenu = undefined;
53645
53646         context.history()
53647             .on('undone.select', null)
53648             .on('redone.select', null);
53649
53650         var surface = context.surface();
53651
53652         surface
53653             .on('dblclick.select', null);
53654
53655         surface
53656             .selectAll('.selected')
53657             .classed('selected', false);
53658
53659         surface
53660             .selectAll('.related')
53661             .classed('related', false);
53662
53663         context.map().on('drawn.select', null);
53664         context.ui().sidebar.hide();
53665     };
53666
53667
53668     return mode;
53669 }
53670
53671 function uiAccount(context) {
53672     var connection = context.connection();
53673
53674
53675     function update(selection$$1) {
53676         if (!connection.authenticated()) {
53677             selection$$1.selectAll('#userLink, #logoutLink')
53678                 .classed('hide', true);
53679             return;
53680         }
53681
53682         connection.userDetails(function(err, details) {
53683             var userLink = selection$$1.select('#userLink'),
53684                 logoutLink = selection$$1.select('#logoutLink');
53685
53686             userLink.html('');
53687             logoutLink.html('');
53688
53689             if (err) return;
53690
53691             selection$$1.selectAll('#userLink, #logoutLink')
53692                 .classed('hide', false);
53693
53694             // Link
53695             userLink.append('a')
53696                 .attr('href', connection.userURL(details.display_name))
53697                 .attr('target', '_blank');
53698
53699             // Add thumbnail or dont
53700             if (details.image_url) {
53701                 userLink.append('img')
53702                     .attr('class', 'icon pre-text user-icon')
53703                     .attr('src', details.image_url);
53704             } else {
53705                 userLink
53706                     .call(svgIcon('#icon-avatar', 'pre-text light'));
53707             }
53708
53709             // Add user name
53710             userLink.append('span')
53711                 .attr('class', 'label')
53712                 .text(details.display_name);
53713
53714             logoutLink.append('a')
53715                 .attr('class', 'logout')
53716                 .attr('href', '#')
53717                 .text(t('logout'))
53718                 .on('click.logout', function() {
53719                     event.preventDefault();
53720                     connection.logout();
53721                 });
53722         });
53723     }
53724
53725
53726     return function(selection$$1) {
53727         selection$$1.append('li')
53728             .attr('id', 'logoutLink')
53729             .classed('hide', true);
53730
53731         selection$$1.append('li')
53732             .attr('id', 'userLink')
53733             .classed('hide', true);
53734
53735         connection
53736             .on('change.account', function() { update(selection$$1); });
53737
53738         update(selection$$1);
53739     };
53740 }
53741
53742 function uiAttribution(context) {
53743     var selection$$1;
53744
53745
53746     function attribution(data, klass) {
53747         var div = selection$$1.selectAll('.' + klass)
53748             .data([0]);
53749
53750         div = div.enter()
53751             .append('div')
53752             .attr('class', klass)
53753             .merge(div);
53754
53755
53756         var background = div.selectAll('.attribution')
53757             .data(data, function(d) { return d.name(); });
53758
53759         background.exit()
53760             .remove();
53761
53762         background = background.enter()
53763             .append('span')
53764             .attr('class', 'attribution')
53765             .each(function(d) {
53766                 if (d.terms_html) {
53767                     select(this)
53768                         .html(d.terms_html);
53769                     return;
53770                 }
53771
53772                 var source = d.terms_text || d.id || d.name();
53773
53774                 if (d.logo) {
53775                     source = '<img class="source-image" src="' + context.imagePath(d.logo) + '">';
53776                 }
53777
53778                 if (d.terms_url) {
53779                     select(this)
53780                         .append('a')
53781                         .attr('href', d.terms_url)
53782                         .attr('target', '_blank')
53783                         .html(source);
53784                 } else {
53785                     select(this)
53786                         .text(source);
53787                 }
53788             })
53789             .merge(background);
53790
53791
53792         var copyright = background.selectAll('.copyright-notice')
53793             .data(function(d) {
53794                 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
53795                 return notice ? [notice] : [];
53796             });
53797
53798         copyright.exit()
53799             .remove();
53800
53801         copyright = copyright.enter()
53802             .append('span')
53803             .attr('class', 'copyright-notice')
53804             .merge(copyright);
53805
53806         copyright
53807             .text(String);
53808     }
53809
53810
53811     function update() {
53812         attribution([context.background().baseLayerSource()], 'base-layer-attribution');
53813         attribution(context.background().overlayLayerSources().filter(function (s) {
53814             return s.validZoom(context.map().zoom());
53815         }), 'overlay-layer-attribution');
53816     }
53817
53818
53819     return function(select$$1) {
53820         selection$$1 = select$$1;
53821
53822         context.background()
53823             .on('change.attribution', update);
53824
53825         context.map()
53826             .on('move.attribution', lodash.throttle(update, 400, {leading: false}));
53827
53828         update();
53829     };
53830 }
53831
53832 function rendererBackgroundSource(data) {
53833     var source = lodash.clone(data),
53834         offset = [0, 0],
53835         name = source.name,
53836         best = !!source.best;
53837
53838     source.scaleExtent = data.scaleExtent || [0, 20];
53839     source.overzoom = data.overzoom !== false;
53840
53841
53842     source.offset = function(_) {
53843         if (!arguments.length) return offset;
53844         offset = _;
53845         return source;
53846     };
53847
53848
53849     source.nudge = function(_, zoomlevel) {
53850         offset[0] += _[0] / Math.pow(2, zoomlevel);
53851         offset[1] += _[1] / Math.pow(2, zoomlevel);
53852         return source;
53853     };
53854
53855
53856     source.name = function() {
53857         return name;
53858     };
53859
53860
53861     source.best = function() {
53862         return best;
53863     };
53864
53865
53866     source.area = function() {
53867         if (!data.polygon) return Number.MAX_VALUE;  // worldwide
53868         var area$$1 = area({ type: 'MultiPolygon', coordinates: [ data.polygon ] });
53869         return isNaN(area$$1) ? 0 : area$$1;
53870     };
53871
53872
53873     source.imageryUsed = function() {
53874         return name || source.id;
53875     };
53876
53877
53878     source.url = function(coord) {
53879         return data.template
53880             .replace('{x}', coord[0])
53881             .replace('{y}', coord[1])
53882             // TMS-flipped y coordinate
53883             .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
53884             .replace(/\{z(oom)?\}/, coord[2])
53885             .replace(/\{switch:([^}]+)\}/, function(s, r) {
53886                 var subdomains = r.split(',');
53887                 return subdomains[(coord[0] + coord[1]) % subdomains.length];
53888             })
53889             .replace('{u}', function() {
53890                 var u = '';
53891                 for (var zoom$$1 = coord[2]; zoom$$1 > 0; zoom$$1--) {
53892                     var b = 0;
53893                     var mask = 1 << (zoom$$1 - 1);
53894                     if ((coord[0] & mask) !== 0) b++;
53895                     if ((coord[1] & mask) !== 0) b += 2;
53896                     u += b.toString();
53897                 }
53898                 return u;
53899             });
53900     };
53901
53902
53903     source.intersects = function(extent$$1) {
53904         extent$$1 = extent$$1.polygon();
53905         return !data.polygon || data.polygon.some(function(polygon) {
53906             return geoPolygonIntersectsPolygon(polygon, extent$$1, true);
53907         });
53908     };
53909
53910
53911     source.validZoom = function(z) {
53912         return source.scaleExtent[0] <= z &&
53913             (source.overzoom || source.scaleExtent[1] > z);
53914     };
53915
53916
53917     source.isLocatorOverlay = function() {
53918         return source.id === 'mapbox_locator_overlay';
53919     };
53920
53921
53922     source.copyrightNotices = function() {};
53923
53924
53925     return source;
53926 }
53927
53928
53929 rendererBackgroundSource.Bing = function(data, dispatch$$1) {
53930     // http://msdn.microsoft.com/en-us/library/ff701716.aspx
53931     // http://msdn.microsoft.com/en-us/library/ff701701.aspx
53932
53933     data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
53934
53935     var bing = rendererBackgroundSource(data),
53936         key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
53937         url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
53938             key + '&jsonp={callback}',
53939         providers = [];
53940
53941     jsonpRequest(url, function(json$$1) {
53942         providers = json$$1.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
53943             return {
53944                 attribution: provider.attribution,
53945                 areas: provider.coverageAreas.map(function(area$$1) {
53946                     return {
53947                         zoom: [area$$1.zoomMin, area$$1.zoomMax],
53948                         extent: geoExtent$$1([area$$1.bbox[1], area$$1.bbox[0]], [area$$1.bbox[3], area$$1.bbox[2]])
53949                     };
53950                 })
53951             };
53952         });
53953         dispatch$$1.call('change');
53954     });
53955
53956     bing.copyrightNotices = function(zoom$$1, extent$$1) {
53957         zoom$$1 = Math.min(zoom$$1, 21);
53958         return providers.filter(function(provider) {
53959             return lodash.some(provider.areas, function(area$$1) {
53960                 return extent$$1.intersects(area$$1.extent) &&
53961                     area$$1.zoom[0] <= zoom$$1 &&
53962                     area$$1.zoom[1] >= zoom$$1;
53963             });
53964         }).map(function(provider) {
53965             return provider.attribution;
53966         }).join(', ');
53967     };
53968
53969     bing.logo = 'bing_maps.png';
53970     bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
53971
53972     return bing;
53973 };
53974
53975
53976 rendererBackgroundSource.None = function() {
53977     var source = rendererBackgroundSource({ id: 'none', template: '' });
53978
53979     source.name = function() {
53980         return t('background.none');
53981     };
53982
53983     source.imageryUsed = function() {
53984         return 'None';
53985     };
53986
53987     source.area = function() {
53988         return -1;  // sources in background pane are sorted by area
53989     };
53990
53991     return source;
53992 };
53993
53994
53995 rendererBackgroundSource.Custom = function(template) {
53996     var source = rendererBackgroundSource({ id: 'custom', template: template });
53997
53998     source.name = function() {
53999         return t('background.custom');
54000     };
54001
54002     source.imageryUsed = function() {
54003         return 'Custom (' + template + ')';
54004     };
54005
54006     source.area = function() {
54007         return -2;  // sources in background pane are sorted by area
54008     };
54009
54010     return source;
54011 };
54012
54013 function rendererTileLayer(context) {
54014     var tileSize = 256,
54015         tile = d3geoTile(),
54016         projection,
54017         cache = {},
54018         tileOrigin,
54019         z,
54020         transformProp = utilPrefixCSSProperty('Transform'),
54021         source = rendererBackgroundSource.None();
54022
54023
54024     // blacklist overlay tiles around Null Island..
54025     function nearNullIsland(x, y, z) {
54026         if (z >= 7) {
54027             var center = Math.pow(2, z - 1),
54028                 width = Math.pow(2, z - 6),
54029                 min$$1 = center - (width / 2),
54030                 max$$1 = center + (width / 2) - 1;
54031             return x >= min$$1 && x <= max$$1 && y >= min$$1 && y <= max$$1;
54032         }
54033         return false;
54034     }
54035
54036
54037     function tileSizeAtZoom(d, z) {
54038         var epsilon = 0.002;
54039         return ((tileSize * Math.pow(2, z - d[2])) / tileSize) + epsilon;
54040     }
54041
54042
54043     function atZoom(t, distance) {
54044         var power = Math.pow(2, distance);
54045         return [
54046             Math.floor(t[0] * power),
54047             Math.floor(t[1] * power),
54048             t[2] + distance];
54049     }
54050
54051
54052     function lookUp(d) {
54053         for (var up = -1; up > -d[2]; up--) {
54054             var tile = atZoom(d, up);
54055             if (cache[source.url(tile)] !== false) {
54056                 return tile;
54057             }
54058         }
54059     }
54060
54061
54062     function uniqueBy(a, n) {
54063         var o = [], seen = {};
54064         for (var i = 0; i < a.length; i++) {
54065             if (seen[a[i][n]] === undefined) {
54066                 o.push(a[i]);
54067                 seen[a[i][n]] = true;
54068             }
54069         }
54070         return o;
54071     }
54072
54073
54074     function addSource(d) {
54075         d.push(source.url(d));
54076         return d;
54077     }
54078
54079
54080     // Update tiles based on current state of `projection`.
54081     function background(selection$$1) {
54082         tile.scale(projection.scale() * 2 * Math.PI)
54083             .translate(projection.translate());
54084
54085         tileOrigin = [
54086             projection.scale() * Math.PI - projection.translate()[0],
54087             projection.scale() * Math.PI - projection.translate()[1]];
54088
54089         z = Math.max(Math.log(projection.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
54090
54091         render(selection$$1);
54092     }
54093
54094
54095     // Derive the tiles onscreen, remove those offscreen and position them.
54096     // Important that this part not depend on `projection` because it's
54097     // rentered when tiles load/error (see #644).
54098     function render(selection$$1) {
54099         var requests = [];
54100         var showDebug = context.getDebug('tile') && !source.overlay;
54101
54102         if (source.validZoom(z)) {
54103             tile().forEach(function(d) {
54104                 addSource(d);
54105                 if (d[3] === '') return;
54106                 if (typeof d[3] !== 'string') return; // Workaround for chrome crash https://github.com/openstreetmap/iD/issues/2295
54107                 requests.push(d);
54108                 if (cache[d[3]] === false && lookUp(d)) {
54109                     requests.push(addSource(lookUp(d)));
54110                 }
54111             });
54112
54113             requests = uniqueBy(requests, 3).filter(function(r) {
54114                 if (!!source.overlay && nearNullIsland(r[0], r[1], r[2])) {
54115                     return false;
54116                 }
54117                 // don't re-request tiles which have failed in the past
54118                 return cache[r[3]] !== false;
54119             });
54120         }
54121
54122         var pixelOffset = [
54123             source.offset()[0] * Math.pow(2, z),
54124             source.offset()[1] * Math.pow(2, z)
54125         ];
54126
54127         function load(d) {
54128             cache[d[3]] = true;
54129             select(this)
54130                 .on('error', null)
54131                 .on('load', null)
54132                 .classed('tile-loaded', true);
54133             render(selection$$1);
54134         }
54135
54136         function error(d) {
54137             cache[d[3]] = false;
54138             select(this)
54139                 .on('error', null)
54140                 .on('load', null)
54141                 .remove();
54142             render(selection$$1);
54143         }
54144
54145         function imageTransform(d) {
54146             var _ts = tileSize * Math.pow(2, z - d[2]);
54147             var scale = tileSizeAtZoom(d, z);
54148             return 'translate(' +
54149                 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
54150                 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
54151                 'scale(' + scale + ',' + scale + ')';
54152         }
54153
54154         function debugTransform(d) {
54155             var _ts = tileSize * Math.pow(2, z - d[2]);
54156             var scale = tileSizeAtZoom(d, z);
54157             return 'translate(' +
54158                 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0] + scale * (tileSize / 4)) + 'px,' +
54159                 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1] + scale * (tileSize / 2)) + 'px)';
54160         }
54161
54162
54163         var image = selection$$1.selectAll('img')
54164             .data(requests, function(d) { return d[3]; });
54165
54166         image.exit()
54167             .style(transformProp, imageTransform)
54168             .classed('tile-removing', true)
54169             .each(function() {
54170                 var tile = select(this);
54171                 window.setTimeout(function() {
54172                     if (tile.classed('tile-removing')) {
54173                         tile.remove();
54174                     }
54175                 }, 300);
54176             });
54177
54178         image.enter()
54179           .append('img')
54180             .attr('class', 'tile')
54181             .attr('src', function(d) { return d[3]; })
54182             .on('error', error)
54183             .on('load', load)
54184           .merge(image)
54185             .style(transformProp, imageTransform)
54186             .classed('tile-debug', showDebug)
54187             .classed('tile-removing', false);
54188
54189
54190         var debug = selection$$1.selectAll('.tile-label-debug')
54191             .data(showDebug ? requests : [], function(d) { return d[3]; });
54192
54193         debug.exit()
54194             .remove();
54195
54196         debug.enter()
54197           .append('div')
54198             .attr('class', 'tile-label-debug')
54199           .merge(debug)
54200             .text(function(d) { return d[2] + ' / ' + d[0] + ' / ' + d[1]; })
54201             .style(transformProp, debugTransform);
54202     }
54203
54204
54205     background.projection = function(_) {
54206         if (!arguments.length) return projection;
54207         projection = _;
54208         return background;
54209     };
54210
54211
54212     background.dimensions = function(_) {
54213         if (!arguments.length) return tile.size();
54214         tile.size(_);
54215         return background;
54216     };
54217
54218
54219     background.source = function(_) {
54220         if (!arguments.length) return source;
54221         source = _;
54222         cache = {};
54223         tile.scaleExtent(source.scaleExtent);
54224         return background;
54225     };
54226
54227
54228     return background;
54229 }
54230
54231 function rendererBackground(context) {
54232     var dispatch$$1 = dispatch('change'),
54233         baseLayer = rendererTileLayer(context).projection(context.projection),
54234         overlayLayers = [],
54235         backgroundSources;
54236
54237
54238     function findSource(id) {
54239         return lodash.find(backgroundSources, function(d) {
54240             return d.id && d.id === id;
54241         });
54242     }
54243
54244
54245     function background(selection$$1) {
54246         var base = selection$$1.selectAll('.layer-background')
54247             .data([0]);
54248
54249         base.enter()
54250             .insert('div', '.layer-data')
54251             .attr('class', 'layer layer-background')
54252             .merge(base)
54253             .call(baseLayer);
54254
54255         var overlays = selection$$1.selectAll('.layer-overlay')
54256             .data(overlayLayers, function(d) { return d.source().name(); });
54257
54258         overlays.exit()
54259             .remove();
54260
54261         overlays.enter()
54262             .insert('div', '.layer-data')
54263             .attr('class', 'layer layer-overlay')
54264             .merge(overlays)
54265             .each(function(layer) { select(this).call(layer); });
54266     }
54267
54268
54269     background.updateImagery = function() {
54270         if (context.inIntro()) return;
54271
54272         var b = background.baseLayerSource(),
54273             o = overlayLayers
54274                 .filter(function (d) { return !d.source().isLocatorOverlay(); })
54275                 .map(function (d) { return d.source().id; })
54276                 .join(','),
54277             meters = geoOffsetToMeters(b.offset()),
54278             epsilon = 0.01,
54279             x = +meters[0].toFixed(2),
54280             y = +meters[1].toFixed(2),
54281             q = utilStringQs(window.location.hash.substring(1));
54282
54283         var id = b.id;
54284         if (id === 'custom') {
54285             id = 'custom:' + b.template;
54286         }
54287
54288         if (id) {
54289             q.background = id;
54290         } else {
54291             delete q.background;
54292         }
54293
54294         if (o) {
54295             q.overlays = o;
54296         } else {
54297             delete q.overlays;
54298         }
54299
54300         if (Math.abs(x) > epsilon || Math.abs(y) > epsilon) {
54301             q.offset = x + ',' + y;
54302         } else {
54303             delete q.offset;
54304         }
54305
54306         window.location.replace('#' + utilQsString(q, true));
54307
54308         var imageryUsed = [b.imageryUsed()];
54309
54310         overlayLayers
54311             .filter(function (d) { return !d.source().isLocatorOverlay(); })
54312             .forEach(function (d) { imageryUsed.push(d.source().imageryUsed()); });
54313
54314         var gpx = context.layers().layer('gpx');
54315         if (gpx && gpx.enabled() && gpx.hasGpx()) {
54316             imageryUsed.push('Local GPX');
54317         }
54318
54319         var mapillary_images = context.layers().layer('mapillary-images');
54320         if (mapillary_images && mapillary_images.enabled()) {
54321             imageryUsed.push('Mapillary Images');
54322         }
54323
54324         var mapillary_signs = context.layers().layer('mapillary-signs');
54325         if (mapillary_signs && mapillary_signs.enabled()) {
54326             imageryUsed.push('Mapillary Signs');
54327         }
54328
54329         context.history().imageryUsed(imageryUsed);
54330     };
54331
54332
54333     background.sources = function(extent$$1) {
54334         return backgroundSources.filter(function(source) {
54335             return source.intersects(extent$$1);
54336         });
54337     };
54338
54339
54340     background.dimensions = function(_) {
54341         if (!_) return;
54342         baseLayer.dimensions(_);
54343
54344         overlayLayers.forEach(function(layer) {
54345             layer.dimensions(_);
54346         });
54347     };
54348
54349
54350     background.baseLayerSource = function(d) {
54351         if (!arguments.length) return baseLayer.source();
54352
54353         // test source against OSM imagery blacklists..
54354         var blacklists = context.connection().imageryBlacklists();
54355
54356         var fail = false,
54357             tested = 0,
54358             regex, i;
54359
54360         for (i = 0; i < blacklists.length; i++) {
54361             try {
54362                 regex = new RegExp(blacklists[i]);
54363                 fail = regex.test(d.template);
54364                 tested++;
54365                 if (fail) break;
54366             } catch (e) {
54367                 /* noop */
54368             }
54369         }
54370
54371         // ensure at least one test was run.
54372         if (!tested) {
54373             regex = new RegExp('.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*');
54374             fail = regex.test(d.template);
54375         }
54376
54377         baseLayer.source(!fail ? d : rendererBackgroundSource.None());
54378         dispatch$$1.call('change');
54379         background.updateImagery();
54380         return background;
54381     };
54382
54383
54384     background.bing = function() {
54385         background.baseLayerSource(findSource('Bing'));
54386     };
54387
54388
54389     background.showsLayer = function(d) {
54390         return d.id === baseLayer.source().id ||
54391             overlayLayers.some(function(layer) { return d.id === layer.source().id; });
54392     };
54393
54394
54395     background.overlayLayerSources = function() {
54396         return overlayLayers.map(function (l) { return l.source(); });
54397     };
54398
54399
54400     background.toggleOverlayLayer = function(d) {
54401         var layer;
54402
54403         for (var i = 0; i < overlayLayers.length; i++) {
54404             layer = overlayLayers[i];
54405             if (layer.source() === d) {
54406                 overlayLayers.splice(i, 1);
54407                 dispatch$$1.call('change');
54408                 background.updateImagery();
54409                 return;
54410             }
54411         }
54412
54413         layer = rendererTileLayer(context)
54414             .source(d)
54415             .projection(context.projection)
54416             .dimensions(baseLayer.dimensions());
54417
54418         overlayLayers.push(layer);
54419         dispatch$$1.call('change');
54420         background.updateImagery();
54421     };
54422
54423
54424     background.nudge = function(d, zoom$$1) {
54425         baseLayer.source().nudge(d, zoom$$1);
54426         dispatch$$1.call('change');
54427         background.updateImagery();
54428         return background;
54429     };
54430
54431
54432     background.offset = function(d) {
54433         if (!arguments.length) return baseLayer.source().offset();
54434         baseLayer.source().offset(d);
54435         dispatch$$1.call('change');
54436         background.updateImagery();
54437         return background;
54438     };
54439
54440
54441     background.init = function() {
54442         function parseMap(qmap) {
54443             if (!qmap) return false;
54444             var args = qmap.split('/').map(Number);
54445             if (args.length < 3 || args.some(isNaN)) return false;
54446             return geoExtent$$1([args[2], args[1]]);
54447         }
54448
54449         var dataImagery = data.imagery || [],
54450             q = utilStringQs(window.location.hash.substring(1)),
54451             chosen = q.background || q.layer,
54452             extent$$1 = parseMap(q.map),
54453             best;
54454
54455         backgroundSources = dataImagery.map(function(source) {
54456             if (source.type === 'bing') {
54457                 return rendererBackgroundSource.Bing(source, dispatch$$1);
54458             } else {
54459                 return rendererBackgroundSource(source);
54460             }
54461         });
54462
54463         backgroundSources.unshift(rendererBackgroundSource.None());
54464
54465         if (!chosen && extent$$1) {
54466             best = lodash.find(this.sources(extent$$1), function(s) { return s.best(); });
54467         }
54468
54469         if (chosen && chosen.indexOf('custom:') === 0) {
54470             background.baseLayerSource(rendererBackgroundSource.Custom(chosen.replace(/^custom:/, '')));
54471         } else {
54472             background.baseLayerSource(findSource(chosen) || best || findSource('Bing') || backgroundSources[1] || backgroundSources[0]);
54473         }
54474
54475         var locator = lodash.find(backgroundSources, function(d) {
54476             return d.overlay && d.default;
54477         });
54478
54479         if (locator) {
54480             background.toggleOverlayLayer(locator);
54481         }
54482
54483         var overlays = (q.overlays || '').split(',');
54484         overlays.forEach(function(overlay) {
54485             overlay = findSource(overlay);
54486             if (overlay) {
54487                 background.toggleOverlayLayer(overlay);
54488             }
54489         });
54490
54491         if (q.gpx) {
54492             var gpx = context.layers().layer('gpx');
54493             if (gpx) {
54494                 gpx.url(q.gpx);
54495             }
54496         }
54497
54498         if (q.offset) {
54499             var offset = q.offset.replace(/;/g, ',').split(',').map(function(n) {
54500                 return !isNaN(n) && n;
54501             });
54502
54503             if (offset.length === 2) {
54504                 background.offset(geoMetersToOffset(offset));
54505             }
54506         }
54507     };
54508
54509
54510     return utilRebind(background, dispatch$$1, 'on');
54511 }
54512
54513 function rendererFeatures(context) {
54514     var traffic_roads = {
54515         'motorway': true,
54516         'motorway_link': true,
54517         'trunk': true,
54518         'trunk_link': true,
54519         'primary': true,
54520         'primary_link': true,
54521         'secondary': true,
54522         'secondary_link': true,
54523         'tertiary': true,
54524         'tertiary_link': true,
54525         'residential': true,
54526         'unclassified': true,
54527         'living_street': true
54528     };
54529
54530     var service_roads = {
54531         'service': true,
54532         'road': true,
54533         'track': true
54534     };
54535
54536     var paths = {
54537         'path': true,
54538         'footway': true,
54539         'cycleway': true,
54540         'bridleway': true,
54541         'steps': true,
54542         'pedestrian': true,
54543         'corridor': true
54544     };
54545
54546     var past_futures = {
54547         'proposed': true,
54548         'construction': true,
54549         'abandoned': true,
54550         'dismantled': true,
54551         'disused': true,
54552         'razed': true,
54553         'demolished': true,
54554         'obliterated': true
54555     };
54556
54557     var dispatch$$1 = dispatch('change', 'redraw'),
54558         _cullFactor = 1,
54559         _cache = {},
54560         _features = {},
54561         _stats = {},
54562         _keys = [],
54563         _hidden = [];
54564
54565
54566     function update() {
54567         _hidden = features.hidden();
54568         dispatch$$1.call('change');
54569         dispatch$$1.call('redraw');
54570     }
54571
54572
54573     function defineFeature(k, filter, max$$1) {
54574         _keys.push(k);
54575         _features[k] = {
54576             filter: filter,
54577             enabled: true,   // whether the user wants it enabled..
54578             count: 0,
54579             currentMax: (max$$1 || Infinity),
54580             defaultMax: (max$$1 || Infinity),
54581             enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
54582             disable: function() { this.enabled = false; this.currentMax = 0; },
54583             hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
54584             autoHidden: function() { return this.hidden() && this.currentMax > 0; }
54585         };
54586     }
54587
54588
54589     defineFeature('points', function isPoint(entity, resolver, geometry) {
54590         return geometry === 'point';
54591     }, 200);
54592
54593     defineFeature('traffic_roads', function isTrafficRoad(entity) {
54594         return traffic_roads[entity.tags.highway];
54595     });
54596
54597     defineFeature('service_roads', function isServiceRoad(entity) {
54598         return service_roads[entity.tags.highway];
54599     });
54600
54601     defineFeature('paths', function isPath(entity) {
54602         return paths[entity.tags.highway];
54603     });
54604
54605     defineFeature('buildings', function isBuilding(entity) {
54606         return (
54607             !!entity.tags['building:part'] ||
54608             (!!entity.tags.building && entity.tags.building !== 'no') ||
54609             entity.tags.amenity === 'shelter' ||
54610             entity.tags.parking === 'multi-storey' ||
54611             entity.tags.parking === 'sheds' ||
54612             entity.tags.parking === 'carports' ||
54613             entity.tags.parking === 'garage_boxes'
54614         );
54615     }, 250);
54616
54617     defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
54618         return geometry === 'area' &&
54619             !_features.buildings.filter(entity) &&
54620             !_features.water.filter(entity);
54621     });
54622
54623     defineFeature('boundaries', function isBoundary(entity) {
54624         return !!entity.tags.boundary;
54625     });
54626
54627     defineFeature('water', function isWater(entity) {
54628         return (
54629             !!entity.tags.waterway ||
54630             entity.tags.natural === 'water' ||
54631             entity.tags.natural === 'coastline' ||
54632             entity.tags.natural === 'bay' ||
54633             entity.tags.landuse === 'pond' ||
54634             entity.tags.landuse === 'basin' ||
54635             entity.tags.landuse === 'reservoir' ||
54636             entity.tags.landuse === 'salt_pond'
54637         );
54638     });
54639
54640     defineFeature('rail', function isRail(entity) {
54641         return (
54642             !!entity.tags.railway ||
54643             entity.tags.landuse === 'railway'
54644         ) && !(
54645             traffic_roads[entity.tags.highway] ||
54646             service_roads[entity.tags.highway] ||
54647             paths[entity.tags.highway]
54648         );
54649     });
54650
54651     defineFeature('power', function isPower(entity) {
54652         return !!entity.tags.power;
54653     });
54654
54655     // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
54656     defineFeature('past_future', function isPastFuture(entity) {
54657         if (
54658             traffic_roads[entity.tags.highway] ||
54659             service_roads[entity.tags.highway] ||
54660             paths[entity.tags.highway]
54661         ) { return false; }
54662
54663         var strings = Object.keys(entity.tags);
54664
54665         for (var i = 0; i < strings.length; i++) {
54666             var s = strings[i];
54667             if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
54668         }
54669         return false;
54670     });
54671
54672     // Lines or areas that don't match another feature filter.
54673     // IMPORTANT: The 'others' feature must be the last one defined,
54674     //   so that code in getMatches can skip this test if `hasMatch = true`
54675     defineFeature('others', function isOther(entity, resolver, geometry) {
54676         return (geometry === 'line' || geometry === 'area');
54677     });
54678
54679
54680     function features() {}
54681
54682
54683     features.features = function() {
54684         return _features;
54685     };
54686
54687
54688     features.keys = function() {
54689         return _keys;
54690     };
54691
54692
54693     features.enabled = function(k) {
54694         if (!arguments.length) {
54695             return _keys.filter(function(k) { return _features[k].enabled; });
54696         }
54697         return _features[k] && _features[k].enabled;
54698     };
54699
54700
54701     features.disabled = function(k) {
54702         if (!arguments.length) {
54703             return _keys.filter(function(k) { return !_features[k].enabled; });
54704         }
54705         return _features[k] && !_features[k].enabled;
54706     };
54707
54708
54709     features.hidden = function(k) {
54710         if (!arguments.length) {
54711             return _keys.filter(function(k) { return _features[k].hidden(); });
54712         }
54713         return _features[k] && _features[k].hidden();
54714     };
54715
54716
54717     features.autoHidden = function(k) {
54718         if (!arguments.length) {
54719             return _keys.filter(function(k) { return _features[k].autoHidden(); });
54720         }
54721         return _features[k] && _features[k].autoHidden();
54722     };
54723
54724
54725     features.enable = function(k) {
54726         if (_features[k] && !_features[k].enabled) {
54727             _features[k].enable();
54728             update();
54729         }
54730     };
54731
54732
54733     features.disable = function(k) {
54734         if (_features[k] && _features[k].enabled) {
54735             _features[k].disable();
54736             update();
54737         }
54738     };
54739
54740
54741     features.toggle = function(k) {
54742         if (_features[k]) {
54743             (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
54744             update();
54745         }
54746     };
54747
54748
54749     features.resetStats = function() {
54750         for (var i = 0; i < _keys.length; i++) {
54751             _features[_keys[i]].count = 0;
54752         }
54753         dispatch$$1.call('change');
54754     };
54755
54756
54757     features.gatherStats = function(d, resolver, dimensions) {
54758         var needsRedraw = false,
54759             type = lodash.groupBy(d, function(ent) { return ent.type; }),
54760             entities = [].concat(type.relation || [], type.way || [], type.node || []),
54761             currHidden, geometry, matches, i, j;
54762
54763         for (i = 0; i < _keys.length; i++) {
54764             _features[_keys[i]].count = 0;
54765         }
54766
54767         // adjust the threshold for point/building culling based on viewport size..
54768         // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
54769         _cullFactor = dimensions[0] * dimensions[1] / 1000000;
54770
54771         for (i = 0; i < entities.length; i++) {
54772             geometry = entities[i].geometry(resolver);
54773             if (!(geometry === 'vertex' || geometry === 'relation')) {
54774                 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
54775                 for (j = 0; j < matches.length; j++) {
54776                     _features[matches[j]].count++;
54777                 }
54778             }
54779         }
54780
54781         currHidden = features.hidden();
54782         if (currHidden !== _hidden) {
54783             _hidden = currHidden;
54784             needsRedraw = true;
54785             dispatch$$1.call('change');
54786         }
54787
54788         return needsRedraw;
54789     };
54790
54791
54792     features.stats = function() {
54793         for (var i = 0; i < _keys.length; i++) {
54794             _stats[_keys[i]] = _features[_keys[i]].count;
54795         }
54796
54797         return _stats;
54798     };
54799
54800
54801     features.clear = function(d) {
54802         for (var i = 0; i < d.length; i++) {
54803             features.clearEntity(d[i]);
54804         }
54805     };
54806
54807
54808     features.clearEntity = function(entity) {
54809         delete _cache[osmEntity$$1.key(entity)];
54810     };
54811
54812
54813     features.reset = function() {
54814         _cache = {};
54815     };
54816
54817
54818     features.getMatches = function(entity, resolver, geometry) {
54819         if (geometry === 'vertex' || geometry === 'relation') return {};
54820
54821         var ent = osmEntity$$1.key(entity);
54822         if (!_cache[ent]) {
54823             _cache[ent] = {};
54824         }
54825
54826         if (!_cache[ent].matches) {
54827             var matches = {},
54828                 hasMatch = false;
54829
54830             for (var i = 0; i < _keys.length; i++) {
54831                 if (_keys[i] === 'others') {
54832                     if (hasMatch) continue;
54833
54834                     // Multipolygon members:
54835                     // If an entity...
54836                     //   1. is a way that hasn't matched other 'interesting' feature rules,
54837                     //   2. and it belongs to a single parent multipolygon relation
54838                     // ...then match whatever feature rules the parent multipolygon has matched.
54839                     // see #2548, #2887
54840                     //
54841                     // IMPORTANT:
54842                     // For this to work, getMatches must be called on relations before ways.
54843                     //
54844                     if (entity.type === 'way') {
54845                         var parents = features.getParents(entity, resolver, geometry);
54846                         if (parents.length === 1 && parents[0].isMultipolygon()) {
54847                             var pkey = osmEntity$$1.key(parents[0]);
54848                             if (_cache[pkey] && _cache[pkey].matches) {
54849                                 matches = lodash.clone(_cache[pkey].matches);
54850                                 continue;
54851                             }
54852                         }
54853                     }
54854                 }
54855
54856                 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
54857                     matches[_keys[i]] = hasMatch = true;
54858                 }
54859             }
54860             _cache[ent].matches = matches;
54861         }
54862
54863         return _cache[ent].matches;
54864     };
54865
54866
54867     features.getParents = function(entity, resolver, geometry) {
54868         if (geometry === 'point') return [];
54869
54870         var ent = osmEntity$$1.key(entity);
54871         if (!_cache[ent]) {
54872             _cache[ent] = {};
54873         }
54874
54875         if (!_cache[ent].parents) {
54876             var parents = [];
54877             if (geometry === 'vertex') {
54878                 parents = resolver.parentWays(entity);
54879             } else {   // 'line', 'area', 'relation'
54880                 parents = resolver.parentRelations(entity);
54881             }
54882             _cache[ent].parents = parents;
54883         }
54884         return _cache[ent].parents;
54885     };
54886
54887
54888     features.isHiddenFeature = function(entity, resolver, geometry) {
54889         if (!_hidden.length) return false;
54890         if (!entity.version) return false;
54891
54892         var matches = features.getMatches(entity, resolver, geometry);
54893
54894         for (var i = 0; i < _hidden.length; i++) {
54895             if (matches[_hidden[i]]) return true;
54896         }
54897         return false;
54898     };
54899
54900
54901     features.isHiddenChild = function(entity, resolver, geometry) {
54902         if (!_hidden.length) return false;
54903         if (!entity.version || geometry === 'point') return false;
54904
54905         var parents = features.getParents(entity, resolver, geometry);
54906         if (!parents.length) return false;
54907
54908         for (var i = 0; i < parents.length; i++) {
54909             if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
54910                 return false;
54911             }
54912         }
54913         return true;
54914     };
54915
54916
54917     features.hasHiddenConnections = function(entity, resolver) {
54918         if (!_hidden.length) return false;
54919         var childNodes, connections;
54920
54921         if (entity.type === 'midpoint') {
54922             childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
54923             connections = [];
54924         } else {
54925             childNodes = entity.nodes ? resolver.childNodes(entity) : [];
54926             connections = features.getParents(entity, resolver, entity.geometry(resolver));
54927         }
54928
54929         // gather ways connected to child nodes..
54930         connections = lodash.reduce(childNodes, function(result, e) {
54931             return resolver.isShared(e) ? lodash.union(result, resolver.parentWays(e)) : result;
54932         }, connections);
54933
54934         return connections.length ? lodash.some(connections, function(e) {
54935             return features.isHidden(e, resolver, e.geometry(resolver));
54936         }) : false;
54937     };
54938
54939
54940     features.isHidden = function(entity, resolver, geometry) {
54941         if (!_hidden.length) return false;
54942         if (!entity.version) return false;
54943
54944         var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
54945         return fn(entity, resolver, geometry);
54946     };
54947
54948
54949     features.filter = function(d, resolver) {
54950         if (!_hidden.length) return d;
54951
54952         var result = [];
54953         for (var i = 0; i < d.length; i++) {
54954             var entity = d[i];
54955             if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
54956                 result.push(entity);
54957             }
54958         }
54959         return result;
54960     };
54961
54962
54963     return utilRebind(features, dispatch$$1, 'on');
54964 }
54965
54966 function utilBindOnce(target, type, listener, capture) {
54967     var typeOnce = type + '.once';
54968     function one() {
54969         target.on(typeOnce, null);
54970         listener.apply(this, arguments);
54971     }
54972     target.on(typeOnce, one, capture);
54973     return this;
54974 }
54975
54976 function rendererMap(context) {
54977
54978     var dimensions = [1, 1],
54979         dispatch$$1 = dispatch('move', 'drawn'),
54980         projection = context.projection,
54981         curtainProjection = context.curtainProjection,
54982         dblclickEnabled = true,
54983         redrawEnabled = true,
54984         transformStart = projection.transform(),
54985         transformLast,
54986         transformed = false,
54987         minzoom = 0,
54988         drawLayers = svgLayers(projection, context),
54989         drawPoints = svgPoints$$1(projection, context),
54990         drawVertices = svgVertices$$1(projection, context),
54991         drawLines = svgLines$$1(projection, context),
54992         drawAreas = svgAreas$$1(projection, context),
54993         drawMidpoints = svgMidpoints$$1(projection, context),
54994         drawLabels = svgLabels(projection, context),
54995         supersurface = select(null),
54996         wrapper = select(null),
54997         surface = select(null),
54998         mouse$$1,
54999         mousemove;
55000
55001     var zoom$$1 = zoom()
55002             .scaleExtent([ztok(2), ztok(24)])
55003             .interpolate(interpolateValue)
55004             .filter(zoomEventFilter)
55005             .on('zoom', zoomPan);
55006
55007     var _selection = select(null);
55008
55009
55010     function map$$1(selection$$1) {
55011
55012         _selection = selection$$1;
55013
55014         context
55015             .on('change.map', immediateRedraw);
55016
55017         context.connection()
55018             .on('change.map', immediateRedraw);
55019
55020         context.history()
55021             .on('change.map', immediateRedraw)
55022             .on('undone.map redone.map', function(stack$$1) {
55023                 var mode = context.mode().id;
55024                 if (mode !== 'browse' && mode !== 'select') return;
55025
55026                 var followSelected = false;
55027                 if (Array.isArray(stack$$1.selectedIDs)) {
55028                     followSelected = (stack$$1.selectedIDs.length === 1 && stack$$1.selectedIDs[0][0] === 'n');
55029                     context.enter(
55030                         modeSelect(context, stack$$1.selectedIDs).follow(followSelected)
55031                     );
55032                 }
55033                 if (!followSelected && stack$$1.transform) {
55034                     map$$1.transformEase(stack$$1.transform);
55035                 }
55036             });
55037
55038         context.background()
55039             .on('change.map', immediateRedraw);
55040
55041         context.features()
55042             .on('redraw.map', immediateRedraw);
55043
55044         drawLayers
55045             .on('change.map', function() {
55046                 context.background().updateImagery();
55047                 immediateRedraw();
55048             });
55049
55050         selection$$1
55051             .on('dblclick.map', dblClick)
55052             .call(zoom$$1)
55053             .call(zoom$$1.transform, projection.transform());
55054
55055         supersurface = selection$$1.append('div')
55056             .attr('id', 'supersurface')
55057             .call(utilSetTransform, 0, 0);
55058
55059         // Need a wrapper div because Opera can't cope with an absolutely positioned
55060         // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
55061         wrapper = supersurface
55062             .append('div')
55063             .attr('class', 'layer layer-data');
55064
55065         map$$1.surface = surface = wrapper
55066             .call(drawLayers)
55067             .selectAll('.surface')
55068             .attr('id', 'surface');
55069
55070         surface
55071             .call(drawLabels.observe)
55072             .on('mousedown.zoom', function() {
55073                 if (event.button === 2) {
55074                     event.stopPropagation();
55075                 }
55076             }, true)
55077             .on('mouseup.zoom', function() {
55078                 if (resetTransform()) immediateRedraw();
55079             })
55080             .on('mousemove.map', function() {
55081                 mousemove = event;
55082             })
55083             .on('mouseover.vertices', function() {
55084                 if (map$$1.editable() && !transformed) {
55085                     var hover = event.target.__data__;
55086                     surface.selectAll('.data-layer-osm')
55087                         .call(drawVertices.drawHover, context.graph(), hover, map$$1.extent(), map$$1.zoom());
55088                     dispatch$$1.call('drawn', this, {full: false});
55089                 }
55090             })
55091             .on('mouseout.vertices', function() {
55092                 if (map$$1.editable() && !transformed) {
55093                     var hover = event.relatedTarget && event.relatedTarget.__data__;
55094                     surface.selectAll('.data-layer-osm')
55095                         .call(drawVertices.drawHover, context.graph(), hover, map$$1.extent(), map$$1.zoom());
55096                     dispatch$$1.call('drawn', this, {full: false});
55097                 }
55098             });
55099
55100         supersurface
55101             .call(context.background());
55102
55103         context.on('enter.map', function() {
55104             if (map$$1.editable() && !transformed) {
55105                 var all = context.intersects(map$$1.extent()),
55106                     filter = utilFunctor(true),
55107                     graph = context.graph();
55108
55109                 all = context.features().filter(all, graph);
55110                 surface.selectAll('.data-layer-osm')
55111                     .call(drawVertices, graph, all, filter, map$$1.extent(), map$$1.zoom())
55112                     .call(drawMidpoints, graph, all, filter, map$$1.trimmedExtent());
55113                 dispatch$$1.call('drawn', this, {full: false});
55114             }
55115         });
55116
55117         map$$1.dimensions(utilGetDimensions(selection$$1));
55118     }
55119
55120
55121     function zoomEventFilter() {
55122         // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
55123         // Intercept `mousedown` and check if there is an orphaned zoom gesture.
55124         // This can happen if a previous `mousedown` occurred without a `mouseup`.
55125         // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
55126         // so that d3-zoom won't stop propagation of new `mousedown` events.
55127         if (event.type === 'mousedown') {
55128             var hasOrphan = false;
55129             var listeners = window.__on;
55130             for (var i = 0; i < listeners.length; i++) {
55131                 var listener = listeners[i];
55132                 if (listener.name === 'zoom' && listener.type === 'mouseup') {
55133                     hasOrphan = true;
55134                     break;
55135                 }
55136             }
55137             if (hasOrphan) {
55138                 var event$$1 = window.CustomEvent;
55139                 if (event$$1) {
55140                     event$$1 = new event$$1('mouseup');
55141                 } else {
55142                     event$$1 = window.document.createEvent('Event');
55143                     event$$1.initEvent('mouseup', false, false);
55144                 }
55145                 // Event needs to be dispatched with an event.view property.
55146                 event$$1.view = window;
55147                 window.dispatchEvent(event$$1);
55148             }
55149         }
55150
55151         return event.button !== 2;   // ignore right clicks
55152     }
55153
55154
55155     function ztok(z) {
55156         return 256 * Math.pow(2, z);
55157     }
55158
55159     function ktoz(k) {
55160         return Math.max(Math.log(k) / Math.LN2 - 8, 0);
55161     }
55162
55163     function pxCenter() {
55164         return [dimensions[0] / 2, dimensions[1] / 2];
55165     }
55166
55167
55168     function drawVector(difference, extent$$1) {
55169         var graph = context.graph(),
55170             features = context.features(),
55171             all = context.intersects(map$$1.extent()),
55172             data, filter;
55173
55174         if (difference) {
55175             var complete = difference.complete(map$$1.extent());
55176             data = lodash.compact(lodash.values(complete));
55177             filter = function(d) { return d.id in complete; };
55178             features.clear(data);
55179
55180         } else {
55181             // force a full redraw if gatherStats detects that a feature
55182             // should be auto-hidden (e.g. points or buildings)..
55183             if (features.gatherStats(all, graph, dimensions)) {
55184                 extent$$1 = undefined;
55185             }
55186
55187             if (extent$$1) {
55188                 data = context.intersects(map$$1.extent().intersection(extent$$1));
55189                 var set$$1 = set$2(lodash.map(data, 'id'));
55190                 filter = function(d) { return set$$1.has(d.id); };
55191
55192             } else {
55193                 data = all;
55194                 filter = utilFunctor(true);
55195             }
55196         }
55197
55198         data = features.filter(data, graph);
55199
55200         surface.selectAll('.data-layer-osm')
55201             .call(drawVertices, graph, data, filter, map$$1.extent(), map$$1.zoom())
55202             .call(drawLines, graph, data, filter)
55203             .call(drawAreas, graph, data, filter)
55204             .call(drawMidpoints, graph, data, filter, map$$1.trimmedExtent())
55205             .call(drawLabels, graph, data, filter, dimensions, !difference && !extent$$1)
55206             .call(drawPoints, graph, data, filter);
55207
55208         dispatch$$1.call('drawn', this, {full: true});
55209     }
55210
55211
55212     function editOff() {
55213         context.features().resetStats();
55214         surface.selectAll('.layer-osm *').remove();
55215         dispatch$$1.call('drawn', this, {full: true});
55216     }
55217
55218
55219     function dblClick() {
55220         if (!dblclickEnabled) {
55221             event.preventDefault();
55222             event.stopImmediatePropagation();
55223         }
55224     }
55225
55226
55227     function zoomPan(manualEvent) {
55228         var event$$1 = (manualEvent || event),
55229             source = event$$1.sourceEvent,
55230             eventTransform = event$$1.transform;
55231
55232         if (transformStart.x === eventTransform.x &&
55233             transformStart.y === eventTransform.y &&
55234             transformStart.k === eventTransform.k) {
55235             return;  // no change
55236         }
55237
55238         // Normalize mousewheel - #3029
55239         // If wheel delta is provided in LINE units, recalculate it in PIXEL units
55240         // We are essentially redoing the calculations that occur here:
55241         //   https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
55242         // See this for more info:
55243         //   https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
55244         if (source && source.type === 'wheel' && source.deltaMode === 1 /* LINE */) {
55245             // pick sensible scroll amount if user scrolling fast or slow..
55246             var lines = Math.abs(source.deltaY),
55247                 scroll = lines > 2 ? 40 : lines * 10;
55248
55249             var t0 = transformed ? transformLast : transformStart,
55250                 p0 = mouse$$1(source),
55251                 p1 = t0.invert(p0),
55252                 k2 = t0.k * Math.pow(2, -source.deltaY * scroll / 500),
55253                 x2 = p0[0] - p1[0] * k2,
55254                 y2 = p0[1] - p1[1] * k2;
55255
55256             eventTransform = identity$8.translate(x2,y2).scale(k2);
55257             _selection.node().__zoom = eventTransform;
55258         }
55259
55260         if (ktoz(eventTransform.k * 2 * Math.PI) < minzoom) {
55261             surface.interrupt();
55262             uiFlash().text(t('cannot_zoom'));
55263             setZoom(context.minEditableZoom(), true);
55264             queueRedraw();
55265             dispatch$$1.call('move', this, map$$1);
55266             return;
55267         }
55268
55269         projection.transform(eventTransform);
55270
55271         var scale = eventTransform.k / transformStart.k,
55272             tX = (eventTransform.x / scale - transformStart.x) * scale,
55273             tY = (eventTransform.y / scale - transformStart.y) * scale;
55274
55275         if (context.inIntro()) {
55276             curtainProjection.transform({
55277                 x: eventTransform.x - tX,
55278                 y: eventTransform.y - tY,
55279                 k: eventTransform.k
55280             });
55281         }
55282
55283         transformed = true;
55284         transformLast = eventTransform;
55285         utilSetTransform(supersurface, tX, tY, scale);
55286         queueRedraw();
55287
55288         dispatch$$1.call('move', this, map$$1);
55289     }
55290
55291
55292     function resetTransform() {
55293         if (!transformed) return false;
55294
55295         // deprecation warning - Radial Menu to be removed in iD v3
55296         surface.selectAll('.edit-menu, .radial-menu').interrupt().remove();
55297         utilSetTransform(supersurface, 0, 0);
55298         transformed = false;
55299         if (context.inIntro()) {
55300             curtainProjection.transform(projection.transform());
55301         }
55302         return true;
55303     }
55304
55305
55306     function redraw(difference, extent$$1) {
55307         if (surface.empty() || !redrawEnabled) return;
55308
55309         // If we are in the middle of a zoom/pan, we can't do differenced redraws.
55310         // It would result in artifacts where differenced entities are redrawn with
55311         // one transform and unchanged entities with another.
55312         if (resetTransform()) {
55313             difference = extent$$1 = undefined;
55314         }
55315
55316         var z = String(~~map$$1.zoom());
55317         if (surface.attr('data-zoom') !== z) {
55318             surface.attr('data-zoom', z)
55319                 .classed('low-zoom', z <= 16);
55320         }
55321
55322         if (!difference) {
55323             supersurface.call(context.background());
55324         }
55325
55326         wrapper
55327             .call(drawLayers);
55328
55329         // OSM
55330         if (map$$1.editable()) {
55331             context.loadTiles(projection, dimensions);
55332             drawVector(difference, extent$$1);
55333         } else {
55334             editOff();
55335         }
55336
55337         transformStart = projection.transform();
55338
55339         return map$$1;
55340     }
55341
55342
55343     var queueRedraw = lodash.throttle(redraw, 750);
55344
55345
55346     var immediateRedraw = function(difference, extent$$1) {
55347         if (!difference && !extent$$1) queueRedraw.cancel();
55348         redraw(difference, extent$$1);
55349     };
55350
55351
55352     function pointLocation(p) {
55353         var translate = projection.translate(),
55354             scale = projection.scale() * 2 * Math.PI;
55355         return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
55356     }
55357
55358
55359     function locationPoint(l) {
55360         var translate = projection.translate(),
55361             scale = projection.scale() * 2 * Math.PI;
55362         return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
55363     }
55364
55365
55366     map$$1.mouse = function() {
55367         var event$$1 = mousemove || event;
55368         if (event$$1) {
55369             var s;
55370             while ((s = event$$1.sourceEvent)) { event$$1 = s; }
55371             return mouse$$1(event$$1);
55372         }
55373         return null;
55374     };
55375
55376
55377     map$$1.mouseCoordinates = function() {
55378         return projection.invert(map$$1.mouse());
55379     };
55380
55381
55382     map$$1.dblclickEnable = function(_) {
55383         if (!arguments.length) return dblclickEnabled;
55384         dblclickEnabled = _;
55385         return map$$1;
55386     };
55387
55388
55389     map$$1.redrawEnable = function(_) {
55390         if (!arguments.length) return redrawEnabled;
55391         redrawEnabled = _;
55392         return map$$1;
55393     };
55394
55395
55396     function setTransform(t2, duration, force) {
55397         var t$$1 = projection.transform();
55398         if (!force && t2.k === t$$1.k && t2.x === t$$1.x && t2.y === t$$1.y) {
55399             return false;
55400         }
55401
55402         if (duration) {
55403             _selection
55404                 .transition()
55405                 .duration(duration)
55406                 .on('start', function() { map$$1.startEase(); })
55407                 .call(zoom$$1.transform, identity$8.translate(t2.x, t2.y).scale(t2.k));
55408         } else {
55409             projection.transform(t2);
55410             transformStart = t2;
55411             _selection.call(zoom$$1.transform, transformStart);
55412         }
55413     }
55414
55415
55416     function setZoom(z2, force, duration) {
55417         if (z2 === map$$1.zoom() && !force) {
55418             return false;
55419         }
55420
55421         var k = projection.scale(),
55422             k2 = Math.max(ztok(2), Math.min(ztok(24), ztok(z2))) / (2 * Math.PI),
55423             center = pxCenter(),
55424             l = pointLocation(center);
55425
55426         projection.scale(k2);
55427
55428         var t$$1 = projection.translate();
55429         l = locationPoint(l);
55430
55431         t$$1[0] += center[0] - l[0];
55432         t$$1[1] += center[1] - l[1];
55433
55434         if (duration) {
55435             projection.scale(k);  // reset scale
55436             _selection
55437                 .transition()
55438                 .duration(duration)
55439                 .on('start', function() { map$$1.startEase(); })
55440                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k2));
55441         } else {
55442             projection.translate(t$$1);
55443             transformStart = projection.transform();
55444             _selection.call(zoom$$1.transform, transformStart);
55445         }
55446
55447         return true;
55448     }
55449
55450
55451     function setCenter(loc2, duration) {
55452         var c = map$$1.center();
55453         if (loc2[0] === c[0] && loc2[1] === c[1]) {
55454             return false;
55455         }
55456
55457         var t$$1 = projection.translate(),
55458             k = projection.scale(),
55459             pxC = pxCenter(),
55460             ll = projection(loc2);
55461
55462         t$$1[0] = t$$1[0] - ll[0] + pxC[0];
55463         t$$1[1] = t$$1[1] - ll[1] + pxC[1];
55464
55465         if (duration) {
55466             _selection
55467                 .transition()
55468                 .duration(duration)
55469                 .on('start', function() { map$$1.startEase(); })
55470                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k));
55471         } else {
55472             projection.translate(t$$1);
55473             transformStart = projection.transform();
55474             _selection.call(zoom$$1.transform, transformStart);
55475         }
55476
55477         return true;
55478     }
55479
55480
55481     map$$1.pan = function(delta, duration) {
55482         var t$$1 = projection.translate(),
55483             k = projection.scale();
55484
55485         t$$1[0] += delta[0];
55486         t$$1[1] += delta[1];
55487
55488         if (duration) {
55489             _selection
55490                 .transition()
55491                 .duration(duration)
55492                 .on('start', function() { map$$1.startEase(); })
55493                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k));
55494         } else {
55495             projection.translate(t$$1);
55496             transformStart = projection.transform();
55497             _selection.call(zoom$$1.transform, transformStart);
55498             dispatch$$1.call('move', this, map$$1);
55499             immediateRedraw();
55500         }
55501
55502         return map$$1;
55503     };
55504
55505
55506     map$$1.dimensions = function(_) {
55507         if (!arguments.length) return dimensions;
55508         var center = map$$1.center();
55509         dimensions = _;
55510         drawLayers.dimensions(dimensions);
55511         context.background().dimensions(dimensions);
55512         projection.clipExtent([[0, 0], dimensions]);
55513         mouse$$1 = utilFastMouse(supersurface.node());
55514         setCenter(center);
55515
55516         queueRedraw();
55517         return map$$1;
55518     };
55519
55520
55521     function zoomIn(delta) {
55522         setZoom(~~map$$1.zoom() + delta, true, 250);
55523     }
55524
55525     function zoomOut(delta) {
55526         setZoom(~~map$$1.zoom() - delta, true, 250);
55527     }
55528
55529     map$$1.zoomIn = function() { zoomIn(1); };
55530     map$$1.zoomInFurther = function() { zoomIn(4); };
55531
55532     map$$1.zoomOut = function() { zoomOut(1); };
55533     map$$1.zoomOutFurther = function() { zoomOut(4); };
55534
55535
55536     map$$1.center = function(loc2) {
55537         if (!arguments.length) {
55538             return projection.invert(pxCenter());
55539         }
55540
55541         if (setCenter(loc2)) {
55542             dispatch$$1.call('move', this, map$$1);
55543         }
55544
55545         queueRedraw();
55546         return map$$1;
55547     };
55548
55549
55550     map$$1.zoom = function(z2) {
55551         if (!arguments.length) {
55552             return Math.max(ktoz(projection.scale() * 2 * Math.PI), 0);
55553         }
55554
55555         if (z2 < minzoom) {
55556             surface.interrupt();
55557             uiFlash().text(t('cannot_zoom'));
55558             z2 = context.minEditableZoom();
55559         }
55560
55561         if (setZoom(z2)) {
55562             dispatch$$1.call('move', this, map$$1);
55563         }
55564
55565         queueRedraw();
55566         return map$$1;
55567     };
55568
55569
55570     map$$1.zoomTo = function(entity, zoomLimits) {
55571         var extent$$1 = entity.extent(context.graph());
55572         if (!isFinite(extent$$1.area())) return;
55573
55574         var z2 = map$$1.trimmedExtentZoom(extent$$1);
55575         zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
55576         map$$1.centerZoom(extent$$1.center(), Math.min(Math.max(z2, zoomLimits[0]), zoomLimits[1]));
55577     };
55578
55579
55580     map$$1.centerZoom = function(loc2, z2) {
55581         var centered = setCenter(loc2),
55582             zoomed   = setZoom(z2);
55583
55584         if (centered || zoomed) {
55585             dispatch$$1.call('move', this, map$$1);
55586         }
55587
55588         queueRedraw();
55589         return map$$1;
55590     };
55591
55592
55593     map$$1.centerEase = function(loc2, duration) {
55594         duration = duration || 250;
55595         setCenter(loc2, duration);
55596         return map$$1;
55597     };
55598
55599
55600     map$$1.zoomEase = function(z2, duration) {
55601         duration = duration || 250;
55602         setZoom(z2, false, duration);
55603         return map$$1;
55604     };
55605
55606
55607     map$$1.transformEase = function(t2, duration) {
55608         duration = duration || 250;
55609         setTransform(t2, duration, false);
55610         return map$$1;
55611     };
55612
55613
55614     map$$1.startEase = function() {
55615         utilBindOnce(surface, 'mousedown.ease', function() {
55616             map$$1.cancelEase();
55617         });
55618         return map$$1;
55619     };
55620
55621
55622     map$$1.cancelEase = function() {
55623         _selection.interrupt();
55624         return map$$1;
55625     };
55626
55627
55628     map$$1.extent = function(_) {
55629         if (!arguments.length) {
55630             return new geoExtent$$1(projection.invert([0, dimensions[1]]),
55631                                  projection.invert([dimensions[0], 0]));
55632         } else {
55633             var extent$$1 = geoExtent$$1(_);
55634             map$$1.centerZoom(extent$$1.center(), map$$1.extentZoom(extent$$1));
55635         }
55636     };
55637
55638
55639     map$$1.trimmedExtent = function(_) {
55640         if (!arguments.length) {
55641             var headerY = 60, footerY = 30, pad = 10;
55642             return new geoExtent$$1(projection.invert([pad, dimensions[1] - footerY - pad]),
55643                                  projection.invert([dimensions[0] - pad, headerY + pad]));
55644         } else {
55645             var extent$$1 = geoExtent$$1(_);
55646             map$$1.centerZoom(extent$$1.center(), map$$1.trimmedExtentZoom(extent$$1));
55647         }
55648     };
55649
55650
55651     function calcZoom(extent$$1, dim) {
55652         var tl = projection([extent$$1[0][0], extent$$1[1][1]]),
55653             br = projection([extent$$1[1][0], extent$$1[0][1]]);
55654
55655         // Calculate maximum zoom that fits extent
55656         var hFactor = (br[0] - tl[0]) / dim[0],
55657             vFactor = (br[1] - tl[1]) / dim[1],
55658             hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
55659             vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
55660             newZoom = map$$1.zoom() - Math.max(hZoomDiff, vZoomDiff);
55661
55662         return newZoom;
55663     }
55664
55665
55666     map$$1.extentZoom = function(_) {
55667         return calcZoom(geoExtent$$1(_), dimensions);
55668     };
55669
55670
55671     map$$1.trimmedExtentZoom = function(_) {
55672         var trimY = 120, trimX = 40,
55673             trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
55674         return calcZoom(geoExtent$$1(_), trimmed);
55675     };
55676
55677
55678     map$$1.editable = function() {
55679         return map$$1.zoom() >= context.minEditableZoom();
55680     };
55681
55682
55683     map$$1.minzoom = function(_) {
55684         if (!arguments.length) return minzoom;
55685         minzoom = _;
55686         return map$$1;
55687     };
55688
55689
55690     map$$1.layers = drawLayers;
55691
55692
55693     return utilRebind(map$$1, dispatch$$1, 'on');
55694 }
55695
55696 var TAU = 2 * Math.PI;
55697 function ztok(z) { return 256 * Math.pow(2, z) / TAU; }
55698 function ktoz(k) { return Math.log(k * TAU) / Math.LN2 - 8; }
55699 function vecSub(a, b) { return [ a[0] - b[0], a[1] - b[1] ]; }
55700 function vecScale(a, b) { return [ a[0] * b, a[1] * b ]; }
55701
55702
55703 function uiMapInMap(context) {
55704     var key = '/';
55705
55706
55707     function map_in_map(selection$$1) {
55708         var backgroundLayer = rendererTileLayer(context),
55709             overlayLayers = {},
55710             projection = geoRawMercator(),
55711             gpxLayer = svgGpx(projection, context).showLabels(false),
55712             debugLayer = svgDebug(projection, context),
55713             zoom$$1 = zoom()
55714                 .scaleExtent([ztok(0.5), ztok(24)])
55715                 .on('start', zoomStarted)
55716                 .on('zoom', zoomed)
55717                 .on('end', zoomEnded),
55718             isTransformed = false,
55719             isHidden = true,
55720             skipEvents = false,
55721             gesture = null,
55722             zDiff = 6,    // by default, minimap renders at (main zoom - 6)
55723             wrap = select(null),
55724             tiles = select(null),
55725             viewport = select(null),
55726             tStart,  // transform at start of gesture
55727             tCurr,   // transform at most recent event
55728             timeoutId;
55729
55730
55731         function zoomStarted() {
55732             if (skipEvents) return;
55733             tStart = tCurr = projection.transform();
55734             gesture = null;
55735         }
55736
55737
55738         function zoomed() {
55739             if (skipEvents) return;
55740
55741             var x = event.transform.x,
55742                 y = event.transform.y,
55743                 k = event.transform.k,
55744                 isZooming = (k !== tStart.k),
55745                 isPanning = (x !== tStart.x || y !== tStart.y);
55746
55747             if (!isZooming && !isPanning) {
55748                 return;  // no change
55749             }
55750
55751             // lock in either zooming or panning, don't allow both in minimap.
55752             if (!gesture) {
55753                 gesture = isZooming ? 'zoom' : 'pan';
55754             }
55755
55756             var tMini = projection.transform(),
55757                 tX, tY, scale;
55758
55759             if (gesture === 'zoom') {
55760                 var dMini = utilGetDimensions(wrap),
55761                     cMini = vecScale(dMini, 0.5);
55762                 scale = k / tMini.k;
55763                 tX = (cMini[0] / scale - cMini[0]) * scale;
55764                 tY = (cMini[1] / scale - cMini[1]) * scale;
55765             } else {
55766                 k = tMini.k;
55767                 scale = 1;
55768                 tX = x - tMini.x;
55769                 tY = y - tMini.y;
55770             }
55771
55772             utilSetTransform(tiles, tX, tY, scale);
55773             utilSetTransform(viewport, 0, 0, scale);
55774             isTransformed = true;
55775             tCurr = identity$8.translate(x, y).scale(k);
55776
55777             var zMain = ktoz(context.projection.scale()),
55778                 zMini = ktoz(k);
55779
55780             zDiff = zMain - zMini;
55781
55782             queueRedraw();
55783         }
55784
55785
55786         function zoomEnded() {
55787             if (skipEvents) return;
55788             if (gesture !== 'pan') return;
55789
55790             updateProjection();
55791             gesture = null;
55792             var dMini = utilGetDimensions(wrap),
55793                 cMini = vecScale(dMini, 0.5);
55794             context.map().center(projection.invert(cMini));   // recenter main map..
55795         }
55796
55797
55798         function updateProjection() {
55799             var loc = context.map().center(),
55800                 dMini = utilGetDimensions(wrap),
55801                 cMini = vecScale(dMini, 0.5),
55802                 tMain = context.projection.transform(),
55803                 zMain = ktoz(tMain.k),
55804                 zMini = Math.max(zMain - zDiff, 0.5),
55805                 kMini = ztok(zMini);
55806
55807             projection
55808                 .translate([tMain.x, tMain.y])
55809                 .scale(kMini);
55810
55811             var point = projection(loc),
55812                 mouse$$1 = (gesture === 'pan') ? vecSub([tCurr.x, tCurr.y], [tStart.x, tStart.y]) : [0, 0],
55813                 xMini = cMini[0] - point[0] + tMain.x + mouse$$1[0],
55814                 yMini = cMini[1] - point[1] + tMain.y + mouse$$1[1];
55815
55816             projection
55817                 .translate([xMini, yMini])
55818                 .clipExtent([[0, 0], dMini]);
55819
55820             tCurr = projection.transform();
55821
55822             if (isTransformed) {
55823                 utilSetTransform(tiles, 0, 0);
55824                 utilSetTransform(viewport, 0, 0);
55825                 isTransformed = false;
55826             }
55827
55828             zoom$$1
55829                 .scaleExtent([ztok(0.5), ztok(zMain - 3)]);
55830
55831             skipEvents = true;
55832             wrap.call(zoom$$1.transform, tCurr);
55833             skipEvents = false;
55834         }
55835
55836
55837         function redraw() {
55838             clearTimeout(timeoutId);
55839             if (isHidden) return;
55840
55841             updateProjection();
55842
55843             var dMini = utilGetDimensions(wrap),
55844                 zMini = ktoz(projection.scale());
55845
55846             // setup tile container
55847             tiles = wrap
55848                 .selectAll('.map-in-map-tiles')
55849                 .data([0]);
55850
55851             tiles = tiles.enter()
55852                 .append('div')
55853                 .attr('class', 'map-in-map-tiles')
55854                 .merge(tiles);
55855
55856             // redraw background
55857             backgroundLayer
55858                 .source(context.background().baseLayerSource())
55859                 .projection(projection)
55860                 .dimensions(dMini);
55861
55862             var background = tiles
55863                 .selectAll('.map-in-map-background')
55864                 .data([0]);
55865
55866             background.enter()
55867                 .append('div')
55868                 .attr('class', 'map-in-map-background')
55869                 .merge(background)
55870                 .call(backgroundLayer);
55871
55872
55873             // redraw overlay
55874             var overlaySources = context.background().overlayLayerSources();
55875             var activeOverlayLayers = [];
55876             for (var i = 0; i < overlaySources.length; i++) {
55877                 if (overlaySources[i].validZoom(zMini)) {
55878                     if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
55879                     activeOverlayLayers.push(overlayLayers[i]
55880                         .source(overlaySources[i])
55881                         .projection(projection)
55882                         .dimensions(dMini));
55883                 }
55884             }
55885
55886             var overlay = tiles
55887                 .selectAll('.map-in-map-overlay')
55888                 .data([0]);
55889
55890             overlay = overlay.enter()
55891                 .append('div')
55892                 .attr('class', 'map-in-map-overlay')
55893                 .merge(overlay);
55894
55895
55896             var overlays = overlay
55897                 .selectAll('div')
55898                 .data(activeOverlayLayers, function(d) { return d.source().name(); });
55899
55900             overlays.exit()
55901                 .remove();
55902
55903             overlays = overlays.enter()
55904                 .append('div')
55905                 .merge(overlays)
55906                 .each(function(layer) { select(this).call(layer); });
55907
55908
55909             var dataLayers = tiles
55910                 .selectAll('.map-in-map-data')
55911                 .data([0]);
55912
55913             dataLayers.exit()
55914                 .remove();
55915
55916             dataLayers = dataLayers.enter()
55917                 .append('svg')
55918                 .attr('class', 'map-in-map-data')
55919                 .merge(dataLayers)
55920                 .call(gpxLayer)
55921                 .call(debugLayer);
55922
55923
55924             // redraw viewport bounding box
55925             if (gesture !== 'pan') {
55926                 var getPath = index$4(projection),
55927                     bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
55928
55929                 viewport = wrap.selectAll('.map-in-map-viewport')
55930                     .data([0]);
55931
55932                 viewport = viewport.enter()
55933                     .append('svg')
55934                     .attr('class', 'map-in-map-viewport')
55935                     .merge(viewport);
55936
55937
55938                 var path$$1 = viewport.selectAll('.map-in-map-bbox')
55939                     .data([bbox]);
55940
55941                 path$$1.enter()
55942                     .append('path')
55943                     .attr('class', 'map-in-map-bbox')
55944                     .merge(path$$1)
55945                     .attr('d', getPath)
55946                     .classed('thick', function(d) { return getPath.area(d) < 30; });
55947             }
55948         }
55949
55950
55951         function queueRedraw() {
55952             clearTimeout(timeoutId);
55953             timeoutId = setTimeout(function() { redraw(); }, 750);
55954         }
55955
55956
55957         function toggle() {
55958             if (event) event.preventDefault();
55959
55960             isHidden = !isHidden;
55961
55962             var label = select('.minimap-toggle');
55963             label.classed('active', !isHidden)
55964                 .select('input').property('checked', !isHidden);
55965
55966             if (isHidden) {
55967                 wrap
55968                     .style('display', 'block')
55969                     .style('opacity', '1')
55970                     .transition()
55971                     .duration(200)
55972                     .style('opacity', '0')
55973                     .on('end', function() {
55974                         selection$$1.selectAll('.map-in-map')
55975                             .style('display', 'none');
55976                     });
55977             } else {
55978                 wrap
55979                     .style('display', 'block')
55980                     .style('opacity', '0')
55981                     .transition()
55982                     .duration(200)
55983                     .style('opacity', '1')
55984                     .on('end', function() {
55985                         redraw();
55986                     });
55987             }
55988         }
55989
55990
55991         uiMapInMap.toggle = toggle;
55992
55993         wrap = selection$$1.selectAll('.map-in-map')
55994             .data([0]);
55995
55996         wrap = wrap.enter()
55997             .append('div')
55998             .attr('class', 'map-in-map')
55999             .style('display', (isHidden ? 'none' : 'block'))
56000             .call(zoom$$1)
56001             .on('dblclick.zoom', null)
56002             .merge(wrap);
56003
56004         context.map()
56005             .on('drawn.map-in-map', function(drawn) {
56006                 if (drawn.full === true) {
56007                     redraw();
56008                 }
56009             });
56010
56011         redraw();
56012
56013         var keybinding = d3keybinding('map-in-map')
56014             .on(key, toggle);
56015
56016         select(document)
56017             .call(keybinding);
56018     }
56019
56020     return map_in_map;
56021 }
56022
56023 function uiTooltipHtml(text, key, heading) {
56024     var s = '';
56025
56026     if (heading) {
56027         s += '<div class="tooltip-heading"><span>' + heading + '</span></div>';
56028     }
56029     if (text) {
56030         s += '<div class="tooltip-text"><span>' + text + '</span></div>';
56031     }
56032     if (key) {
56033         s += '<div class="keyhint-wrap"><span>' + t('tooltip_keyhint') + '</span>' +
56034             '<span class="keyhint">' + key + '</span></div>';
56035     }
56036
56037     return s;
56038 }
56039
56040 function uiBackground(context) {
56041     var key = 'B',
56042         detected = utilDetect(),
56043         opacities = [1, 0.75, 0.5, 0.25],
56044         directions = [
56045             ['right', [0.5, 0]],
56046             ['top', [0, -0.5]],
56047             ['left', [-0.5, 0]],
56048             ['bottom', [0, 0.5]]],
56049         opacityDefault = (context.storage('background-opacity') !== null) ?
56050             (+context.storage('background-opacity')) : 1.0,
56051         customTemplate = context.storage('background-custom-template') || '',
56052         previous;
56053
56054     // Can be 0 from <1.3.0 use or due to issue #1923.
56055     if (opacityDefault === 0) opacityDefault = 1.0;
56056
56057
56058     function background(selection$$1) {
56059
56060         function sortSources(a, b) {
56061             return a.best() && !b.best() ? -1
56062                 : b.best() && !a.best() ? 1
56063                 : descending(a.area(), b.area()) || ascending(a.name(), b.name()) || 0;
56064         }
56065
56066
56067         function setOpacity(d) {
56068             var bg = context.container().selectAll('.layer-background')
56069                 .transition()
56070                 .style('opacity', d)
56071                 .attr('data-opacity', d);
56072
56073             if (!detected.opera) {
56074                 utilSetTransform(bg, 0, 0);
56075             }
56076
56077             opacityList.selectAll('li')
56078                 .classed('active', function(_) { return _ === d; });
56079
56080             context.storage('background-opacity', d);
56081         }
56082
56083
56084         function setTooltips(selection$$1) {
56085             selection$$1.each(function(d, i, nodes) {
56086                 var item = select(this).select('label'),
56087                     span = item.select('span'),
56088                     placement = (i < nodes.length / 2) ? 'bottom' : 'top',
56089                     isOverflowing = (span.property('clientWidth') !== span.property('scrollWidth'));
56090
56091                 if (d === previous) {
56092                     item.call(tooltip()
56093                         .placement(placement)
56094                         .html(true)
56095                         .title(function() {
56096                             var tip = '<div>' + t('background.switch') + '</div>';
56097                             return uiTooltipHtml(tip, uiCmd('⌘B'));
56098                         })
56099                     );
56100                 } else if (d.description || isOverflowing) {
56101                     item.call(tooltip()
56102                         .placement(placement)
56103                         .title(d.description || d.name())
56104                     );
56105                 } else {
56106                     item.call(tooltip().destroy);
56107                 }
56108             });
56109         }
56110
56111
56112         function selectLayer() {
56113             function active$$1(d) {
56114                 return context.background().showsLayer(d);
56115             }
56116
56117             content.selectAll('.layer, .custom_layer')
56118                 .classed('active', active$$1)
56119                 .classed('switch', function(d) { return d === previous; })
56120                 .call(setTooltips)
56121                 .selectAll('input')
56122                 .property('checked', active$$1);
56123         }
56124
56125
56126         function clickSetSource(d) {
56127             event.preventDefault();
56128             previous = context.background().baseLayerSource();
56129             context.background().baseLayerSource(d);
56130             selectLayer();
56131             document.activeElement.blur();
56132         }
56133
56134
56135         function editCustom() {
56136             event.preventDefault();
56137             var template = window.prompt(t('background.custom_prompt'), customTemplate);
56138             if (template) {
56139                 setCustom(template);
56140             } else {
56141                 selectLayer();
56142             }
56143         }
56144
56145
56146         function setCustom(template) {
56147             context.storage('background-custom-template', template);
56148             var d = rendererBackgroundSource.Custom(template);
56149             content.selectAll('.custom_layer').datum(d);
56150             clickSetSource(d);
56151         }
56152
56153
56154         function clickSetOverlay(d) {
56155             event.preventDefault();
56156             context.background().toggleOverlayLayer(d);
56157             selectLayer();
56158             document.activeElement.blur();
56159         }
56160
56161
56162         function drawList(layerList, type, change, filter) {
56163             var sources = context.background()
56164                 .sources(context.map().extent())
56165                 .filter(filter);
56166
56167             var layerLinks = layerList.selectAll('li.layer')
56168                 .data(sources, function(d) { return d.name(); });
56169
56170             layerLinks.exit()
56171                 .remove();
56172
56173             var enter = layerLinks.enter()
56174                 .insert('li', '.custom_layer')
56175                 .attr('class', 'layer')
56176                 .classed('best', function(d) { return d.best(); });
56177
56178             enter.filter(function(d) { return d.best(); })
56179                 .append('div')
56180                 .attr('class', 'best')
56181                 .call(tooltip()
56182                     .title(t('background.best_imagery'))
56183                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
56184                 .append('span')
56185                 .html('&#9733;');
56186
56187             var label = enter
56188                 .append('label');
56189
56190             label
56191                 .append('input')
56192                 .attr('type', type)
56193                 .attr('name', 'layers')
56194                 .on('change', change);
56195
56196             label
56197                 .append('span')
56198                 .text(function(d) { return d.name(); });
56199
56200
56201             layerList.selectAll('li.layer')
56202                 .sort(sortSources)
56203                 .style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
56204         }
56205
56206
56207         function update() {
56208             backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
56209             overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
56210
56211             selectLayer();
56212
56213             var source = context.background().baseLayerSource();
56214             if (source.id === 'custom') {
56215                 customTemplate = source.template;
56216             }
56217
56218             updateOffsetVal();
56219         }
56220
56221
56222         function updateOffsetVal() {
56223             var meters = geoOffsetToMeters(context.background().offset()),
56224                 x = +meters[0].toFixed(2),
56225                 y = +meters[1].toFixed(2);
56226
56227             selectAll('.nudge-inner-rect')
56228                 .select('input')
56229                 .classed('error', false)
56230                 .property('value', x + ', ' + y);
56231
56232             selectAll('.nudge-reset')
56233                 .classed('disabled', function() {
56234                     return (x === 0 && y === 0);
56235                 });
56236         }
56237
56238
56239         function resetOffset() {
56240             if (event.button !== 0) return;
56241             context.background().offset([0, 0]);
56242             updateOffsetVal();
56243         }
56244
56245
56246         function nudge(d) {
56247             context.background().nudge(d, context.map().zoom());
56248             updateOffsetVal();
56249         }
56250
56251
56252         function buttonOffset(d) {
56253             if (event.button !== 0) return;
56254             var timeout$$1 = window.setTimeout(function() {
56255                     interval$$1 = window.setInterval(nudge.bind(null, d), 100);
56256                 }, 500),
56257                 interval$$1;
56258
56259             function doneNudge() {
56260                 window.clearTimeout(timeout$$1);
56261                 window.clearInterval(interval$$1);
56262                 select(window)
56263                     .on('mouseup.buttonoffset', null, true)
56264                     .on('mousedown.buttonoffset', null, true);
56265             }
56266
56267             select(window)
56268                 .on('mouseup.buttonoffset', doneNudge, true)
56269                 .on('mousedown.buttonoffset', doneNudge, true);
56270
56271             nudge(d);
56272         }
56273
56274
56275         function inputOffset() {
56276             if (event.button !== 0) return;
56277             var input = select(this);
56278             var d = input.node().value;
56279
56280             if (d === '') return resetOffset();
56281
56282             d = d.replace(/;/g, ',').split(',').map(function(n) {
56283                 // if n is NaN, it will always get mapped to false.
56284                 return !isNaN(n) && n;
56285             });
56286
56287             if (d.length !== 2 || !d[0] || !d[1]) {
56288                 input.classed('error', true);
56289                 return;
56290             }
56291
56292             context.background().offset(geoMetersToOffset(d));
56293             updateOffsetVal();
56294         }
56295
56296
56297         function dragOffset() {
56298             if (event.button !== 0) return;
56299             var origin = [event.clientX, event.clientY];
56300
56301             context.container()
56302                 .append('div')
56303                 .attr('class', 'nudge-surface');
56304
56305             select(window)
56306                 .on('mousemove.offset', function() {
56307                     var latest = [event.clientX, event.clientY];
56308                     var d = [
56309                         -(origin[0] - latest[0]) / 4,
56310                         -(origin[1] - latest[1]) / 4
56311                     ];
56312
56313                     origin = latest;
56314                     nudge(d);
56315                 })
56316                 .on('mouseup.offset', function() {
56317                     if (event.button !== 0) return;
56318                     selectAll('.nudge-surface')
56319                         .remove();
56320
56321                     select(window)
56322                         .on('mousemove.offset', null)
56323                         .on('mouseup.offset', null);
56324                 });
56325
56326             event.preventDefault();
56327         }
56328
56329
56330         function hide() {
56331             setVisible(false);
56332         }
56333
56334
56335         function toggle() {
56336             if (event) event.preventDefault();
56337             tooltipBehavior.hide(button);
56338             setVisible(!button.classed('active'));
56339         }
56340
56341
56342         function quickSwitch() {
56343             if (previous) {
56344                 clickSetSource(previous);
56345             }
56346         }
56347
56348
56349         function setVisible(show) {
56350             if (show !== shown) {
56351                 button.classed('active', show);
56352                 shown = show;
56353
56354                 if (show) {
56355                     selection$$1
56356                         .on('mousedown.background-inside', function() {
56357                             event.stopPropagation();
56358                         });
56359
56360                     content
56361                         .style('display', 'block')
56362                         .style('right', '-300px')
56363                         .transition()
56364                         .duration(200)
56365                         .style('right', '0px');
56366
56367                     content.selectAll('.layer, .custom_layer')
56368                         .call(setTooltips);
56369
56370                 } else {
56371                     content
56372                         .style('display', 'block')
56373                         .style('right', '0px')
56374                         .transition()
56375                         .duration(200)
56376                         .style('right', '-300px')
56377                         .on('end', function() {
56378                             select(this).style('display', 'none');
56379                         });
56380
56381                     selection$$1
56382                         .on('mousedown.background-inside', null);
56383                 }
56384             }
56385         }
56386
56387
56388         var content = selection$$1
56389                 .append('div')
56390                 .attr('class', 'fillL map-overlay col3 content hide'),
56391             tooltipBehavior = tooltip()
56392                 .placement((textDirection === 'rtl') ? 'right' : 'left')
56393                 .html(true)
56394                 .title(uiTooltipHtml(t('background.description'), key)),
56395             button = selection$$1
56396                 .append('button')
56397                 .attr('tabindex', -1)
56398                 .on('click', toggle)
56399                 .call(svgIcon('#icon-layers', 'light'))
56400                 .call(tooltipBehavior),
56401             shown = false;
56402
56403
56404         /* opacity switcher */
56405
56406         var opawrap = content
56407                 .append('div')
56408                 .attr('class', 'opacity-options-wrapper');
56409
56410         opawrap
56411             .append('h4')
56412             .text(t('background.title'));
56413
56414         var opacityList = opawrap
56415             .append('ul')
56416             .attr('class', 'opacity-options');
56417
56418         opacityList.selectAll('div.opacity')
56419             .data(opacities)
56420             .enter()
56421             .append('li')
56422             .attr('data-original-title', function(d) {
56423                 return t('background.percent_brightness', { opacity: (d * 100) });
56424             })
56425             .on('click.set-opacity', setOpacity)
56426             .html('<div class="select-box"></div>')
56427             .call(tooltip()
56428                 .placement((textDirection === 'rtl') ? 'right' : 'left'))
56429             .append('div')
56430             .attr('class', 'opacity')
56431             .style('opacity', function(d) { return 1.25 - d; });
56432
56433
56434         /* background switcher */
56435
56436         var backgroundList = content
56437             .append('ul')
56438             .attr('class', 'layer-list')
56439             .attr('dir', 'auto');
56440
56441         var custom = backgroundList
56442             .append('li')
56443             .attr('class', 'custom_layer')
56444             .datum(rendererBackgroundSource.Custom());
56445
56446         custom
56447             .append('button')
56448             .attr('class', 'layer-browse')
56449             .call(tooltip()
56450                 .title(t('background.custom_button'))
56451                 .placement((textDirection === 'rtl') ? 'right' : 'left'))
56452             .on('click', editCustom)
56453             .call(svgIcon('#icon-search'));
56454
56455         var label = custom
56456             .append('label');
56457
56458         label
56459             .append('input')
56460             .attr('type', 'radio')
56461             .attr('name', 'layers')
56462             .on('change', function () {
56463                 if (customTemplate) {
56464                     setCustom(customTemplate);
56465                 } else {
56466                     editCustom();
56467                 }
56468             });
56469
56470         label
56471             .append('span')
56472             .text(t('background.custom'));
56473
56474         content
56475             .append('div')
56476             .attr('class', 'imagery-faq')
56477             .append('a')
56478             .attr('target', '_blank')
56479             .attr('tabindex', -1)
56480             .call(svgIcon('#icon-out-link', 'inline'))
56481             .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
56482             .append('span')
56483             .text(t('background.imagery_source_faq'));
56484
56485         var overlayList = content
56486             .append('ul')
56487             .attr('class', 'layer-list');
56488
56489         var controls = content
56490             .append('div')
56491             .attr('class', 'controls-list');
56492
56493
56494         /* minimap toggle */
56495
56496         var minimapLabel = controls
56497             .append('label')
56498             .call(tooltip()
56499                 .html(true)
56500                 .title(uiTooltipHtml(t('background.minimap.tooltip'), '/'))
56501                 .placement('top')
56502             );
56503
56504         minimapLabel
56505             .classed('minimap-toggle', true)
56506             .append('input')
56507             .attr('type', 'checkbox')
56508             .on('change', function() {
56509                 uiMapInMap.toggle();
56510                 event.preventDefault();
56511             });
56512
56513         minimapLabel
56514             .append('span')
56515             .text(t('background.minimap.description'));
56516
56517
56518         /* imagery offset controls */
56519
56520         var adjustments = content
56521             .append('div')
56522             .attr('class', 'adjustments');
56523
56524         adjustments
56525             .append('a')
56526             .text(t('background.fix_misalignment'))
56527             .attr('href', '#')
56528             .classed('hide-toggle', true)
56529             .classed('expanded', false)
56530             .on('click', function() {
56531                 if (event.button !== 0) return;
56532                 var exp = select(this).classed('expanded');
56533                 nudgeContainer.style('display', exp ? 'none' : 'block');
56534                 select(this).classed('expanded', !exp);
56535                 event.preventDefault();
56536             });
56537
56538         var nudgeContainer = adjustments
56539             .append('div')
56540             .attr('class', 'nudge-container cf')
56541             .style('display', 'none');
56542
56543         nudgeContainer
56544             .append('div')
56545             .attr('class', 'nudge-instructions')
56546             .text(t('background.offset'));
56547
56548         var nudgeRect = nudgeContainer
56549             .append('div')
56550             .attr('class', 'nudge-outer-rect')
56551             .on('mousedown', dragOffset);
56552
56553         nudgeRect
56554             .append('div')
56555             .attr('class', 'nudge-inner-rect')
56556             .append('input')
56557             .on('change', inputOffset)
56558             .on('mousedown', function() {
56559                 if (event.button !== 0) return;
56560                 event.stopPropagation();
56561             });
56562
56563         nudgeContainer
56564             .append('div')
56565             .selectAll('button')
56566             .data(directions).enter()
56567             .append('button')
56568             .attr('class', function(d) { return d[0] + ' nudge'; })
56569             .on('mousedown', function(d) {
56570                 if (event.button !== 0) return;
56571                 buttonOffset(d[1]);
56572             });
56573
56574         nudgeContainer
56575             .append('button')
56576             .attr('title', t('background.reset'))
56577             .attr('class', 'nudge-reset disabled')
56578             .on('click', resetOffset)
56579             .call(
56580                 (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
56581             );
56582
56583         context.map()
56584             .on('move.background-update', lodash.debounce(update, 1000));
56585
56586         context.background()
56587             .on('change.background-update', update);
56588
56589
56590         update();
56591         setOpacity(opacityDefault);
56592
56593         var keybinding = d3keybinding('background')
56594             .on(key, toggle)
56595             .on(uiCmd('⌘B'), quickSwitch)
56596             .on('F', hide)
56597             .on('H', hide);
56598
56599         select(document)
56600             .call(keybinding);
56601
56602         context.surface().on('mousedown.background-outside', hide);
56603         context.container().on('mousedown.background-outside', hide);
56604     }
56605
56606     return background;
56607 }
56608
56609 function uiContributors(context) {
56610     var debouncedUpdate = lodash.debounce(function() { update(); }, 1000),
56611         limit = 4,
56612         hidden = false,
56613         wrap = select(null);
56614
56615
56616     function update() {
56617         var users = {},
56618             entities = context.intersects(context.map().extent());
56619
56620         entities.forEach(function(entity) {
56621             if (entity && entity.user) users[entity.user] = true;
56622         });
56623
56624         var u = Object.keys(users),
56625             subset = u.slice(0, u.length > limit ? limit - 1 : limit);
56626
56627         wrap.html('')
56628             .call(svgIcon('#icon-nearby', 'pre-text light'));
56629
56630         var userList = select(document.createElement('span'));
56631
56632         userList.selectAll()
56633             .data(subset)
56634             .enter()
56635             .append('a')
56636             .attr('class', 'user-link')
56637             .attr('href', function(d) { return context.connection().userURL(d); })
56638             .attr('target', '_blank')
56639             .attr('tabindex', -1)
56640             .text(String);
56641
56642         if (u.length > limit) {
56643             var count = select(document.createElement('span'));
56644
56645             count.append('a')
56646                 .attr('target', '_blank')
56647                 .attr('tabindex', -1)
56648                 .attr('href', function() {
56649                     return context.connection().changesetsURL(context.map().center(), context.map().zoom());
56650                 })
56651                 .text(u.length - limit + 1);
56652
56653             wrap.append('span')
56654                 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
56655
56656         } else {
56657             wrap.append('span')
56658                 .html(t('contributors.list', { users: userList.html() }));
56659         }
56660
56661         if (!u.length) {
56662             hidden = true;
56663             wrap
56664                 .transition()
56665                 .style('opacity', 0);
56666
56667         } else if (hidden) {
56668             wrap
56669                 .transition()
56670                 .style('opacity', 1);
56671         }
56672     }
56673
56674
56675     return function(selection$$1) {
56676         wrap = selection$$1;
56677         update();
56678
56679         context.connection().on('loaded.contributors', debouncedUpdate);
56680         context.map().on('move.contributors', debouncedUpdate);
56681     };
56682 }
56683
56684 function uiFeatureInfo(context) {
56685     function update(selection$$1) {
56686         var features = context.features(),
56687             stats = features.stats(),
56688             count = 0,
56689             hiddenList = lodash.compact(lodash.map(features.hidden(), function(k) {
56690                 if (stats[k]) {
56691                     count += stats[k];
56692                     return String(stats[k]) + ' ' + t('feature.' + k + '.description');
56693                 }
56694             }));
56695
56696         selection$$1.html('');
56697
56698         if (hiddenList.length) {
56699             var tooltipBehavior = tooltip()
56700                     .placement('top')
56701                     .html(true)
56702                     .title(function() {
56703                         return uiTooltipHtml(hiddenList.join('<br/>'));
56704                     });
56705
56706             var warning = selection$$1.append('a')
56707                 .attr('href', '#')
56708                 .attr('tabindex', -1)
56709                 .html(t('feature_info.hidden_warning', { count: count }))
56710                 .call(tooltipBehavior)
56711                 .on('click', function() {
56712                     tooltipBehavior.hide(warning);
56713                     // open map data panel?
56714                     event.preventDefault();
56715                 });
56716         }
56717
56718         selection$$1
56719             .classed('hide', !hiddenList.length);
56720     }
56721
56722
56723     return function(selection$$1) {
56724         update(selection$$1);
56725
56726         context.features().on('change.feature_info', function() {
56727             update(selection$$1);
56728         });
56729     };
56730 }
56731
56732 function uiFullScreen(context) {
56733     var element = context.container().node(),
56734         keybinding = d3keybinding('full-screen');
56735         // button;
56736
56737
56738     function getFullScreenFn() {
56739         if (element.requestFullscreen) {
56740             return element.requestFullscreen;
56741         } else if (element.msRequestFullscreen) {
56742             return element.msRequestFullscreen;
56743         } else if (element.mozRequestFullScreen) {
56744             return element.mozRequestFullScreen;
56745         } else if (element.webkitRequestFullscreen) {
56746             return element.webkitRequestFullscreen;
56747         }
56748     }
56749
56750
56751     function getExitFullScreenFn() {
56752         if (document.exitFullscreen) {
56753             return document.exitFullscreen;
56754         } else if (document.msExitFullscreen) {
56755             return document.msExitFullscreen;
56756         } else if (document.mozCancelFullScreen) {
56757             return document.mozCancelFullScreen;
56758         } else if (document.webkitExitFullscreen) {
56759             return document.webkitExitFullscreen;
56760         }
56761     }
56762
56763
56764     function isFullScreen() {
56765         return document.fullscreenElement ||
56766             document.mozFullScreenElement ||
56767             document.webkitFullscreenElement ||
56768             document.msFullscreenElement;
56769     }
56770
56771
56772     function isSupported() {
56773         return !!getFullScreenFn();
56774     }
56775
56776
56777     function fullScreen() {
56778         event.preventDefault();
56779         if (!isFullScreen()) {
56780             // button.classed('active', true);
56781             getFullScreenFn().apply(element);
56782         } else {
56783             // button.classed('active', false);
56784             getExitFullScreenFn().apply(document);
56785         }
56786     }
56787
56788
56789     return function() { // selection) {
56790         if (!isSupported())
56791             return;
56792
56793         // button = selection.append('button')
56794         //     .attr('title', t('full_screen'))
56795         //     .attr('tabindex', -1)
56796         //     .on('click', fullScreen)
56797         //     .call(tooltip);
56798
56799         // button.append('span')
56800         //     .attr('class', 'icon full-screen');
56801
56802         keybinding
56803             .on('f11', fullScreen)
56804             .on(uiCmd('⌘⇧F'), fullScreen);
56805
56806         select(document)
56807             .call(keybinding);
56808     };
56809 }
56810
56811 function uiModal(selection$$1, blocking) {
56812     var keybinding = d3keybinding('modal');
56813     var previous = selection$$1.select('div.modal');
56814     var animate = previous.empty();
56815
56816     previous.transition()
56817         .duration(200)
56818         .style('opacity', 0)
56819         .remove();
56820
56821     var shaded = selection$$1
56822         .append('div')
56823         .attr('class', 'shaded')
56824         .style('opacity', 0);
56825
56826     shaded.close = function() {
56827         shaded
56828             .transition()
56829             .duration(200)
56830             .style('opacity',0)
56831             .remove();
56832
56833         modal
56834             .transition()
56835             .duration(200)
56836             .style('top','0px');
56837
56838         keybinding.off();
56839     };
56840
56841
56842     var modal = shaded
56843         .append('div')
56844         .attr('class', 'modal fillL col6');
56845
56846     if (!blocking) {
56847         shaded.on('click.remove-modal', function() {
56848             if (event.target === this) {
56849                 shaded.close();
56850             }
56851         });
56852
56853         modal.append('button')
56854             .attr('class', 'close')
56855             .on('click', shaded.close)
56856             .call(svgIcon('#icon-close'));
56857
56858         keybinding
56859             .on('⌫', shaded.close)
56860             .on('⎋', shaded.close);
56861
56862         select(document)
56863             .call(keybinding);
56864     }
56865
56866     modal
56867         .append('div')
56868         .attr('class', 'content');
56869
56870     if (animate) {
56871         shaded.transition().style('opacity', 1);
56872     } else {
56873         shaded.style('opacity', 1);
56874     }
56875
56876
56877     return shaded;
56878 }
56879
56880 function uiLoading(context) {
56881     var message = '',
56882         blocking = false,
56883         modalSelection;
56884
56885
56886     var loading = function(selection) {
56887         modalSelection = uiModal(selection, blocking);
56888
56889         var loadertext = modalSelection.select('.content')
56890             .classed('loading-modal', true)
56891             .append('div')
56892             .attr('class', 'modal-section fillL');
56893
56894         loadertext
56895             .append('img')
56896             .attr('class', 'loader')
56897             .attr('src', context.imagePath('loader-white.gif'));
56898
56899         loadertext
56900             .append('h3')
56901             .text(message);
56902
56903         modalSelection.select('button.close')
56904             .attr('class', 'hide');
56905
56906         return loading;
56907     };
56908
56909
56910     loading.message = function(_) {
56911         if (!arguments.length) return message;
56912         message = _;
56913         return loading;
56914     };
56915
56916
56917     loading.blocking = function(_) {
56918         if (!arguments.length) return blocking;
56919         blocking = _;
56920         return loading;
56921     };
56922
56923
56924     loading.close = function() {
56925         modalSelection.remove();
56926     };
56927
56928
56929     return loading;
56930 }
56931
56932 function uiGeolocate(context) {
56933     var geoOptions = { enableHighAccuracy: false, timeout: 6000 /* 6sec */ },
56934         locating = uiLoading(context).message(t('geolocate.locating')).blocking(true),
56935         timeoutId;
56936
56937
56938     function click() {
56939         if (context.inIntro()) return;
56940         context.enter(modeBrowse(context));
56941         context.container().call(locating);
56942         navigator.geolocation.getCurrentPosition(success, error, geoOptions);
56943
56944         // This timeout ensures that we still call finish() even if
56945         // the user declines to share their location in Firefox
56946         timeoutId = setTimeout(finish, 10000 /* 10sec */ );
56947     }
56948
56949
56950     function success(position) {
56951         var map = context.map(),
56952             extent = geoExtent$$1([position.coords.longitude, position.coords.latitude])
56953                 .padByMeters(position.coords.accuracy);
56954
56955         map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
56956         finish();
56957     }
56958
56959
56960     function error() {
56961         finish();
56962     }
56963
56964
56965     function finish() {
56966         locating.close();  // unblock ui
56967         if (timeoutId) { clearTimeout(timeoutId); }
56968         timeoutId = undefined;
56969     }
56970
56971
56972     return function(selection) {
56973         if (!navigator.geolocation) return;
56974
56975         selection
56976             .append('button')
56977             .attr('tabindex', -1)
56978             .attr('title', t('geolocate.title'))
56979             .on('click', click)
56980             .call(svgIcon('#icon-geolocate', 'light'))
56981             .call(tooltip()
56982                 .placement((textDirection === 'rtl') ? 'right' : 'left'));
56983     };
56984 }
56985
56986 var marked = createCommonjsModule(function (module, exports) {
56987 /**
56988  * marked - a markdown parser
56989  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
56990  * https://github.com/chjj/marked
56991  */
56992
56993 (function() {
56994
56995 /**
56996  * Block-Level Grammar
56997  */
56998
56999 var block = {
57000   newline: /^\n+/,
57001   code: /^( {4}[^\n]+\n*)+/,
57002   fences: noop,
57003   hr: /^( *[-*_]){3,} *(?:\n+|$)/,
57004   heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
57005   nptable: noop,
57006   lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
57007   blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
57008   list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
57009   html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
57010   def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
57011   table: noop,
57012   paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
57013   text: /^[^\n]+/
57014 };
57015
57016 block.bullet = /(?:[*+-]|\d+\.)/;
57017 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
57018 block.item = replace(block.item, 'gm')
57019   (/bull/g, block.bullet)
57020   ();
57021
57022 block.list = replace(block.list)
57023   (/bull/g, block.bullet)
57024   ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
57025   ('def', '\\n+(?=' + block.def.source + ')')
57026   ();
57027
57028 block.blockquote = replace(block.blockquote)
57029   ('def', block.def)
57030   ();
57031
57032 block._tag = '(?!(?:'
57033   + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
57034   + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
57035   + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
57036
57037 block.html = replace(block.html)
57038   ('comment', /<!--[\s\S]*?-->/)
57039   ('closed', /<(tag)[\s\S]+?<\/\1>/)
57040   ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
57041   (/tag/g, block._tag)
57042   ();
57043
57044 block.paragraph = replace(block.paragraph)
57045   ('hr', block.hr)
57046   ('heading', block.heading)
57047   ('lheading', block.lheading)
57048   ('blockquote', block.blockquote)
57049   ('tag', '<' + block._tag)
57050   ('def', block.def)
57051   ();
57052
57053 /**
57054  * Normal Block Grammar
57055  */
57056
57057 block.normal = merge({}, block);
57058
57059 /**
57060  * GFM Block Grammar
57061  */
57062
57063 block.gfm = merge({}, block.normal, {
57064   fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
57065   paragraph: /^/,
57066   heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
57067 });
57068
57069 block.gfm.paragraph = replace(block.paragraph)
57070   ('(?!', '(?!'
57071     + block.gfm.fences.source.replace('\\1', '\\2') + '|'
57072     + block.list.source.replace('\\1', '\\3') + '|')
57073   ();
57074
57075 /**
57076  * GFM + Tables Block Grammar
57077  */
57078
57079 block.tables = merge({}, block.gfm, {
57080   nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
57081   table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
57082 });
57083
57084 /**
57085  * Block Lexer
57086  */
57087
57088 function Lexer(options) {
57089   this.tokens = [];
57090   this.tokens.links = {};
57091   this.options = options || marked.defaults;
57092   this.rules = block.normal;
57093
57094   if (this.options.gfm) {
57095     if (this.options.tables) {
57096       this.rules = block.tables;
57097     } else {
57098       this.rules = block.gfm;
57099     }
57100   }
57101 }
57102
57103 /**
57104  * Expose Block Rules
57105  */
57106
57107 Lexer.rules = block;
57108
57109 /**
57110  * Static Lex Method
57111  */
57112
57113 Lexer.lex = function(src, options) {
57114   var lexer = new Lexer(options);
57115   return lexer.lex(src);
57116 };
57117
57118 /**
57119  * Preprocessing
57120  */
57121
57122 Lexer.prototype.lex = function(src) {
57123   src = src
57124     .replace(/\r\n|\r/g, '\n')
57125     .replace(/\t/g, '    ')
57126     .replace(/\u00a0/g, ' ')
57127     .replace(/\u2424/g, '\n');
57128
57129   return this.token(src, true);
57130 };
57131
57132 /**
57133  * Lexing
57134  */
57135
57136 Lexer.prototype.token = function(src, top, bq) {
57137   var src = src.replace(/^ +$/gm, '')
57138     , next
57139     , loose
57140     , cap
57141     , bull
57142     , b
57143     , item
57144     , space
57145     , i
57146     , l;
57147
57148   while (src) {
57149     // newline
57150     if (cap = this.rules.newline.exec(src)) {
57151       src = src.substring(cap[0].length);
57152       if (cap[0].length > 1) {
57153         this.tokens.push({
57154           type: 'space'
57155         });
57156       }
57157     }
57158
57159     // code
57160     if (cap = this.rules.code.exec(src)) {
57161       src = src.substring(cap[0].length);
57162       cap = cap[0].replace(/^ {4}/gm, '');
57163       this.tokens.push({
57164         type: 'code',
57165         text: !this.options.pedantic
57166           ? cap.replace(/\n+$/, '')
57167           : cap
57168       });
57169       continue;
57170     }
57171
57172     // fences (gfm)
57173     if (cap = this.rules.fences.exec(src)) {
57174       src = src.substring(cap[0].length);
57175       this.tokens.push({
57176         type: 'code',
57177         lang: cap[2],
57178         text: cap[3] || ''
57179       });
57180       continue;
57181     }
57182
57183     // heading
57184     if (cap = this.rules.heading.exec(src)) {
57185       src = src.substring(cap[0].length);
57186       this.tokens.push({
57187         type: 'heading',
57188         depth: cap[1].length,
57189         text: cap[2]
57190       });
57191       continue;
57192     }
57193
57194     // table no leading pipe (gfm)
57195     if (top && (cap = this.rules.nptable.exec(src))) {
57196       src = src.substring(cap[0].length);
57197
57198       item = {
57199         type: 'table',
57200         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
57201         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
57202         cells: cap[3].replace(/\n$/, '').split('\n')
57203       };
57204
57205       for (i = 0; i < item.align.length; i++) {
57206         if (/^ *-+: *$/.test(item.align[i])) {
57207           item.align[i] = 'right';
57208         } else if (/^ *:-+: *$/.test(item.align[i])) {
57209           item.align[i] = 'center';
57210         } else if (/^ *:-+ *$/.test(item.align[i])) {
57211           item.align[i] = 'left';
57212         } else {
57213           item.align[i] = null;
57214         }
57215       }
57216
57217       for (i = 0; i < item.cells.length; i++) {
57218         item.cells[i] = item.cells[i].split(/ *\| */);
57219       }
57220
57221       this.tokens.push(item);
57222
57223       continue;
57224     }
57225
57226     // lheading
57227     if (cap = this.rules.lheading.exec(src)) {
57228       src = src.substring(cap[0].length);
57229       this.tokens.push({
57230         type: 'heading',
57231         depth: cap[2] === '=' ? 1 : 2,
57232         text: cap[1]
57233       });
57234       continue;
57235     }
57236
57237     // hr
57238     if (cap = this.rules.hr.exec(src)) {
57239       src = src.substring(cap[0].length);
57240       this.tokens.push({
57241         type: 'hr'
57242       });
57243       continue;
57244     }
57245
57246     // blockquote
57247     if (cap = this.rules.blockquote.exec(src)) {
57248       src = src.substring(cap[0].length);
57249
57250       this.tokens.push({
57251         type: 'blockquote_start'
57252       });
57253
57254       cap = cap[0].replace(/^ *> ?/gm, '');
57255
57256       // Pass `top` to keep the current
57257       // "toplevel" state. This is exactly
57258       // how markdown.pl works.
57259       this.token(cap, top, true);
57260
57261       this.tokens.push({
57262         type: 'blockquote_end'
57263       });
57264
57265       continue;
57266     }
57267
57268     // list
57269     if (cap = this.rules.list.exec(src)) {
57270       src = src.substring(cap[0].length);
57271       bull = cap[2];
57272
57273       this.tokens.push({
57274         type: 'list_start',
57275         ordered: bull.length > 1
57276       });
57277
57278       // Get each top-level item.
57279       cap = cap[0].match(this.rules.item);
57280
57281       next = false;
57282       l = cap.length;
57283       i = 0;
57284
57285       for (; i < l; i++) {
57286         item = cap[i];
57287
57288         // Remove the list item's bullet
57289         // so it is seen as the next token.
57290         space = item.length;
57291         item = item.replace(/^ *([*+-]|\d+\.) +/, '');
57292
57293         // Outdent whatever the
57294         // list item contains. Hacky.
57295         if (~item.indexOf('\n ')) {
57296           space -= item.length;
57297           item = !this.options.pedantic
57298             ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
57299             : item.replace(/^ {1,4}/gm, '');
57300         }
57301
57302         // Determine whether the next list item belongs here.
57303         // Backpedal if it does not belong in this list.
57304         if (this.options.smartLists && i !== l - 1) {
57305           b = block.bullet.exec(cap[i + 1])[0];
57306           if (bull !== b && !(bull.length > 1 && b.length > 1)) {
57307             src = cap.slice(i + 1).join('\n') + src;
57308             i = l - 1;
57309           }
57310         }
57311
57312         // Determine whether item is loose or not.
57313         // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
57314         // for discount behavior.
57315         loose = next || /\n\n(?!\s*$)/.test(item);
57316         if (i !== l - 1) {
57317           next = item.charAt(item.length - 1) === '\n';
57318           if (!loose) loose = next;
57319         }
57320
57321         this.tokens.push({
57322           type: loose
57323             ? 'loose_item_start'
57324             : 'list_item_start'
57325         });
57326
57327         // Recurse.
57328         this.token(item, false, bq);
57329
57330         this.tokens.push({
57331           type: 'list_item_end'
57332         });
57333       }
57334
57335       this.tokens.push({
57336         type: 'list_end'
57337       });
57338
57339       continue;
57340     }
57341
57342     // html
57343     if (cap = this.rules.html.exec(src)) {
57344       src = src.substring(cap[0].length);
57345       this.tokens.push({
57346         type: this.options.sanitize
57347           ? 'paragraph'
57348           : 'html',
57349         pre: !this.options.sanitizer
57350           && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
57351         text: cap[0]
57352       });
57353       continue;
57354     }
57355
57356     // def
57357     if ((!bq && top) && (cap = this.rules.def.exec(src))) {
57358       src = src.substring(cap[0].length);
57359       this.tokens.links[cap[1].toLowerCase()] = {
57360         href: cap[2],
57361         title: cap[3]
57362       };
57363       continue;
57364     }
57365
57366     // table (gfm)
57367     if (top && (cap = this.rules.table.exec(src))) {
57368       src = src.substring(cap[0].length);
57369
57370       item = {
57371         type: 'table',
57372         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
57373         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
57374         cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
57375       };
57376
57377       for (i = 0; i < item.align.length; i++) {
57378         if (/^ *-+: *$/.test(item.align[i])) {
57379           item.align[i] = 'right';
57380         } else if (/^ *:-+: *$/.test(item.align[i])) {
57381           item.align[i] = 'center';
57382         } else if (/^ *:-+ *$/.test(item.align[i])) {
57383           item.align[i] = 'left';
57384         } else {
57385           item.align[i] = null;
57386         }
57387       }
57388
57389       for (i = 0; i < item.cells.length; i++) {
57390         item.cells[i] = item.cells[i]
57391           .replace(/^ *\| *| *\| *$/g, '')
57392           .split(/ *\| */);
57393       }
57394
57395       this.tokens.push(item);
57396
57397       continue;
57398     }
57399
57400     // top-level paragraph
57401     if (top && (cap = this.rules.paragraph.exec(src))) {
57402       src = src.substring(cap[0].length);
57403       this.tokens.push({
57404         type: 'paragraph',
57405         text: cap[1].charAt(cap[1].length - 1) === '\n'
57406           ? cap[1].slice(0, -1)
57407           : cap[1]
57408       });
57409       continue;
57410     }
57411
57412     // text
57413     if (cap = this.rules.text.exec(src)) {
57414       // Top-level should never reach here.
57415       src = src.substring(cap[0].length);
57416       this.tokens.push({
57417         type: 'text',
57418         text: cap[0]
57419       });
57420       continue;
57421     }
57422
57423     if (src) {
57424       throw new
57425         Error('Infinite loop on byte: ' + src.charCodeAt(0));
57426     }
57427   }
57428
57429   return this.tokens;
57430 };
57431
57432 /**
57433  * Inline-Level Grammar
57434  */
57435
57436 var inline = {
57437   escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
57438   autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
57439   url: noop,
57440   tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
57441   link: /^!?\[(inside)\]\(href\)/,
57442   reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
57443   nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
57444   strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
57445   em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
57446   code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
57447   br: /^ {2,}\n(?!\s*$)/,
57448   del: noop,
57449   text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
57450 };
57451
57452 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
57453 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
57454
57455 inline.link = replace(inline.link)
57456   ('inside', inline._inside)
57457   ('href', inline._href)
57458   ();
57459
57460 inline.reflink = replace(inline.reflink)
57461   ('inside', inline._inside)
57462   ();
57463
57464 /**
57465  * Normal Inline Grammar
57466  */
57467
57468 inline.normal = merge({}, inline);
57469
57470 /**
57471  * Pedantic Inline Grammar
57472  */
57473
57474 inline.pedantic = merge({}, inline.normal, {
57475   strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
57476   em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
57477 });
57478
57479 /**
57480  * GFM Inline Grammar
57481  */
57482
57483 inline.gfm = merge({}, inline.normal, {
57484   escape: replace(inline.escape)('])', '~|])')(),
57485   url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
57486   del: /^~~(?=\S)([\s\S]*?\S)~~/,
57487   text: replace(inline.text)
57488     (']|', '~]|')
57489     ('|', '|https?://|')
57490     ()
57491 });
57492
57493 /**
57494  * GFM + Line Breaks Inline Grammar
57495  */
57496
57497 inline.breaks = merge({}, inline.gfm, {
57498   br: replace(inline.br)('{2,}', '*')(),
57499   text: replace(inline.gfm.text)('{2,}', '*')()
57500 });
57501
57502 /**
57503  * Inline Lexer & Compiler
57504  */
57505
57506 function InlineLexer(links, options) {
57507   this.options = options || marked.defaults;
57508   this.links = links;
57509   this.rules = inline.normal;
57510   this.renderer = this.options.renderer || new Renderer;
57511   this.renderer.options = this.options;
57512
57513   if (!this.links) {
57514     throw new
57515       Error('Tokens array requires a `links` property.');
57516   }
57517
57518   if (this.options.gfm) {
57519     if (this.options.breaks) {
57520       this.rules = inline.breaks;
57521     } else {
57522       this.rules = inline.gfm;
57523     }
57524   } else if (this.options.pedantic) {
57525     this.rules = inline.pedantic;
57526   }
57527 }
57528
57529 /**
57530  * Expose Inline Rules
57531  */
57532
57533 InlineLexer.rules = inline;
57534
57535 /**
57536  * Static Lexing/Compiling Method
57537  */
57538
57539 InlineLexer.output = function(src, links, options) {
57540   var inline = new InlineLexer(links, options);
57541   return inline.output(src);
57542 };
57543
57544 /**
57545  * Lexing/Compiling
57546  */
57547
57548 InlineLexer.prototype.output = function(src) {
57549   var out = ''
57550     , link
57551     , text
57552     , href
57553     , cap;
57554
57555   while (src) {
57556     // escape
57557     if (cap = this.rules.escape.exec(src)) {
57558       src = src.substring(cap[0].length);
57559       out += cap[1];
57560       continue;
57561     }
57562
57563     // autolink
57564     if (cap = this.rules.autolink.exec(src)) {
57565       src = src.substring(cap[0].length);
57566       if (cap[2] === '@') {
57567         text = cap[1].charAt(6) === ':'
57568           ? this.mangle(cap[1].substring(7))
57569           : this.mangle(cap[1]);
57570         href = this.mangle('mailto:') + text;
57571       } else {
57572         text = escape(cap[1]);
57573         href = text;
57574       }
57575       out += this.renderer.link(href, null, text);
57576       continue;
57577     }
57578
57579     // url (gfm)
57580     if (!this.inLink && (cap = this.rules.url.exec(src))) {
57581       src = src.substring(cap[0].length);
57582       text = escape(cap[1]);
57583       href = text;
57584       out += this.renderer.link(href, null, text);
57585       continue;
57586     }
57587
57588     // tag
57589     if (cap = this.rules.tag.exec(src)) {
57590       if (!this.inLink && /^<a /i.test(cap[0])) {
57591         this.inLink = true;
57592       } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
57593         this.inLink = false;
57594       }
57595       src = src.substring(cap[0].length);
57596       out += this.options.sanitize
57597         ? this.options.sanitizer
57598           ? this.options.sanitizer(cap[0])
57599           : escape(cap[0])
57600         : cap[0];
57601       continue;
57602     }
57603
57604     // link
57605     if (cap = this.rules.link.exec(src)) {
57606       src = src.substring(cap[0].length);
57607       this.inLink = true;
57608       out += this.outputLink(cap, {
57609         href: cap[2],
57610         title: cap[3]
57611       });
57612       this.inLink = false;
57613       continue;
57614     }
57615
57616     // reflink, nolink
57617     if ((cap = this.rules.reflink.exec(src))
57618         || (cap = this.rules.nolink.exec(src))) {
57619       src = src.substring(cap[0].length);
57620       link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
57621       link = this.links[link.toLowerCase()];
57622       if (!link || !link.href) {
57623         out += cap[0].charAt(0);
57624         src = cap[0].substring(1) + src;
57625         continue;
57626       }
57627       this.inLink = true;
57628       out += this.outputLink(cap, link);
57629       this.inLink = false;
57630       continue;
57631     }
57632
57633     // strong
57634     if (cap = this.rules.strong.exec(src)) {
57635       src = src.substring(cap[0].length);
57636       out += this.renderer.strong(this.output(cap[2] || cap[1]));
57637       continue;
57638     }
57639
57640     // em
57641     if (cap = this.rules.em.exec(src)) {
57642       src = src.substring(cap[0].length);
57643       out += this.renderer.em(this.output(cap[2] || cap[1]));
57644       continue;
57645     }
57646
57647     // code
57648     if (cap = this.rules.code.exec(src)) {
57649       src = src.substring(cap[0].length);
57650       out += this.renderer.codespan(escape(cap[2], true));
57651       continue;
57652     }
57653
57654     // br
57655     if (cap = this.rules.br.exec(src)) {
57656       src = src.substring(cap[0].length);
57657       out += this.renderer.br();
57658       continue;
57659     }
57660
57661     // del (gfm)
57662     if (cap = this.rules.del.exec(src)) {
57663       src = src.substring(cap[0].length);
57664       out += this.renderer.del(this.output(cap[1]));
57665       continue;
57666     }
57667
57668     // text
57669     if (cap = this.rules.text.exec(src)) {
57670       src = src.substring(cap[0].length);
57671       out += this.renderer.text(escape(this.smartypants(cap[0])));
57672       continue;
57673     }
57674
57675     if (src) {
57676       throw new
57677         Error('Infinite loop on byte: ' + src.charCodeAt(0));
57678     }
57679   }
57680
57681   return out;
57682 };
57683
57684 /**
57685  * Compile Link
57686  */
57687
57688 InlineLexer.prototype.outputLink = function(cap, link) {
57689   var href = escape(link.href)
57690     , title = link.title ? escape(link.title) : null;
57691
57692   return cap[0].charAt(0) !== '!'
57693     ? this.renderer.link(href, title, this.output(cap[1]))
57694     : this.renderer.image(href, title, escape(cap[1]));
57695 };
57696
57697 /**
57698  * Smartypants Transformations
57699  */
57700
57701 InlineLexer.prototype.smartypants = function(text) {
57702   if (!this.options.smartypants) return text;
57703   return text
57704     // em-dashes
57705     .replace(/---/g, '\u2014')
57706     // en-dashes
57707     .replace(/--/g, '\u2013')
57708     // opening singles
57709     .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
57710     // closing singles & apostrophes
57711     .replace(/'/g, '\u2019')
57712     // opening doubles
57713     .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
57714     // closing doubles
57715     .replace(/"/g, '\u201d')
57716     // ellipses
57717     .replace(/\.{3}/g, '\u2026');
57718 };
57719
57720 /**
57721  * Mangle Links
57722  */
57723
57724 InlineLexer.prototype.mangle = function(text) {
57725   if (!this.options.mangle) return text;
57726   var out = ''
57727     , l = text.length
57728     , i = 0
57729     , ch;
57730
57731   for (; i < l; i++) {
57732     ch = text.charCodeAt(i);
57733     if (Math.random() > 0.5) {
57734       ch = 'x' + ch.toString(16);
57735     }
57736     out += '&#' + ch + ';';
57737   }
57738
57739   return out;
57740 };
57741
57742 /**
57743  * Renderer
57744  */
57745
57746 function Renderer(options) {
57747   this.options = options || {};
57748 }
57749
57750 Renderer.prototype.code = function(code, lang, escaped) {
57751   if (this.options.highlight) {
57752     var out = this.options.highlight(code, lang);
57753     if (out != null && out !== code) {
57754       escaped = true;
57755       code = out;
57756     }
57757   }
57758
57759   if (!lang) {
57760     return '<pre><code>'
57761       + (escaped ? code : escape(code, true))
57762       + '\n</code></pre>';
57763   }
57764
57765   return '<pre><code class="'
57766     + this.options.langPrefix
57767     + escape(lang, true)
57768     + '">'
57769     + (escaped ? code : escape(code, true))
57770     + '\n</code></pre>\n';
57771 };
57772
57773 Renderer.prototype.blockquote = function(quote) {
57774   return '<blockquote>\n' + quote + '</blockquote>\n';
57775 };
57776
57777 Renderer.prototype.html = function(html) {
57778   return html;
57779 };
57780
57781 Renderer.prototype.heading = function(text, level, raw) {
57782   return '<h'
57783     + level
57784     + ' id="'
57785     + this.options.headerPrefix
57786     + raw.toLowerCase().replace(/[^\w]+/g, '-')
57787     + '">'
57788     + text
57789     + '</h'
57790     + level
57791     + '>\n';
57792 };
57793
57794 Renderer.prototype.hr = function() {
57795   return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
57796 };
57797
57798 Renderer.prototype.list = function(body, ordered) {
57799   var type = ordered ? 'ol' : 'ul';
57800   return '<' + type + '>\n' + body + '</' + type + '>\n';
57801 };
57802
57803 Renderer.prototype.listitem = function(text) {
57804   return '<li>' + text + '</li>\n';
57805 };
57806
57807 Renderer.prototype.paragraph = function(text) {
57808   return '<p>' + text + '</p>\n';
57809 };
57810
57811 Renderer.prototype.table = function(header, body) {
57812   return '<table>\n'
57813     + '<thead>\n'
57814     + header
57815     + '</thead>\n'
57816     + '<tbody>\n'
57817     + body
57818     + '</tbody>\n'
57819     + '</table>\n';
57820 };
57821
57822 Renderer.prototype.tablerow = function(content) {
57823   return '<tr>\n' + content + '</tr>\n';
57824 };
57825
57826 Renderer.prototype.tablecell = function(content, flags) {
57827   var type = flags.header ? 'th' : 'td';
57828   var tag = flags.align
57829     ? '<' + type + ' style="text-align:' + flags.align + '">'
57830     : '<' + type + '>';
57831   return tag + content + '</' + type + '>\n';
57832 };
57833
57834 // span level renderer
57835 Renderer.prototype.strong = function(text) {
57836   return '<strong>' + text + '</strong>';
57837 };
57838
57839 Renderer.prototype.em = function(text) {
57840   return '<em>' + text + '</em>';
57841 };
57842
57843 Renderer.prototype.codespan = function(text) {
57844   return '<code>' + text + '</code>';
57845 };
57846
57847 Renderer.prototype.br = function() {
57848   return this.options.xhtml ? '<br/>' : '<br>';
57849 };
57850
57851 Renderer.prototype.del = function(text) {
57852   return '<del>' + text + '</del>';
57853 };
57854
57855 Renderer.prototype.link = function(href, title, text) {
57856   if (this.options.sanitize) {
57857     try {
57858       var prot = decodeURIComponent(unescape(href))
57859         .replace(/[^\w:]/g, '')
57860         .toLowerCase();
57861     } catch (e) {
57862       return '';
57863     }
57864     if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
57865       return '';
57866     }
57867   }
57868   var out = '<a href="' + href + '"';
57869   if (title) {
57870     out += ' title="' + title + '"';
57871   }
57872   out += '>' + text + '</a>';
57873   return out;
57874 };
57875
57876 Renderer.prototype.image = function(href, title, text) {
57877   var out = '<img src="' + href + '" alt="' + text + '"';
57878   if (title) {
57879     out += ' title="' + title + '"';
57880   }
57881   out += this.options.xhtml ? '/>' : '>';
57882   return out;
57883 };
57884
57885 Renderer.prototype.text = function(text) {
57886   return text;
57887 };
57888
57889 /**
57890  * Parsing & Compiling
57891  */
57892
57893 function Parser(options) {
57894   this.tokens = [];
57895   this.token = null;
57896   this.options = options || marked.defaults;
57897   this.options.renderer = this.options.renderer || new Renderer;
57898   this.renderer = this.options.renderer;
57899   this.renderer.options = this.options;
57900 }
57901
57902 /**
57903  * Static Parse Method
57904  */
57905
57906 Parser.parse = function(src, options, renderer) {
57907   var parser = new Parser(options, renderer);
57908   return parser.parse(src);
57909 };
57910
57911 /**
57912  * Parse Loop
57913  */
57914
57915 Parser.prototype.parse = function(src) {
57916   this.inline = new InlineLexer(src.links, this.options, this.renderer);
57917   this.tokens = src.reverse();
57918
57919   var out = '';
57920   while (this.next()) {
57921     out += this.tok();
57922   }
57923
57924   return out;
57925 };
57926
57927 /**
57928  * Next Token
57929  */
57930
57931 Parser.prototype.next = function() {
57932   return this.token = this.tokens.pop();
57933 };
57934
57935 /**
57936  * Preview Next Token
57937  */
57938
57939 Parser.prototype.peek = function() {
57940   return this.tokens[this.tokens.length - 1] || 0;
57941 };
57942
57943 /**
57944  * Parse Text Tokens
57945  */
57946
57947 Parser.prototype.parseText = function() {
57948   var body = this.token.text;
57949
57950   while (this.peek().type === 'text') {
57951     body += '\n' + this.next().text;
57952   }
57953
57954   return this.inline.output(body);
57955 };
57956
57957 /**
57958  * Parse Current Token
57959  */
57960
57961 Parser.prototype.tok = function() {
57962   switch (this.token.type) {
57963     case 'space': {
57964       return '';
57965     }
57966     case 'hr': {
57967       return this.renderer.hr();
57968     }
57969     case 'heading': {
57970       return this.renderer.heading(
57971         this.inline.output(this.token.text),
57972         this.token.depth,
57973         this.token.text);
57974     }
57975     case 'code': {
57976       return this.renderer.code(this.token.text,
57977         this.token.lang,
57978         this.token.escaped);
57979     }
57980     case 'table': {
57981       var header = ''
57982         , body = ''
57983         , i
57984         , row
57985         , cell
57986         , flags
57987         , j;
57988
57989       // header
57990       cell = '';
57991       for (i = 0; i < this.token.header.length; i++) {
57992         flags = { header: true, align: this.token.align[i] };
57993         cell += this.renderer.tablecell(
57994           this.inline.output(this.token.header[i]),
57995           { header: true, align: this.token.align[i] }
57996         );
57997       }
57998       header += this.renderer.tablerow(cell);
57999
58000       for (i = 0; i < this.token.cells.length; i++) {
58001         row = this.token.cells[i];
58002
58003         cell = '';
58004         for (j = 0; j < row.length; j++) {
58005           cell += this.renderer.tablecell(
58006             this.inline.output(row[j]),
58007             { header: false, align: this.token.align[j] }
58008           );
58009         }
58010
58011         body += this.renderer.tablerow(cell);
58012       }
58013       return this.renderer.table(header, body);
58014     }
58015     case 'blockquote_start': {
58016       var body = '';
58017
58018       while (this.next().type !== 'blockquote_end') {
58019         body += this.tok();
58020       }
58021
58022       return this.renderer.blockquote(body);
58023     }
58024     case 'list_start': {
58025       var body = ''
58026         , ordered = this.token.ordered;
58027
58028       while (this.next().type !== 'list_end') {
58029         body += this.tok();
58030       }
58031
58032       return this.renderer.list(body, ordered);
58033     }
58034     case 'list_item_start': {
58035       var body = '';
58036
58037       while (this.next().type !== 'list_item_end') {
58038         body += this.token.type === 'text'
58039           ? this.parseText()
58040           : this.tok();
58041       }
58042
58043       return this.renderer.listitem(body);
58044     }
58045     case 'loose_item_start': {
58046       var body = '';
58047
58048       while (this.next().type !== 'list_item_end') {
58049         body += this.tok();
58050       }
58051
58052       return this.renderer.listitem(body);
58053     }
58054     case 'html': {
58055       var html = !this.token.pre && !this.options.pedantic
58056         ? this.inline.output(this.token.text)
58057         : this.token.text;
58058       return this.renderer.html(html);
58059     }
58060     case 'paragraph': {
58061       return this.renderer.paragraph(this.inline.output(this.token.text));
58062     }
58063     case 'text': {
58064       return this.renderer.paragraph(this.parseText());
58065     }
58066   }
58067 };
58068
58069 /**
58070  * Helpers
58071  */
58072
58073 function escape(html, encode) {
58074   return html
58075     .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
58076     .replace(/</g, '&lt;')
58077     .replace(/>/g, '&gt;')
58078     .replace(/"/g, '&quot;')
58079     .replace(/'/g, '&#39;');
58080 }
58081
58082 function unescape(html) {
58083         // explicitly match decimal, hex, and named HTML entities 
58084   return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
58085     n = n.toLowerCase();
58086     if (n === 'colon') return ':';
58087     if (n.charAt(0) === '#') {
58088       return n.charAt(1) === 'x'
58089         ? String.fromCharCode(parseInt(n.substring(2), 16))
58090         : String.fromCharCode(+n.substring(1));
58091     }
58092     return '';
58093   });
58094 }
58095
58096 function replace(regex, opt) {
58097   regex = regex.source;
58098   opt = opt || '';
58099   return function self(name, val) {
58100     if (!name) return new RegExp(regex, opt);
58101     val = val.source || val;
58102     val = val.replace(/(^|[^\[])\^/g, '$1');
58103     regex = regex.replace(name, val);
58104     return self;
58105   };
58106 }
58107
58108 function noop() {}
58109 noop.exec = noop;
58110
58111 function merge(obj) {
58112   var i = 1
58113     , target
58114     , key;
58115
58116   for (; i < arguments.length; i++) {
58117     target = arguments[i];
58118     for (key in target) {
58119       if (Object.prototype.hasOwnProperty.call(target, key)) {
58120         obj[key] = target[key];
58121       }
58122     }
58123   }
58124
58125   return obj;
58126 }
58127
58128
58129 /**
58130  * Marked
58131  */
58132
58133 function marked(src, opt, callback) {
58134   if (callback || typeof opt === 'function') {
58135     if (!callback) {
58136       callback = opt;
58137       opt = null;
58138     }
58139
58140     opt = merge({}, marked.defaults, opt || {});
58141
58142     var highlight = opt.highlight
58143       , tokens
58144       , pending
58145       , i = 0;
58146
58147     try {
58148       tokens = Lexer.lex(src, opt);
58149     } catch (e) {
58150       return callback(e);
58151     }
58152
58153     pending = tokens.length;
58154
58155     var done = function(err) {
58156       if (err) {
58157         opt.highlight = highlight;
58158         return callback(err);
58159       }
58160
58161       var out;
58162
58163       try {
58164         out = Parser.parse(tokens, opt);
58165       } catch (e) {
58166         err = e;
58167       }
58168
58169       opt.highlight = highlight;
58170
58171       return err
58172         ? callback(err)
58173         : callback(null, out);
58174     };
58175
58176     if (!highlight || highlight.length < 3) {
58177       return done();
58178     }
58179
58180     delete opt.highlight;
58181
58182     if (!pending) return done();
58183
58184     for (; i < tokens.length; i++) {
58185       (function(token) {
58186         if (token.type !== 'code') {
58187           return --pending || done();
58188         }
58189         return highlight(token.text, token.lang, function(err, code) {
58190           if (err) return done(err);
58191           if (code == null || code === token.text) {
58192             return --pending || done();
58193           }
58194           token.text = code;
58195           token.escaped = true;
58196           --pending || done();
58197         });
58198       })(tokens[i]);
58199     }
58200
58201     return;
58202   }
58203   try {
58204     if (opt) opt = merge({}, marked.defaults, opt);
58205     return Parser.parse(Lexer.lex(src, opt), opt);
58206   } catch (e) {
58207     e.message += '\nPlease report this to https://github.com/chjj/marked.';
58208     if ((opt || marked.defaults).silent) {
58209       return '<p>An error occured:</p><pre>'
58210         + escape(e.message + '', true)
58211         + '</pre>';
58212     }
58213     throw e;
58214   }
58215 }
58216
58217 /**
58218  * Options
58219  */
58220
58221 marked.options =
58222 marked.setOptions = function(opt) {
58223   merge(marked.defaults, opt);
58224   return marked;
58225 };
58226
58227 marked.defaults = {
58228   gfm: true,
58229   tables: true,
58230   breaks: false,
58231   pedantic: false,
58232   sanitize: false,
58233   sanitizer: null,
58234   mangle: true,
58235   smartLists: false,
58236   silent: false,
58237   highlight: null,
58238   langPrefix: 'lang-',
58239   smartypants: false,
58240   headerPrefix: '',
58241   renderer: new Renderer,
58242   xhtml: false
58243 };
58244
58245 /**
58246  * Expose
58247  */
58248
58249 marked.Parser = Parser;
58250 marked.parser = Parser.parse;
58251
58252 marked.Renderer = Renderer;
58253
58254 marked.Lexer = Lexer;
58255 marked.lexer = Lexer.lex;
58256
58257 marked.InlineLexer = InlineLexer;
58258 marked.inlineLexer = InlineLexer.output;
58259
58260 marked.parse = marked;
58261
58262 {
58263   module.exports = marked;
58264 }
58265
58266 }).call(function() {
58267   return this || (typeof window !== 'undefined' ? window : commonjsGlobal);
58268 }());
58269 });
58270
58271 function pointBox(loc, context) {
58272     var rect = context.surfaceRect();
58273     var point = context.curtainProjection(loc);
58274     return {
58275         left: point[0] + rect.left - 40,
58276         top: point[1] + rect.top - 60,
58277         width: 80,
58278         height: 90
58279     };
58280 }
58281
58282
58283 function pad$1(locOrBox, padding, context) {
58284     var box;
58285     if (locOrBox instanceof Array) {
58286         var rect = context.surfaceRect();
58287         var point = context.curtainProjection(locOrBox);
58288         box = {
58289             left: point[0] + rect.left,
58290             top: point[1] + rect.top
58291         };
58292     } else {
58293         box = locOrBox;
58294     }
58295
58296     return {
58297         left: box.left - padding,
58298         top: box.top - padding,
58299         width: (box.width || 0) + 2 * padding,
58300         height: (box.width || 0) + 2 * padding
58301     };
58302 }
58303
58304
58305 function icon(name, svgklass) {
58306     return '<svg class="icon ' + (svgklass || '') + '">' +
58307          '<use xlink:href="' + name + '"></use></svg>';
58308 }
58309
58310
58311 function slugify(text$$1) {
58312     return text$$1.toString().toLowerCase()
58313         .replace(/\s+/g, '-')           // Replace spaces with -
58314         .replace(/[^\w\-]+/g, '')       // Remove all non-word chars
58315         .replace(/\-\-+/g, '-')         // Replace multiple - with single -
58316         .replace(/^-+/, '')             // Trim - from start of text
58317         .replace(/-+$/, '');            // Trim - from end of text
58318 }
58319
58320
58321 // console warning for missing walkthrough names
58322 var missingStrings = {};
58323 function checkKey(key, text$$1) {
58324     if (t(key, { default: undefined}) === undefined) {
58325         if (missingStrings.hasOwnProperty(key)) return;  // warn once
58326         missingStrings[key] = text$$1;
58327         var missing = key + ': ' + text$$1;
58328         if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
58329     }
58330 }
58331
58332
58333 function localize(obj) {
58334     var key;
58335
58336     // Assign name if entity has one..
58337     var name = obj.tags && obj.tags.name;
58338     if (name) {
58339         key = 'intro.graph.name.' + slugify(name);
58340         obj.tags.name = t(key, { default: name });
58341         checkKey(key, name);
58342     }
58343
58344     // Assign street name if entity has one..
58345     var street = obj.tags && obj.tags['addr:street'];
58346     if (street) {
58347         key = 'intro.graph.name.' + slugify(street);
58348         obj.tags['addr:street'] = t(key, { default: street });
58349         checkKey(key, street);
58350
58351         // Add address details common across walkthrough..
58352         var addrTags = [
58353             'block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood',
58354             'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'
58355         ];
58356         addrTags.forEach(function(k) {
58357             var key = 'intro.graph.' + k,
58358                 tag = 'addr:' + k,
58359                 val = obj.tags && obj.tags[tag],
58360                 str = t(key, { default: val });
58361
58362             if (str) {
58363                 if (str.match(/^<.*>$/) !== null) {
58364                     delete obj.tags[tag];
58365                 } else {
58366                     obj.tags[tag] = str;
58367                 }
58368             }
58369         });
58370     }
58371
58372     return obj;
58373 }
58374
58375
58376 // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
58377 function isMostlySquare(points) {
58378     // note: uses 15 here instead of the 12 from actionOrthogonalize because
58379     // actionOrthogonalize can actually straighten some larger angles as it iterates
58380     var threshold = 15, // degrees within right or straight
58381         lowerBound = Math.cos((90 - threshold) * Math.PI / 180),  // near right
58382         upperBound = Math.cos(threshold * Math.PI / 180),         // near straight
58383         mag;
58384
58385     for (var i = 0; i < points.length; i++) {
58386         mag = Math.abs(normalizedDotProduct(i, points));
58387         if (mag > lowerBound && mag < upperBound) {
58388             return false;
58389         }
58390     }
58391
58392     return true;
58393
58394
58395     function normalizedDotProduct(i, points) {
58396         var a = points[(i - 1 + points.length) % points.length],
58397             b = points[i],
58398             c = points[(i + 1) % points.length],
58399             p = subtractPoints(a, b),
58400             q = subtractPoints(c, b);
58401
58402         p = normalizePoint(p);
58403         q = normalizePoint(q);
58404
58405         return p[0] * q[0] + p[1] * q[1];
58406
58407
58408         function subtractPoints(a, b) {
58409             return [a[0] - b[0], a[1] - b[1]];
58410         }
58411
58412         function normalizePoint(point) {
58413             var vector = [0, 0];
58414             var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
58415             if (length !== 0) {
58416                 vector[0] = point[0] / length;
58417                 vector[1] = point[1] / length;
58418             }
58419             return vector;
58420         }
58421     }
58422 }
58423
58424
58425 function selectMenuItem(operation) {
58426     var selector$$1 = '.edit-menu .edit-menu-item-' + operation +
58427         ', .radial-menu .radial-menu-item-' + operation;
58428     return select(selector$$1);
58429 }
58430
58431
58432 function transitionTime(point1, point2) {
58433     var distance = geoSphericalDistance(point1, point2);
58434     if (distance === 0)
58435         return 0;
58436     else if (distance < 80)
58437         return 500;
58438     else
58439         return 1000;
58440 }
58441
58442 var dataIntroGraph = {"n1":{"id":"n1","loc":[-85.631039,41.948829]},"n10":{"id":"n10","loc":[-85.634733,41.941588]},"n100":{"id":"n100","loc":[-85.637395,41.942252]},"n1000":{"id":"n1000","loc":[-85.632699,41.944763]},"n1001":{"id":"n1001","loc":[-85.632685,41.944763]},"n1002":{"id":"n1002","loc":[-85.632673,41.944755]},"n1003":{"id":"n1003","loc":[-85.632595,41.944682]},"n1004":{"id":"n1004","loc":[-85.632576,41.944673]},"n1005":{"id":"n1005","loc":[-85.632551,41.944667]},"n1006":{"id":"n1006","loc":[-85.63253,41.944667]},"n1007":{"id":"n1007","loc":[-85.632502,41.944669]},"n1008":{"id":"n1008","loc":[-85.632483,41.944677]},"n1009":{"id":"n1009","loc":[-85.632383,41.944731]},"n101":{"id":"n101","loc":[-85.637357,41.942252]},"n1010":{"id":"n1010","loc":[-85.63349,41.944976],"tags":{"addr:city":"Three Rivers","addr:housenumber":"31","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","name":"Sherwin-Williams","shop":"paint"}},"n1011":{"id":"n1011","loc":[-85.633548,41.945034],"tags":{"addr:city":"Three Rivers","addr:housenumber":"33","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","name":"Unique Jewelry","shop":"jewelry"}},"n1012":{"id":"n1012","loc":[-85.633683,41.945129],"tags":{"addr:city":"Three Rivers","addr:housenumber":"37","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","name":"World Fare","shop":"gift"}},"n1013":{"id":"n1013","loc":[-85.634563,41.945469],"tags":{"addr:city":"Three Rivers","addr:housenumber":"62","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","name":"Golden Finch Framing","shop":"frame"}},"n1014":{"id":"n1014","loc":[-85.634469,41.945379],"tags":{"addr:city":"Three Rivers","addr:housenumber":"58","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","name":"Dollar Tree","shop":"second_hand"}},"n1015":{"id":"n1015","loc":[-85.634227,41.945159],"tags":{"addr:city":"Three Rivers","addr:housenumber":"48","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","amenity":"theatre","name":"Riviera Theatre"}},"n1016":{"id":"n1016","loc":[-85.634057,41.945012],"tags":{"addr:city":"Three Rivers","addr:housenumber":"42","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","name":"River City Appliance","shop":"appliance"}},"n1017":{"id":"n1017","loc":[-85.633879,41.945325],"tags":{"addr:city":"Three Rivers","addr:housenumber":"45","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","name":"Paparazzi Tattoo","shop":"tattoo"}},"n1018":{"id":"n1018","loc":[-85.634914,41.945839],"tags":{"addr:city":"Three Rivers","addr:housenumber":"88","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","amenity":"bank","name":"Southern Michigan Bank"}},"n1019":{"id":"n1019","loc":[-85.634514,41.946176]},"n102":{"id":"n102","loc":[-85.637357,41.942216]},"n1020":{"id":"n1020","loc":[-85.634087,41.946178]},"n1021":{"id":"n1021","loc":[-85.634357,41.945805]},"n1022":{"id":"n1022","loc":[-85.634389,41.945788]},"n1023":{"id":"n1023","loc":[-85.634491,41.94581]},"n1024":{"id":"n1024","loc":[-85.634513,41.945853]},"n1025":{"id":"n1025","loc":[-85.634506,41.94583]},"n1026":{"id":"n1026","loc":[-85.634762,41.946056],"tags":{"crossing":"zebra","highway":"crossing"}},"n1027":{"id":"n1027","loc":[-85.634767,41.946172]},"n1028":{"id":"n1028","loc":[-85.634622,41.946175],"tags":{"crossing":"zebra","highway":"crossing"}},"n1029":{"id":"n1029","loc":[-85.640655,41.942057]},"n103":{"id":"n103","loc":[-85.637386,41.942054]},"n1030":{"id":"n1030","loc":[-85.640947,41.942057]},"n1031":{"id":"n1031","loc":[-85.640957,41.942593]},"n1032":{"id":"n1032","loc":[-85.630953,41.960873]},"n1033":{"id":"n1033","loc":[-85.632174,41.960679]},"n1034":{"id":"n1034","loc":[-85.638785,41.943066]},"n1035":{"id":"n1035","loc":[-85.638853,41.943065]},"n1036":{"id":"n1036","loc":[-85.638855,41.943183]},"n1037":{"id":"n1037","loc":[-85.638552,41.943189]},"n1038":{"id":"n1038","loc":[-85.63855,41.943149]},"n1039":{"id":"n1039","loc":[-85.638638,41.943068]},"n104":{"id":"n104","loc":[-85.637387,41.942125]},"n1040":{"id":"n1040","loc":[-85.638638,41.943078]},"n1041":{"id":"n1041","loc":[-85.638813,41.943163]},"n1042":{"id":"n1042","loc":[-85.638684,41.943165]},"n1043":{"id":"n1043","loc":[-85.638682,41.943105]},"n1044":{"id":"n1044","loc":[-85.638706,41.943105]},"n1045":{"id":"n1045","loc":[-85.638707,41.943117]},"n1046":{"id":"n1046","loc":[-85.638812,41.943115]},"n1047":{"id":"n1047","loc":[-85.638769,41.943407]},"n1048":{"id":"n1048","loc":[-85.638549,41.943407]},"n1049":{"id":"n1049","loc":[-85.638567,41.943555]},"n105":{"id":"n105","loc":[-85.637319,41.942125]},"n1050":{"id":"n1050","loc":[-85.638426,41.943554]},"n1051":{"id":"n1051","loc":[-85.638427,41.94346]},"n1052":{"id":"n1052","loc":[-85.638568,41.943461]},"n1053":{"id":"n1053","loc":[-85.639264,41.943415]},"n1054":{"id":"n1054","loc":[-85.639082,41.943417]},"n1055":{"id":"n1055","loc":[-85.63908,41.943331]},"n1056":{"id":"n1056","loc":[-85.639136,41.94333]},"n1057":{"id":"n1057","loc":[-85.639158,41.943312]},"n1058":{"id":"n1058","loc":[-85.639188,41.943313]},"n1059":{"id":"n1059","loc":[-85.639211,41.943331]},"n106":{"id":"n106","loc":[-85.637319,41.942137]},"n1060":{"id":"n1060","loc":[-85.639262,41.943331]},"n1061":{"id":"n1061","loc":[-85.638986,41.943515]},"n1062":{"id":"n1062","loc":[-85.63888,41.943521]},"n1063":{"id":"n1063","loc":[-85.638871,41.943436]},"n1064":{"id":"n1064","loc":[-85.638958,41.943431]},"n1065":{"id":"n1065","loc":[-85.638979,41.943443]},"n1066":{"id":"n1066","loc":[-85.63926,41.943703]},"n1067":{"id":"n1067","loc":[-85.639152,41.943704]},"n1068":{"id":"n1068","loc":[-85.639152,41.943691]},"n1069":{"id":"n1069","loc":[-85.639063,41.943691]},"n107":{"id":"n107","loc":[-85.637259,41.942137]},"n1070":{"id":"n1070","loc":[-85.639062,41.943613]},"n1071":{"id":"n1071","loc":[-85.639259,41.943611]},"n1072":{"id":"n1072","loc":[-85.639117,41.943726]},"n1073":{"id":"n1073","loc":[-85.639118,41.943767]},"n1074":{"id":"n1074","loc":[-85.639051,41.943768]},"n1075":{"id":"n1075","loc":[-85.63905,41.943727]},"n1076":{"id":"n1076","loc":[-85.638627,41.943716]},"n1077":{"id":"n1077","loc":[-85.63863,41.943634]},"n1078":{"id":"n1078","loc":[-85.63844,41.943631]},"n1079":{"id":"n1079","loc":[-85.638437,41.943729]},"n108":{"id":"n108","loc":[-85.637259,41.942126]},"n1080":{"id":"n1080","loc":[-85.638533,41.94373]},"n1081":{"id":"n1081","loc":[-85.638534,41.943715]},"n1082":{"id":"n1082","loc":[-85.638678,41.943941]},"n1083":{"id":"n1083","loc":[-85.638522,41.943944]},"n1084":{"id":"n1084","loc":[-85.63852,41.943864]},"n1085":{"id":"n1085","loc":[-85.638676,41.943861]},"n1086":{"id":"n1086","loc":[-85.638663,41.944059]},"n1087":{"id":"n1087","loc":[-85.638513,41.944061]},"n1088":{"id":"n1088","loc":[-85.638511,41.943991]},"n1089":{"id":"n1089","loc":[-85.638661,41.943989]},"n109":{"id":"n109","loc":[-85.637193,41.942126]},"n1090":{"id":"n1090","loc":[-85.63865,41.944134]},"n1091":{"id":"n1091","loc":[-85.638429,41.944144]},"n1092":{"id":"n1092","loc":[-85.638426,41.944106]},"n1093":{"id":"n1093","loc":[-85.638476,41.944104]},"n1094":{"id":"n1094","loc":[-85.638475,41.94409]},"n1095":{"id":"n1095","loc":[-85.638594,41.944084]},"n1096":{"id":"n1096","loc":[-85.638595,41.944101]},"n1097":{"id":"n1097","loc":[-85.638647,41.944099]},"n1098":{"id":"n1098","loc":[-85.63829,41.944154]},"n1099":{"id":"n1099","loc":[-85.638558,41.944155]},"n11":{"id":"n11","loc":[-85.634602,41.941523]},"n110":{"id":"n110","loc":[-85.637192,41.942053]},"n1100":{"id":"n1100","loc":[-85.638558,41.944338]},"n1101":{"id":"n1101","loc":[-85.638851,41.944408]},"n1102":{"id":"n1102","loc":[-85.637771,41.943989]},"n1103":{"id":"n1103","loc":[-85.639345,41.943964]},"n1104":{"id":"n1104","loc":[-85.638515,41.94397]},"n1105":{"id":"n1105","loc":[-85.639256,41.943928]},"n1106":{"id":"n1106","loc":[-85.639157,41.943929]},"n1107":{"id":"n1107","loc":[-85.639156,41.9439]},"n1108":{"id":"n1108","loc":[-85.639118,41.9439]},"n1109":{"id":"n1109","loc":[-85.639116,41.94382]},"n111":{"id":"n111","loc":[-85.637248,41.942053]},"n1110":{"id":"n1110","loc":[-85.639202,41.943819]},"n1111":{"id":"n1111","loc":[-85.639202,41.943837]},"n1112":{"id":"n1112","loc":[-85.639293,41.943836]},"n1113":{"id":"n1113","loc":[-85.639295,41.943898]},"n1114":{"id":"n1114","loc":[-85.639255,41.943898]},"n1115":{"id":"n1115","loc":[-85.639296,41.944083]},"n1116":{"id":"n1116","loc":[-85.639144,41.944084]},"n1117":{"id":"n1117","loc":[-85.639143,41.944026]},"n1118":{"id":"n1118","loc":[-85.639162,41.944026]},"n1119":{"id":"n1119","loc":[-85.639162,41.944]},"n112":{"id":"n112","loc":[-85.637248,41.942042]},"n1120":{"id":"n1120","loc":[-85.639295,41.943999]},"n1121":{"id":"n1121","loc":[-85.639131,41.944139]},"n1122":{"id":"n1122","loc":[-85.63901,41.94414]},"n1123":{"id":"n1123","loc":[-85.63901,41.944076]},"n1124":{"id":"n1124","loc":[-85.63913,41.944075]},"n1125":{"id":"n1125","loc":[-85.639092,41.944155]},"n1126":{"id":"n1126","loc":[-85.639093,41.944308]},"n1127":{"id":"n1127","loc":[-85.639225,41.944308]},"n1128":{"id":"n1128","loc":[-85.639225,41.94429]},"n1129":{"id":"n1129","loc":[-85.639253,41.944289]},"n113":{"id":"n113","loc":[-85.637338,41.942041]},"n1130":{"id":"n1130","loc":[-85.639253,41.944269]},"n1131":{"id":"n1131","loc":[-85.639243,41.944269]},"n1132":{"id":"n1132","loc":[-85.639243,41.944229]},"n1133":{"id":"n1133","loc":[-85.639224,41.944229]},"n1134":{"id":"n1134","loc":[-85.639224,41.944196]},"n1135":{"id":"n1135","loc":[-85.639195,41.944196]},"n1136":{"id":"n1136","loc":[-85.639195,41.944155]},"n1137":{"id":"n1137","loc":[-85.639072,41.944154]},"n1138":{"id":"n1138","loc":[-85.638865,41.944154]},"n1139":{"id":"n1139","loc":[-85.638863,41.943967]},"n114":{"id":"n114","loc":[-85.637338,41.942055]},"n1140":{"id":"n1140","loc":[-85.6386,41.942698]},"n1141":{"id":"n1141","loc":[-85.639348,41.942698]},"n1142":{"id":"n1142","loc":[-85.639377,41.944984]},"n1143":{"id":"n1143","loc":[-85.63937,41.945013]},"n1144":{"id":"n1144","loc":[-85.639357,41.945033]},"n1145":{"id":"n1145","loc":[-85.639353,41.945053]},"n1146":{"id":"n1146","loc":[-85.639352,41.945084]},"n1147":{"id":"n1147","loc":[-85.638278,41.945516]},"n1148":{"id":"n1148","loc":[-85.637505,41.945801]},"n1149":{"id":"n1149","loc":[-85.637327,41.945857]},"n115":{"id":"n115","loc":[-85.637583,41.941943]},"n1150":{"id":"n1150","loc":[-85.637168,41.945899]},"n1151":{"id":"n1151","loc":[-85.637017,41.94593]},"n1152":{"id":"n1152","loc":[-85.637185,41.945938]},"n1153":{"id":"n1153","loc":[-85.63682,41.945963]},"n1154":{"id":"n1154","loc":[-85.636639,41.945984]},"n1155":{"id":"n1155","loc":[-85.636439,41.945999]},"n1156":{"id":"n1156","loc":[-85.635801,41.945999]},"n1157":{"id":"n1157","loc":[-85.635769,41.945908]},"n1158":{"id":"n1158","loc":[-85.635953,41.946154]},"n1159":{"id":"n1159","loc":[-85.635472,41.94598]},"n116":{"id":"n116","loc":[-85.637584,41.941983]},"n1160":{"id":"n1160","loc":[-85.635409,41.945981]},"n1161":{"id":"n1161","loc":[-85.635583,41.945987]},"n1162":{"id":"n1162","loc":[-85.636452,41.945805]},"n1163":{"id":"n1163","loc":[-85.636425,41.94582]},"n1164":{"id":"n1164","loc":[-85.636396,41.945817]},"n1165":{"id":"n1165","loc":[-85.636368,41.945797]},"n1166":{"id":"n1166","loc":[-85.636346,41.945767]},"n1167":{"id":"n1167","loc":[-85.636307,41.945745]},"n1168":{"id":"n1168","loc":[-85.636194,41.94565]},"n1169":{"id":"n1169","loc":[-85.636121,41.945579]},"n117":{"id":"n117","loc":[-85.63751,41.941983]},"n1170":{"id":"n1170","loc":[-85.635995,41.945432]},"n1171":{"id":"n1171","loc":[-85.637564,41.943538]},"n1172":{"id":"n1172","loc":[-85.63756,41.943505]},"n1173":{"id":"n1173","loc":[-85.637435,41.943489]},"n1174":{"id":"n1174","loc":[-85.637093,41.943556]},"n1175":{"id":"n1175","loc":[-85.634836,41.941574]},"n1176":{"id":"n1176","loc":[-85.634692,41.9415]},"n1177":{"id":"n1177","loc":[-85.634261,41.941337]},"n1178":{"id":"n1178","loc":[-85.634208,41.940962]},"n1179":{"id":"n1179","loc":[-85.635247,41.940968]},"n118":{"id":"n118","loc":[-85.637509,41.941944]},"n1180":{"id":"n1180","loc":[-85.63514,41.941205]},"n1181":{"id":"n1181","loc":[-85.634858,41.941511]},"n1182":{"id":"n1182","loc":[-85.630725,41.943465]},"n1183":{"id":"n1183","loc":[-85.632591,41.942826]},"n1184":{"id":"n1184","loc":[-85.634487,41.941928]},"n1185":{"id":"n1185","loc":[-85.634499,41.942056]},"n1186":{"id":"n1186","loc":[-85.63433,41.943102]},"n1187":{"id":"n1187","loc":[-85.634158,41.943151]},"n1188":{"id":"n1188","loc":[-85.634107,41.94305]},"n1189":{"id":"n1189","loc":[-85.634279,41.943002]},"n119":{"id":"n119","loc":[-85.637724,41.941973]},"n1190":{"id":"n1190","loc":[-85.634362,41.943762]},"n1191":{"id":"n1191","loc":[-85.634331,41.943731]},"n1192":{"id":"n1192","loc":[-85.634396,41.943695]},"n1193":{"id":"n1193","loc":[-85.634426,41.943726]},"n1194":{"id":"n1194","loc":[-85.621569,41.956021]},"n1195":{"id":"n1195","loc":[-85.621574,41.956164]},"n1196":{"id":"n1196","loc":[-85.621489,41.956165]},"n1197":{"id":"n1197","loc":[-85.621488,41.956136]},"n1198":{"id":"n1198","loc":[-85.621372,41.956139]},"n1199":{"id":"n1199","loc":[-85.621369,41.956049]},"n12":{"id":"n12","loc":[-85.63359,41.941093]},"n120":{"id":"n120","loc":[-85.637633,41.941973]},"n1200":{"id":"n1200","loc":[-85.621493,41.956047]},"n1201":{"id":"n1201","loc":[-85.621492,41.956022]},"n1202":{"id":"n1202","loc":[-85.619744,41.953192]},"n1203":{"id":"n1203","loc":[-85.619059,41.953902]},"n1204":{"id":"n1204","loc":[-85.623984,41.95469]},"n1205":{"id":"n1205","loc":[-85.630159,41.958208]},"n1206":{"id":"n1206","loc":[-85.63002,41.958208]},"n1207":{"id":"n1207","loc":[-85.630021,41.95814]},"n1208":{"id":"n1208","loc":[-85.63,41.95814]},"n1209":{"id":"n1209","loc":[-85.63,41.958043]},"n121":{"id":"n121","loc":[-85.637633,41.941853]},"n1210":{"id":"n1210","loc":[-85.630159,41.958043]},"n1211":{"id":"n1211","loc":[-85.630304,41.957566]},"n1212":{"id":"n1212","loc":[-85.630303,41.957684]},"n1213":{"id":"n1213","loc":[-85.630073,41.957683]},"n1214":{"id":"n1214","loc":[-85.630072,41.957721]},"n1215":{"id":"n1215","loc":[-85.629993,41.95772]},"n1216":{"id":"n1216","loc":[-85.629993,41.95768]},"n1217":{"id":"n1217","loc":[-85.629968,41.95768]},"n1218":{"id":"n1218","loc":[-85.629969,41.957588]},"n1219":{"id":"n1219","loc":[-85.630219,41.95759]},"n122":{"id":"n122","loc":[-85.637724,41.941853]},"n1220":{"id":"n1220","loc":[-85.630219,41.957566]},"n1221":{"id":"n1221","loc":[-85.630717,41.957744]},"n1222":{"id":"n1222","loc":[-85.630596,41.957745]},"n1223":{"id":"n1223","loc":[-85.630598,41.957553]},"n1224":{"id":"n1224","loc":[-85.630717,41.957555]},"n1225":{"id":"n1225","loc":[-85.630609,41.957745]},"n1226":{"id":"n1226","loc":[-85.63061,41.957789]},"n1227":{"id":"n1227","loc":[-85.630327,41.957791]},"n1228":{"id":"n1228","loc":[-85.630324,41.95752]},"n1229":{"id":"n1229","loc":[-85.630325,41.95756]},"n123":{"id":"n123","loc":[-85.637773,41.941988]},"n1230":{"id":"n1230","loc":[-85.63057,41.95756]},"n1231":{"id":"n1231","loc":[-85.63069,41.958016]},"n1232":{"id":"n1232","loc":[-85.630586,41.958017]},"n1233":{"id":"n1233","loc":[-85.630584,41.957956]},"n1234":{"id":"n1234","loc":[-85.630614,41.957956]},"n1235":{"id":"n1235","loc":[-85.630611,41.957835]},"n1236":{"id":"n1236","loc":[-85.630737,41.957833]},"n1237":{"id":"n1237","loc":[-85.630739,41.957921]},"n1238":{"id":"n1238","loc":[-85.630688,41.957922]},"n1239":{"id":"n1239","loc":[-85.630719,41.958291]},"n124":{"id":"n124","loc":[-85.637773,41.942046]},"n1240":{"id":"n1240","loc":[-85.630592,41.958291]},"n1241":{"id":"n1241","loc":[-85.630593,41.958108]},"n1242":{"id":"n1242","loc":[-85.630701,41.958109]},"n1243":{"id":"n1243","loc":[-85.6307,41.958173]},"n1244":{"id":"n1244","loc":[-85.630711,41.958173]},"n1245":{"id":"n1245","loc":[-85.630711,41.958233]},"n1246":{"id":"n1246","loc":[-85.630719,41.958233]},"n1247":{"id":"n1247","loc":[-85.630523,41.958329]},"n1248":{"id":"n1248","loc":[-85.630388,41.958329]},"n1249":{"id":"n1249","loc":[-85.630387,41.958262]},"n125":{"id":"n125","loc":[-85.637693,41.942047]},"n1250":{"id":"n1250","loc":[-85.630523,41.958261]},"n1251":{"id":"n1251","loc":[-85.63072,41.958636]},"n1252":{"id":"n1252","loc":[-85.630721,41.958709]},"n1253":{"id":"n1253","loc":[-85.630503,41.958712]},"n1254":{"id":"n1254","loc":[-85.630498,41.958511]},"n1255":{"id":"n1255","loc":[-85.630635,41.95851]},"n1256":{"id":"n1256","loc":[-85.630638,41.958636]},"n1257":{"id":"n1257","loc":[-85.630437,41.958822]},"n1258":{"id":"n1258","loc":[-85.630437,41.958849]},"n1259":{"id":"n1259","loc":[-85.630393,41.958849]},"n126":{"id":"n126","loc":[-85.637692,41.941988]},"n1260":{"id":"n1260","loc":[-85.630393,41.958822]},"n1261":{"id":"n1261","loc":[-85.630605,41.959102]},"n1262":{"id":"n1262","loc":[-85.63049,41.959104]},"n1263":{"id":"n1263","loc":[-85.630487,41.958996]},"n1264":{"id":"n1264","loc":[-85.630462,41.958996]},"n1265":{"id":"n1265","loc":[-85.63046,41.958922]},"n1266":{"id":"n1266","loc":[-85.630562,41.958921]},"n1267":{"id":"n1267","loc":[-85.630564,41.958992]},"n1268":{"id":"n1268","loc":[-85.630602,41.958992]},"n1269":{"id":"n1269","loc":[-85.630126,41.957096]},"n127":{"id":"n127","loc":[-85.637604,41.941994]},"n1270":{"id":"n1270","loc":[-85.630129,41.957283]},"n1271":{"id":"n1271","loc":[-85.629993,41.957284]},"n1272":{"id":"n1272","loc":[-85.629992,41.957216]},"n1273":{"id":"n1273","loc":[-85.630015,41.957215]},"n1274":{"id":"n1274","loc":[-85.630013,41.957097]},"n1275":{"id":"n1275","loc":[-85.630211,41.956592]},"n1276":{"id":"n1276","loc":[-85.630211,41.956676]},"n1277":{"id":"n1277","loc":[-85.630162,41.956676]},"n1278":{"id":"n1278","loc":[-85.630162,41.95676]},"n1279":{"id":"n1279","loc":[-85.630037,41.956761]},"n128":{"id":"n128","loc":[-85.637604,41.942057]},"n1280":{"id":"n1280","loc":[-85.630037,41.956592]},"n1281":{"id":"n1281","loc":[-85.630309,41.95653]},"n1282":{"id":"n1282","loc":[-85.630326,41.957065]},"n1283":{"id":"n1283","loc":[-85.630118,41.957065]},"n1284":{"id":"n1284","loc":[-85.630119,41.957096]},"n1285":{"id":"n1285","loc":[-85.63067,41.957307]},"n1286":{"id":"n1286","loc":[-85.630536,41.957308]},"n1287":{"id":"n1287","loc":[-85.630533,41.957111]},"n1288":{"id":"n1288","loc":[-85.630667,41.95711]},"n1289":{"id":"n1289","loc":[-85.630676,41.956808]},"n129":{"id":"n129","loc":[-85.63748,41.942057]},"n1290":{"id":"n1290","loc":[-85.630551,41.956808]},"n1291":{"id":"n1291","loc":[-85.630552,41.956982]},"n1292":{"id":"n1292","loc":[-85.63059,41.956982]},"n1293":{"id":"n1293","loc":[-85.63059,41.957001]},"n1294":{"id":"n1294","loc":[-85.630692,41.957001]},"n1295":{"id":"n1295","loc":[-85.630692,41.956936]},"n1296":{"id":"n1296","loc":[-85.630676,41.956936]},"n1297":{"id":"n1297","loc":[-85.630496,41.956889]},"n1298":{"id":"n1298","loc":[-85.630501,41.956947]},"n1299":{"id":"n1299","loc":[-85.630377,41.956953]},"n13":{"id":"n13","loc":[-85.633643,41.941143]},"n130":{"id":"n130","loc":[-85.63748,41.941994]},"n1300":{"id":"n1300","loc":[-85.630359,41.956938]},"n1301":{"id":"n1301","loc":[-85.630359,41.956912]},"n1302":{"id":"n1302","loc":[-85.63038,41.956894]},"n1303":{"id":"n1303","loc":[-85.630679,41.956747]},"n1304":{"id":"n1304","loc":[-85.630572,41.956748]},"n1305":{"id":"n1305","loc":[-85.63057,41.956668]},"n1306":{"id":"n1306","loc":[-85.630501,41.956669]},"n1307":{"id":"n1307","loc":[-85.630499,41.95659]},"n1308":{"id":"n1308","loc":[-85.630565,41.956589]},"n1309":{"id":"n1309","loc":[-85.630564,41.956541]},"n131":{"id":"n131","loc":[-85.637431,41.941832]},"n1310":{"id":"n1310","loc":[-85.630686,41.956539]},"n1311":{"id":"n1311","loc":[-85.630688,41.956631]},"n1312":{"id":"n1312","loc":[-85.630676,41.956631]},"n1313":{"id":"n1313","loc":[-85.630686,41.956487]},"n1314":{"id":"n1314","loc":[-85.63059,41.956487]},"n1315":{"id":"n1315","loc":[-85.63059,41.956396]},"n1316":{"id":"n1316","loc":[-85.630686,41.956396]},"n1317":{"id":"n1317","loc":[-85.630643,41.9563]},"n1318":{"id":"n1318","loc":[-85.630548,41.956301]},"n1319":{"id":"n1319","loc":[-85.630545,41.956217]},"n132":{"id":"n132","loc":[-85.637432,41.94189]},"n1320":{"id":"n1320","loc":[-85.630529,41.956214]},"n1321":{"id":"n1321","loc":[-85.630521,41.956202]},"n1322":{"id":"n1322","loc":[-85.63052,41.95618]},"n1323":{"id":"n1323","loc":[-85.630527,41.956169]},"n1324":{"id":"n1324","loc":[-85.630544,41.956163]},"n1325":{"id":"n1325","loc":[-85.630543,41.956094]},"n1326":{"id":"n1326","loc":[-85.630641,41.956093]},"n1327":{"id":"n1327","loc":[-85.630642,41.956134]},"n1328":{"id":"n1328","loc":[-85.630656,41.956134]},"n1329":{"id":"n1329","loc":[-85.630657,41.956252]},"n133":{"id":"n133","loc":[-85.637412,41.94189]},"n1330":{"id":"n1330","loc":[-85.630643,41.956252]},"n1331":{"id":"n1331","loc":[-85.630409,41.956044]},"n1332":{"id":"n1332","loc":[-85.630409,41.956075]},"n1333":{"id":"n1333","loc":[-85.630195,41.956078]},"n1334":{"id":"n1334","loc":[-85.630195,41.9561]},"n1335":{"id":"n1335","loc":[-85.630088,41.956101]},"n1336":{"id":"n1336","loc":[-85.630087,41.956048]},"n1337":{"id":"n1337","loc":[-85.630345,41.956114]},"n1338":{"id":"n1338","loc":[-85.630328,41.956113]},"n1339":{"id":"n1339","loc":[-85.63034,41.956189]},"n134":{"id":"n134","loc":[-85.637413,41.941938]},"n1340":{"id":"n1340","loc":[-85.630355,41.956185]},"n1341":{"id":"n1341","loc":[-85.630311,41.956117]},"n1342":{"id":"n1342","loc":[-85.630297,41.956125]},"n1343":{"id":"n1343","loc":[-85.630287,41.956136]},"n1344":{"id":"n1344","loc":[-85.630283,41.956149]},"n1345":{"id":"n1345","loc":[-85.630285,41.956162]},"n1346":{"id":"n1346","loc":[-85.630293,41.956174]},"n1347":{"id":"n1347","loc":[-85.630306,41.956183]},"n1348":{"id":"n1348","loc":[-85.630322,41.956188]},"n1349":{"id":"n1349","loc":[-85.630368,41.956179]},"n135":{"id":"n135","loc":[-85.637342,41.941939]},"n1350":{"id":"n1350","loc":[-85.630378,41.95617]},"n1351":{"id":"n1351","loc":[-85.630384,41.956159]},"n1352":{"id":"n1352","loc":[-85.630385,41.956147]},"n1353":{"id":"n1353","loc":[-85.630381,41.956136]},"n1354":{"id":"n1354","loc":[-85.630372,41.956126]},"n1355":{"id":"n1355","loc":[-85.63036,41.956118]},"n1356":{"id":"n1356","loc":[-85.630776,41.956041]},"n1357":{"id":"n1357","loc":[-85.630195,41.956036]},"n1358":{"id":"n1358","loc":[-85.630137,41.956037]},"n1359":{"id":"n1359","loc":[-85.630136,41.956006]},"n136":{"id":"n136","loc":[-85.637342,41.941914]},"n1360":{"id":"n1360","loc":[-85.630194,41.956005]},"n1361":{"id":"n1361","loc":[-85.629864,41.956039]},"n1362":{"id":"n1362","loc":[-85.629864,41.955862]},"n1363":{"id":"n1363","loc":[-85.629541,41.958291]},"n1364":{"id":"n1364","loc":[-85.629419,41.958292]},"n1365":{"id":"n1365","loc":[-85.629417,41.958168]},"n1366":{"id":"n1366","loc":[-85.629445,41.958168]},"n1367":{"id":"n1367","loc":[-85.629444,41.958109]},"n1368":{"id":"n1368","loc":[-85.629537,41.958108]},"n1369":{"id":"n1369","loc":[-85.629351,41.958136]},"n137":{"id":"n137","loc":[-85.637212,41.941916]},"n1370":{"id":"n1370","loc":[-85.629352,41.958202]},"n1371":{"id":"n1371","loc":[-85.629365,41.958202]},"n1372":{"id":"n1372","loc":[-85.629365,41.958223]},"n1373":{"id":"n1373","loc":[-85.629291,41.958224]},"n1374":{"id":"n1374","loc":[-85.62929,41.958137]},"n1375":{"id":"n1375","loc":[-85.629443,41.958073]},"n1376":{"id":"n1376","loc":[-85.629252,41.958075]},"n1377":{"id":"n1377","loc":[-85.629253,41.95827]},"n1378":{"id":"n1378","loc":[-85.629566,41.957585]},"n1379":{"id":"n1379","loc":[-85.629566,41.957692]},"n138":{"id":"n138","loc":[-85.637211,41.941835]},"n1380":{"id":"n1380","loc":[-85.629281,41.957693]},"n1381":{"id":"n1381","loc":[-85.62928,41.957585]},"n1382":{"id":"n1382","loc":[-85.629004,41.957599]},"n1383":{"id":"n1383","loc":[-85.629004,41.957682]},"n1384":{"id":"n1384","loc":[-85.628902,41.957682]},"n1385":{"id":"n1385","loc":[-85.628902,41.957723]},"n1386":{"id":"n1386","loc":[-85.628731,41.957724]},"n1387":{"id":"n1387","loc":[-85.628731,41.9576]},"n1388":{"id":"n1388","loc":[-85.62836,41.957679]},"n1389":{"id":"n1389","loc":[-85.628359,41.957759]},"n139":{"id":"n139","loc":[-85.637293,41.941834]},"n1390":{"id":"n1390","loc":[-85.628062,41.957757]},"n1391":{"id":"n1391","loc":[-85.628063,41.957657]},"n1392":{"id":"n1392","loc":[-85.628198,41.957657]},"n1393":{"id":"n1393","loc":[-85.628198,41.957678]},"n1394":{"id":"n1394","loc":[-85.627775,41.958095]},"n1395":{"id":"n1395","loc":[-85.627608,41.958095]},"n1396":{"id":"n1396","loc":[-85.627606,41.957829]},"n1397":{"id":"n1397","loc":[-85.627774,41.957829]},"n1398":{"id":"n1398","loc":[-85.626816,41.957636]},"n1399":{"id":"n1399","loc":[-85.626787,41.957681]},"n14":{"id":"n14","loc":[-85.633643,41.940122]},"n140":{"id":"n140","loc":[-85.637293,41.941823]},"n1400":{"id":"n1400","loc":[-85.626673,41.95764]},"n1401":{"id":"n1401","loc":[-85.626703,41.957594]},"n1402":{"id":"n1402","loc":[-85.62694,41.95752]},"n1403":{"id":"n1403","loc":[-85.62688,41.957611]},"n1404":{"id":"n1404","loc":[-85.626798,41.957582]},"n1405":{"id":"n1405","loc":[-85.626793,41.95759]},"n1406":{"id":"n1406","loc":[-85.626657,41.95754]},"n1407":{"id":"n1407","loc":[-85.626666,41.957526]},"n1408":{"id":"n1408","loc":[-85.626584,41.957497]},"n1409":{"id":"n1409","loc":[-85.626638,41.957415]},"n141":{"id":"n141","loc":[-85.637363,41.941822]},"n1410":{"id":"n1410","loc":[-85.626731,41.957449]},"n1411":{"id":"n1411","loc":[-85.626725,41.957457]},"n1412":{"id":"n1412","loc":[-85.626843,41.9575]},"n1413":{"id":"n1413","loc":[-85.626851,41.957487]},"n1414":{"id":"n1414","loc":[-85.626579,41.957521]},"n1415":{"id":"n1415","loc":[-85.626537,41.957587]},"n1416":{"id":"n1416","loc":[-85.626427,41.957551]},"n1417":{"id":"n1417","loc":[-85.626468,41.957483]},"n1418":{"id":"n1418","loc":[-85.626592,41.957639]},"n1419":{"id":"n1419","loc":[-85.626807,41.957713]},"n142":{"id":"n142","loc":[-85.637364,41.941833]},"n1420":{"id":"n1420","loc":[-85.627129,41.957401]},"n1421":{"id":"n1421","loc":[-85.627209,41.95742]},"n1422":{"id":"n1422","loc":[-85.627302,41.957435]},"n1423":{"id":"n1423","loc":[-85.629566,41.957048]},"n1424":{"id":"n1424","loc":[-85.629568,41.957215]},"n1425":{"id":"n1425","loc":[-85.629383,41.957216]},"n1426":{"id":"n1426","loc":[-85.629384,41.95727]},"n1427":{"id":"n1427","loc":[-85.629231,41.957271]},"n1428":{"id":"n1428","loc":[-85.62923,41.957198]},"n1429":{"id":"n1429","loc":[-85.629322,41.957198]},"n143":{"id":"n143","loc":[-85.637559,41.942448]},"n1430":{"id":"n1430","loc":[-85.629321,41.957108]},"n1431":{"id":"n1431","loc":[-85.629441,41.957108]},"n1432":{"id":"n1432","loc":[-85.62944,41.957049]},"n1433":{"id":"n1433","loc":[-85.629337,41.957018]},"n1434":{"id":"n1434","loc":[-85.629366,41.957028]},"n1435":{"id":"n1435","loc":[-85.629375,41.957044]},"n1436":{"id":"n1436","loc":[-85.629354,41.957071]},"n1437":{"id":"n1437","loc":[-85.629317,41.957071]},"n1438":{"id":"n1438","loc":[-85.62929,41.957074]},"n1439":{"id":"n1439","loc":[-85.62927,41.957084]},"n144":{"id":"n144","loc":[-85.637036,41.942454]},"n1440":{"id":"n1440","loc":[-85.629232,41.957081]},"n1441":{"id":"n1441","loc":[-85.629222,41.957057]},"n1442":{"id":"n1442","loc":[-85.629259,41.957025]},"n1443":{"id":"n1443","loc":[-85.629293,41.957017]},"n1444":{"id":"n1444","loc":[-85.629251,41.957085]},"n1445":{"id":"n1445","loc":[-85.629235,41.957041]},"n1446":{"id":"n1446","loc":[-85.62937,41.95706]},"n1447":{"id":"n1447","loc":[-85.629531,41.956909]},"n1448":{"id":"n1448","loc":[-85.629408,41.956909]},"n1449":{"id":"n1449","loc":[-85.629402,41.956681]},"n145":{"id":"n145","loc":[-85.636692,41.942828]},"n1450":{"id":"n1450","loc":[-85.62953,41.956681]},"n1451":{"id":"n1451","loc":[-85.629402,41.956728]},"n1452":{"id":"n1452","loc":[-85.629408,41.956845]},"n1453":{"id":"n1453","loc":[-85.629385,41.956845]},"n1454":{"id":"n1454","loc":[-85.629384,41.956728]},"n1455":{"id":"n1455","loc":[-85.629063,41.956973]},"n1456":{"id":"n1456","loc":[-85.629064,41.957009]},"n1457":{"id":"n1457","loc":[-85.62902,41.957009]},"n1458":{"id":"n1458","loc":[-85.629019,41.956973]},"n1459":{"id":"n1459","loc":[-85.629136,41.956633]},"n146":{"id":"n146","loc":[-85.635929,41.942826]},"n1460":{"id":"n1460","loc":[-85.629084,41.956632]},"n1461":{"id":"n1461","loc":[-85.629084,41.956605]},"n1462":{"id":"n1462","loc":[-85.629136,41.956605]},"n1463":{"id":"n1463","loc":[-85.629153,41.956657]},"n1464":{"id":"n1464","loc":[-85.627914,41.956661]},"n1465":{"id":"n1465","loc":[-85.630096,41.956101]},"n1466":{"id":"n1466","loc":[-85.630097,41.95612]},"n1467":{"id":"n1467","loc":[-85.630011,41.956121]},"n1468":{"id":"n1468","loc":[-85.630015,41.956374]},"n1469":{"id":"n1469","loc":[-85.629148,41.95626]},"n147":{"id":"n147","loc":[-85.636433,41.942828]},"n1470":{"id":"n1470","loc":[-85.629527,41.956591]},"n1471":{"id":"n1471","loc":[-85.629405,41.956591]},"n1472":{"id":"n1472","loc":[-85.629405,41.956459]},"n1473":{"id":"n1473","loc":[-85.629369,41.956459]},"n1474":{"id":"n1474","loc":[-85.629369,41.956424]},"n1475":{"id":"n1475","loc":[-85.629413,41.956424]},"n1476":{"id":"n1476","loc":[-85.629414,41.956326]},"n1477":{"id":"n1477","loc":[-85.629522,41.956326]},"n1478":{"id":"n1478","loc":[-85.629522,41.956487]},"n1479":{"id":"n1479","loc":[-85.629527,41.956487]},"n148":{"id":"n148","loc":[-85.636435,41.942864],"tags":{"entrance":"yes"}},"n1480":{"id":"n1480","loc":[-85.629414,41.95634]},"n1481":{"id":"n1481","loc":[-85.629149,41.956338]},"n1482":{"id":"n1482","loc":[-85.62931,41.956531]},"n1483":{"id":"n1483","loc":[-85.629291,41.95655]},"n1484":{"id":"n1484","loc":[-85.629255,41.95655]},"n1485":{"id":"n1485","loc":[-85.629236,41.956533]},"n1486":{"id":"n1486","loc":[-85.629237,41.956461]},"n1487":{"id":"n1487","loc":[-85.629257,41.956445]},"n1488":{"id":"n1488","loc":[-85.629257,41.956428]},"n1489":{"id":"n1489","loc":[-85.629287,41.956428]},"n149":{"id":"n149","loc":[-85.637235,41.942622]},"n1490":{"id":"n1490","loc":[-85.629287,41.956445]},"n1491":{"id":"n1491","loc":[-85.62931,41.95646]},"n1492":{"id":"n1492","loc":[-85.629049,41.956425]},"n1493":{"id":"n1493","loc":[-85.628907,41.956427]},"n1494":{"id":"n1494","loc":[-85.628907,41.956455]},"n1495":{"id":"n1495","loc":[-85.628841,41.956455]},"n1496":{"id":"n1496","loc":[-85.62884,41.956424]},"n1497":{"id":"n1497","loc":[-85.628764,41.956425]},"n1498":{"id":"n1498","loc":[-85.628762,41.956323]},"n1499":{"id":"n1499","loc":[-85.628808,41.956323]},"n15":{"id":"n15","loc":[-85.633477,41.940187]},"n150":{"id":"n150","loc":[-85.637247,41.943116]},"n1500":{"id":"n1500","loc":[-85.628808,41.956314]},"n1501":{"id":"n1501","loc":[-85.628911,41.956313]},"n1502":{"id":"n1502","loc":[-85.628911,41.956322]},"n1503":{"id":"n1503","loc":[-85.62896,41.956322]},"n1504":{"id":"n1504","loc":[-85.62896,41.956348]},"n1505":{"id":"n1505","loc":[-85.629047,41.956347]},"n1506":{"id":"n1506","loc":[-85.628893,41.957263]},"n1507":{"id":"n1507","loc":[-85.628788,41.957264]},"n1508":{"id":"n1508","loc":[-85.628786,41.95711]},"n1509":{"id":"n1509","loc":[-85.628894,41.957109]},"n151":{"id":"n151","loc":[-85.637564,41.943116]},"n1510":{"id":"n1510","loc":[-85.628893,41.957075]},"n1511":{"id":"n1511","loc":[-85.628965,41.957075]},"n1512":{"id":"n1512","loc":[-85.628965,41.957111]},"n1513":{"id":"n1513","loc":[-85.629035,41.95711]},"n1514":{"id":"n1514","loc":[-85.629036,41.957209]},"n1515":{"id":"n1515","loc":[-85.628893,41.95721]},"n1516":{"id":"n1516","loc":[-85.631348,41.95773]},"n1517":{"id":"n1517","loc":[-85.631101,41.957732]},"n1518":{"id":"n1518","loc":[-85.631099,41.957558]},"n1519":{"id":"n1519","loc":[-85.63123,41.957557]},"n152":{"id":"n152","loc":[-85.637552,41.942619]},"n1520":{"id":"n1520","loc":[-85.631231,41.957618]},"n1521":{"id":"n1521","loc":[-85.63129,41.957618]},"n1522":{"id":"n1522","loc":[-85.63129,41.957651]},"n1523":{"id":"n1523","loc":[-85.631346,41.957651]},"n1524":{"id":"n1524","loc":[-85.631366,41.95802]},"n1525":{"id":"n1525","loc":[-85.631141,41.958021]},"n1526":{"id":"n1526","loc":[-85.63114,41.957943]},"n1527":{"id":"n1527","loc":[-85.631167,41.957943]},"n1528":{"id":"n1528","loc":[-85.631166,41.957808]},"n1529":{"id":"n1529","loc":[-85.631301,41.957807]},"n153":{"id":"n153","loc":[-85.63763,41.942528]},"n1530":{"id":"n1530","loc":[-85.631302,41.95789]},"n1531":{"id":"n1531","loc":[-85.631364,41.95789]},"n1532":{"id":"n1532","loc":[-85.631539,41.957754]},"n1533":{"id":"n1533","loc":[-85.631069,41.957756]},"n1534":{"id":"n1534","loc":[-85.631536,41.957518]},"n1535":{"id":"n1535","loc":[-85.631543,41.957995]},"n1536":{"id":"n1536","loc":[-85.631531,41.957748]},"n1537":{"id":"n1537","loc":[-85.631485,41.957748]},"n1538":{"id":"n1538","loc":[-85.631484,41.957698]},"n1539":{"id":"n1539","loc":[-85.631531,41.957698]},"n154":{"id":"n154","loc":[-85.637151,41.94253]},"n1540":{"id":"n1540","loc":[-85.631586,41.957742]},"n1541":{"id":"n1541","loc":[-85.63155,41.957742]},"n1542":{"id":"n1542","loc":[-85.631551,41.957702]},"n1543":{"id":"n1543","loc":[-85.631587,41.957702]},"n1544":{"id":"n1544","loc":[-85.631534,41.95807]},"n1545":{"id":"n1545","loc":[-85.631534,41.958097]},"n1546":{"id":"n1546","loc":[-85.631491,41.958097]},"n1547":{"id":"n1547","loc":[-85.631491,41.95807]},"n1548":{"id":"n1548","loc":[-85.631304,41.958861]},"n1549":{"id":"n1549","loc":[-85.631186,41.958862]},"n155":{"id":"n155","loc":[-85.63715,41.942424]},"n1550":{"id":"n1550","loc":[-85.631182,41.958653]},"n1551":{"id":"n1551","loc":[-85.6313,41.958651]},"n1552":{"id":"n1552","loc":[-85.631293,41.95854]},"n1553":{"id":"n1553","loc":[-85.631176,41.958539]},"n1554":{"id":"n1554","loc":[-85.631176,41.958377]},"n1555":{"id":"n1555","loc":[-85.631297,41.958377]},"n1556":{"id":"n1556","loc":[-85.631297,41.958422]},"n1557":{"id":"n1557","loc":[-85.631333,41.958422]},"n1558":{"id":"n1558","loc":[-85.631333,41.958479]},"n1559":{"id":"n1559","loc":[-85.631293,41.958479]},"n156":{"id":"n156","loc":[-85.637629,41.942422]},"n1560":{"id":"n1560","loc":[-85.631951,41.958908]},"n1561":{"id":"n1561","loc":[-85.631838,41.958909]},"n1562":{"id":"n1562","loc":[-85.631837,41.958847]},"n1563":{"id":"n1563","loc":[-85.631859,41.958847]},"n1564":{"id":"n1564","loc":[-85.631858,41.958746]},"n1565":{"id":"n1565","loc":[-85.631961,41.958745]},"n1566":{"id":"n1566","loc":[-85.631962,41.958812]},"n1567":{"id":"n1567","loc":[-85.631949,41.958813]},"n1568":{"id":"n1568","loc":[-85.631579,41.958913]},"n1569":{"id":"n1569","loc":[-85.631567,41.95864]},"n157":{"id":"n157","loc":[-85.638232,41.942477]},"n1570":{"id":"n1570","loc":[-85.631942,41.958639]},"n1571":{"id":"n1571","loc":[-85.631543,41.958594]},"n1572":{"id":"n1572","loc":[-85.631543,41.958065]},"n1573":{"id":"n1573","loc":[-85.631888,41.958546]},"n1574":{"id":"n1574","loc":[-85.631804,41.958546]},"n1575":{"id":"n1575","loc":[-85.631803,41.95841]},"n1576":{"id":"n1576","loc":[-85.631886,41.958409]},"n1577":{"id":"n1577","loc":[-85.631897,41.958125]},"n1578":{"id":"n1578","loc":[-85.631755,41.958126]},"n1579":{"id":"n1579","loc":[-85.631756,41.958174]},"n158":{"id":"n158","loc":[-85.637775,41.942483]},"n1580":{"id":"n1580","loc":[-85.63178,41.958174]},"n1581":{"id":"n1581","loc":[-85.631782,41.958272]},"n1582":{"id":"n1582","loc":[-85.631922,41.958271]},"n1583":{"id":"n1583","loc":[-85.631922,41.958244]},"n1584":{"id":"n1584","loc":[-85.631883,41.958245]},"n1585":{"id":"n1585","loc":[-85.631882,41.958175]},"n1586":{"id":"n1586","loc":[-85.631898,41.958175]},"n1587":{"id":"n1587","loc":[-85.631924,41.958032]},"n1588":{"id":"n1588","loc":[-85.631762,41.958032]},"n1589":{"id":"n1589","loc":[-85.63176,41.957827]},"n159":{"id":"n159","loc":[-85.638107,41.942512]},"n1590":{"id":"n1590","loc":[-85.631888,41.957826]},"n1591":{"id":"n1591","loc":[-85.631888,41.957892]},"n1592":{"id":"n1592","loc":[-85.631871,41.957892]},"n1593":{"id":"n1593","loc":[-85.631872,41.957949]},"n1594":{"id":"n1594","loc":[-85.631923,41.957949]},"n1595":{"id":"n1595","loc":[-85.631695,41.95795]},"n1596":{"id":"n1596","loc":[-85.631666,41.957975]},"n1597":{"id":"n1597","loc":[-85.63163,41.957975]},"n1598":{"id":"n1598","loc":[-85.6316,41.957951]},"n1599":{"id":"n1599","loc":[-85.6316,41.95785]},"n16":{"id":"n16","loc":[-85.63341,41.94032]},"n160":{"id":"n160","loc":[-85.637763,41.942514]},"n1600":{"id":"n1600","loc":[-85.63166,41.95785]},"n1601":{"id":"n1601","loc":[-85.631696,41.957873]},"n1602":{"id":"n1602","loc":[-85.631924,41.957762]},"n1603":{"id":"n1603","loc":[-85.631762,41.957762]},"n1604":{"id":"n1604","loc":[-85.631762,41.957708]},"n1605":{"id":"n1605","loc":[-85.631785,41.957708]},"n1606":{"id":"n1606","loc":[-85.631785,41.957606]},"n1607":{"id":"n1607","loc":[-85.631734,41.957606]},"n1608":{"id":"n1608","loc":[-85.631734,41.957538]},"n1609":{"id":"n1609","loc":[-85.631821,41.957538]},"n161":{"id":"n161","loc":[-85.637763,41.942445]},"n1610":{"id":"n1610","loc":[-85.631935,41.957545]},"n1611":{"id":"n1611","loc":[-85.631821,41.957544]},"n1612":{"id":"n1612","loc":[-85.631935,41.957645]},"n1613":{"id":"n1613","loc":[-85.631924,41.957645]},"n1614":{"id":"n1614","loc":[-85.627135,41.953828]},"n1615":{"id":"n1615","loc":[-85.633517,41.941353],"tags":{"man_made":"lighthouse"}},"n1616":{"id":"n1616","loc":[-85.633659,41.942041],"tags":{"amenity":"bbq"}},"n1617":{"id":"n1617","loc":[-85.63662,41.942911],"tags":{"amenity":"toilets"}},"n1618":{"id":"n1618","loc":[-85.637487,41.943876],"tags":{"amenity":"toilets"}},"n1619":{"id":"n1619","loc":[-85.634938,41.941917],"tags":{"amenity":"toilets"}},"n162":{"id":"n162","loc":[-85.638107,41.942443]},"n1620":{"id":"n1620","loc":[-85.632427,41.941678],"tags":{"amenity":"bbq"}},"n1621":{"id":"n1621","loc":[-85.638033,41.944568],"tags":{"amenity":"bbq"}},"n1622":{"id":"n1622","loc":[-85.638052,41.944522],"tags":{"amenity":"bbq"}},"n1623":{"id":"n1623","loc":[-85.635001,41.941965]},"n1624":{"id":"n1624","loc":[-85.634635,41.941884]},"n1625":{"id":"n1625","loc":[-85.634667,41.941894]},"n1626":{"id":"n1626","loc":[-85.634791,41.942011]},"n1627":{"id":"n1627","loc":[-85.634749,41.941938]},"n1628":{"id":"n1628","loc":[-85.627295,41.953946],"tags":{"barrier":"gate"}},"n1629":{"id":"n1629","loc":[-85.629076,41.954689]},"n163":{"id":"n163","loc":[-85.638813,41.942475]},"n1630":{"id":"n1630","loc":[-85.640667,41.942595]},"n1631":{"id":"n1631","loc":[-85.639455,41.94261]},"n1632":{"id":"n1632","loc":[-85.643407,41.942336]},"n1633":{"id":"n1633","loc":[-85.641845,41.941316]},"n1634":{"id":"n1634","loc":[-85.643322,41.942224]},"n1635":{"id":"n1635","loc":[-85.643301,41.942124]},"n1636":{"id":"n1636","loc":[-85.640639,41.941326]},"n1637":{"id":"n1637","loc":[-85.640614,41.940058]},"n1638":{"id":"n1638","loc":[-85.639428,41.941335]},"n1639":{"id":"n1639","loc":[-85.643078,41.941293]},"n164":{"id":"n164","loc":[-85.63883,41.942422]},"n1640":{"id":"n1640","loc":[-85.64371,41.942302]},"n1641":{"id":"n1641","loc":[-85.643056,41.94001]},"n1642":{"id":"n1642","loc":[-85.643097,41.942575],"tags":{"highway":"traffic_signals","traffic_signals":"signal"}},"n1643":{"id":"n1643","loc":[-85.641855,41.942586]},"n1644":{"id":"n1644","loc":[-85.643549,41.942209]},"n1645":{"id":"n1645","loc":[-85.639359,41.94007]},"n1646":{"id":"n1646","loc":[-85.642797,41.940522]},"n1647":{"id":"n1647","loc":[-85.642589,41.940523]},"n1648":{"id":"n1648","loc":[-85.642587,41.940287]},"n1649":{"id":"n1649","loc":[-85.642797,41.940286]},"n165":{"id":"n165","loc":[-85.63883,41.942508]},"n1650":{"id":"n1650","loc":[-85.642571,41.940523]},"n1651":{"id":"n1651","loc":[-85.642568,41.940286]},"n1652":{"id":"n1652","loc":[-85.642316,41.940289]},"n1653":{"id":"n1653","loc":[-85.642321,41.940436]},"n1654":{"id":"n1654","loc":[-85.642292,41.940458]},"n1655":{"id":"n1655","loc":[-85.642287,41.940483]},"n1656":{"id":"n1656","loc":[-85.642323,41.940509]},"n1657":{"id":"n1657","loc":[-85.642385,41.940511]},"n1658":{"id":"n1658","loc":[-85.642408,41.940526]},"n1659":{"id":"n1659","loc":[-85.641962,41.94109]},"n166":{"id":"n166","loc":[-85.638364,41.942508]},"n1660":{"id":"n1660","loc":[-85.642753,41.941084]},"n1661":{"id":"n1661","loc":[-85.642752,41.941004]},"n1662":{"id":"n1662","loc":[-85.642806,41.941003]},"n1663":{"id":"n1663","loc":[-85.642803,41.940731]},"n1664":{"id":"n1664","loc":[-85.642741,41.940732]},"n1665":{"id":"n1665","loc":[-85.64274,41.940645]},"n1666":{"id":"n1666","loc":[-85.641957,41.940651]},"n1667":{"id":"n1667","loc":[-85.642937,41.941241]},"n1668":{"id":"n1668","loc":[-85.641776,41.941253]},"n1669":{"id":"n1669","loc":[-85.641766,41.940598]},"n167":{"id":"n167","loc":[-85.638836,41.942167]},"n1670":{"id":"n1670","loc":[-85.64198,41.940598]},"n1671":{"id":"n1671","loc":[-85.641961,41.940137]},"n1672":{"id":"n1672","loc":[-85.642934,41.94012]},"n1673":{"id":"n1673","loc":[-85.643074,41.941173]},"n1674":{"id":"n1674","loc":[-85.642841,41.940997]},"n1675":{"id":"n1675","loc":[-85.642839,41.940721]},"n1676":{"id":"n1676","loc":[-85.643065,41.940552]},"n1677":{"id":"n1677","loc":[-85.642732,41.94124]},"n1678":{"id":"n1678","loc":[-85.641815,41.941246]},"n1679":{"id":"n1679","loc":[-85.641813,41.941132]},"n168":{"id":"n168","loc":[-85.638836,41.94229]},"n1680":{"id":"n1680","loc":[-85.641839,41.941111]},"n1681":{"id":"n1681","loc":[-85.641884,41.941098]},"n1682":{"id":"n1682","loc":[-85.642732,41.941092]},"n1683":{"id":"n1683","loc":[-85.642776,41.941302]},"n1684":{"id":"n1684","loc":[-85.632788,41.946236]},"n1685":{"id":"n1685","loc":[-85.622342,41.953127]},"n1686":{"id":"n1686","loc":[-85.641848,41.941167]},"n1687":{"id":"n1687","loc":[-85.643753,41.941503]},"n1688":{"id":"n1688","loc":[-85.643762,41.942119]},"n1689":{"id":"n1689","loc":[-85.64238,41.942262]},"n169":{"id":"n169","loc":[-85.638594,41.94229]},"n1690":{"id":"n1690","loc":[-85.642374,41.941944]},"n1691":{"id":"n1691","loc":[-85.642518,41.941943]},"n1692":{"id":"n1692","loc":[-85.642519,41.94198]},"n1693":{"id":"n1693","loc":[-85.642831,41.941977]},"n1694":{"id":"n1694","loc":[-85.642837,41.942312]},"n1695":{"id":"n1695","loc":[-85.642495,41.942315]},"n1696":{"id":"n1696","loc":[-85.642494,41.942261]},"n1697":{"id":"n1697","loc":[-85.641087,41.942433]},"n1698":{"id":"n1698","loc":[-85.641081,41.942006]},"n1699":{"id":"n1699","loc":[-85.641244,41.942005]},"n17":{"id":"n17","loc":[-85.633478,41.94081]},"n170":{"id":"n170","loc":[-85.638594,41.942422]},"n1700":{"id":"n1700","loc":[-85.64125,41.942431]},"n1701":{"id":"n1701","loc":[-85.641331,41.942968]},"n1702":{"id":"n1702","loc":[-85.641328,41.942713]},"n1703":{"id":"n1703","loc":[-85.641521,41.942712]},"n1704":{"id":"n1704","loc":[-85.641523,41.942924]},"n1705":{"id":"n1705","loc":[-85.641504,41.942924]},"n1706":{"id":"n1706","loc":[-85.641505,41.942967]},"n1707":{"id":"n1707","loc":[-85.638612,41.942408]},"n1708":{"id":"n1708","loc":[-85.638612,41.942327]},"n1709":{"id":"n1709","loc":[-85.638775,41.942327]},"n171":{"id":"n171","loc":[-85.638364,41.942356]},"n1710":{"id":"n1710","loc":[-85.638775,41.942299]},"n1711":{"id":"n1711","loc":[-85.638835,41.942298]},"n1712":{"id":"n1712","loc":[-85.638835,41.942407]},"n1713":{"id":"n1713","loc":[-85.639116,41.942444]},"n1714":{"id":"n1714","loc":[-85.639114,41.942362]},"n1715":{"id":"n1715","loc":[-85.639294,41.94236]},"n1716":{"id":"n1716","loc":[-85.639296,41.942442]},"n1717":{"id":"n1717","loc":[-85.639808,41.942385]},"n1718":{"id":"n1718","loc":[-85.639805,41.942285]},"n1719":{"id":"n1719","loc":[-85.639988,41.942283]},"n172":{"id":"n172","loc":[-85.638364,41.942167]},"n1720":{"id":"n1720","loc":[-85.63999,41.942383]},"n1721":{"id":"n1721","loc":[-85.639633,41.943023]},"n1722":{"id":"n1722","loc":[-85.639867,41.943019]},"n1723":{"id":"n1723","loc":[-85.639866,41.942964]},"n1724":{"id":"n1724","loc":[-85.639888,41.942963]},"n1725":{"id":"n1725","loc":[-85.639883,41.942779]},"n1726":{"id":"n1726","loc":[-85.639851,41.94278]},"n1727":{"id":"n1727","loc":[-85.63985,41.94274]},"n1728":{"id":"n1728","loc":[-85.639789,41.942741]},"n1729":{"id":"n1729","loc":[-85.639789,41.942753]},"n173":{"id":"n173","loc":[-85.639038,41.942463]},"n1730":{"id":"n1730","loc":[-85.639698,41.942754]},"n1731":{"id":"n1731","loc":[-85.639699,41.942788]},"n1732":{"id":"n1732","loc":[-85.639675,41.942789]},"n1733":{"id":"n1733","loc":[-85.639676,41.94283]},"n1734":{"id":"n1734","loc":[-85.639701,41.942829]},"n1735":{"id":"n1735","loc":[-85.639702,41.942869]},"n1736":{"id":"n1736","loc":[-85.639629,41.94287]},"n1737":{"id":"n1737","loc":[-85.643568,41.942946]},"n1738":{"id":"n1738","loc":[-85.643568,41.942777]},"n1739":{"id":"n1739","loc":[-85.643401,41.942777]},"n174":{"id":"n174","loc":[-85.638897,41.942464]},"n1740":{"id":"n1740","loc":[-85.643401,41.942863]},"n1741":{"id":"n1741","loc":[-85.643448,41.942863]},"n1742":{"id":"n1742","loc":[-85.643448,41.942946]},"n1743":{"id":"n1743","loc":[-85.642836,41.942981]},"n1744":{"id":"n1744","loc":[-85.642917,41.942979]},"n1745":{"id":"n1745","loc":[-85.642914,41.942904]},"n1746":{"id":"n1746","loc":[-85.642938,41.942903]},"n1747":{"id":"n1747","loc":[-85.642935,41.942813]},"n1748":{"id":"n1748","loc":[-85.642775,41.942816]},"n1749":{"id":"n1749","loc":[-85.642778,41.942906]},"n175":{"id":"n175","loc":[-85.638897,41.942423]},"n1750":{"id":"n1750","loc":[-85.642833,41.942905]},"n1751":{"id":"n1751","loc":[-85.642302,41.942886]},"n1752":{"id":"n1752","loc":[-85.642299,41.942721]},"n1753":{"id":"n1753","loc":[-85.642422,41.94272]},"n1754":{"id":"n1754","loc":[-85.642425,41.942868]},"n1755":{"id":"n1755","loc":[-85.642385,41.942869]},"n1756":{"id":"n1756","loc":[-85.642385,41.942885]},"n1757":{"id":"n1757","loc":[-85.641533,41.942939]},"n1758":{"id":"n1758","loc":[-85.64161,41.942877]},"n1759":{"id":"n1759","loc":[-85.641676,41.942922]},"n176":{"id":"n176","loc":[-85.638853,41.942423]},"n1760":{"id":"n1760","loc":[-85.6416,41.942985]},"n1761":{"id":"n1761","loc":[-85.64206,41.942802]},"n1762":{"id":"n1762","loc":[-85.642059,41.942741]},"n1763":{"id":"n1763","loc":[-85.642196,41.942741]},"n1764":{"id":"n1764","loc":[-85.642196,41.942818]},"n1765":{"id":"n1765","loc":[-85.642128,41.942819]},"n1766":{"id":"n1766","loc":[-85.642128,41.942801]},"n1767":{"id":"n1767","loc":[-85.640943,41.942934]},"n1768":{"id":"n1768","loc":[-85.641035,41.942933]},"n1769":{"id":"n1769","loc":[-85.641032,41.942797]},"n177":{"id":"n177","loc":[-85.638852,41.94237]},"n1770":{"id":"n1770","loc":[-85.640997,41.942798]},"n1771":{"id":"n1771","loc":[-85.640996,41.942764]},"n1772":{"id":"n1772","loc":[-85.640861,41.942766]},"n1773":{"id":"n1773","loc":[-85.640862,41.942848]},"n1774":{"id":"n1774","loc":[-85.640941,41.942847]},"n1775":{"id":"n1775","loc":[-85.643766,41.942226]},"n1776":{"id":"n1776","loc":[-85.643768,41.942407]},"n1777":{"id":"n1777","loc":[-85.643218,41.94177]},"n1778":{"id":"n1778","loc":[-85.64321,41.941327]},"n1779":{"id":"n1779","loc":[-85.643649,41.941323]},"n178":{"id":"n178","loc":[-85.638892,41.94237]},"n1780":{"id":"n1780","loc":[-85.643656,41.941716]},"n1781":{"id":"n1781","loc":[-85.64358,41.941717]},"n1782":{"id":"n1782","loc":[-85.64358,41.941767]},"n1783":{"id":"n1783","loc":[-85.64382,41.941495]},"n1784":{"id":"n1784","loc":[-85.643817,41.941317]},"n1785":{"id":"n1785","loc":[-85.643235,41.941833]},"n1786":{"id":"n1786","loc":[-85.64335,41.941842]},"n1787":{"id":"n1787","loc":[-85.643504,41.941903]},"n1788":{"id":"n1788","loc":[-85.643554,41.941946]},"n1789":{"id":"n1789","loc":[-85.643618,41.942015]},"n179":{"id":"n179","loc":[-85.638891,41.942334]},"n1790":{"id":"n1790","loc":[-85.64346,41.941971]},"n1791":{"id":"n1791","loc":[-85.643528,41.942468]},"n1792":{"id":"n1792","loc":[-85.643621,41.942363]},"n1793":{"id":"n1793","loc":[-85.643496,41.942297]},"n1794":{"id":"n1794","loc":[-85.643446,41.942246]},"n1795":{"id":"n1795","loc":[-85.643398,41.942177]},"n1796":{"id":"n1796","loc":[-85.643398,41.942031]},"n1797":{"id":"n1797","loc":[-85.621531,41.952693]},"n1798":{"id":"n1798","loc":[-85.643221,41.942028]},"n1799":{"id":"n1799","loc":[-85.643225,41.942276]},"n18":{"id":"n18","loc":[-85.63345,41.94071]},"n180":{"id":"n180","loc":[-85.639037,41.942334]},"n1800":{"id":"n1800","loc":[-85.643265,41.942347]},"n1801":{"id":"n1801","loc":[-85.643323,41.942413]},"n1802":{"id":"n1802","loc":[-85.643411,41.94247]},"n1803":{"id":"n1803","loc":[-85.643459,41.942435]},"n1804":{"id":"n1804","loc":[-85.643767,41.942307]},"n1805":{"id":"n1805","loc":[-85.643661,41.942293]},"n1806":{"id":"n1806","loc":[-85.643578,41.942247]},"n1807":{"id":"n1807","loc":[-85.643522,41.942125]},"n1808":{"id":"n1808","loc":[-85.643515,41.942061]},"n1809":{"id":"n1809","loc":[-85.643346,41.941924]},"n181":{"id":"n181","loc":[-85.638074,41.941839]},"n1810":{"id":"n1810","loc":[-85.643086,41.94192]},"n1811":{"id":"n1811","loc":[-85.643529,41.94217]},"n1812":{"id":"n1812","loc":[-85.643489,41.942003]},"n1813":{"id":"n1813","loc":[-85.643295,41.941919]},"n1814":{"id":"n1814","loc":[-85.643305,41.942163]},"n1815":{"id":"n1815","loc":[-85.643354,41.942285]},"n1816":{"id":"n1816","loc":[-85.643472,41.942389]},"n1817":{"id":"n1817","loc":[-85.643608,41.942271]},"n1818":{"id":"n1818","loc":[-85.643876,41.941402]},"n1819":{"id":"n1819","loc":[-85.643818,41.941369]},"n182":{"id":"n182","loc":[-85.638076,41.941942]},"n1820":{"id":"n1820","loc":[-85.643682,41.941304]},"n1821":{"id":"n1821","loc":[-85.64359,41.941286]},"n1822":{"id":"n1822","loc":[-85.643317,41.941727]},"n1823":{"id":"n1823","loc":[-85.643301,41.941286]},"n1824":{"id":"n1824","loc":[-85.643553,41.941698]},"n1825":{"id":"n1825","loc":[-85.643543,41.941286]},"n1826":{"id":"n1826","loc":[-85.636967,41.940118]},"n1827":{"id":"n1827","loc":[-85.63378,41.940114]},"n1828":{"id":"n1828","loc":[-85.637254,41.940075]},"n1829":{"id":"n1829","loc":[-85.637002,41.941355]},"n183":{"id":"n183","loc":[-85.637955,41.941944]},"n1830":{"id":"n1830","loc":[-85.643532,41.94204]},"n1831":{"id":"n1831","loc":[-85.638235,41.942615]},"n1832":{"id":"n1832","loc":[-85.637039,41.942624]},"n1833":{"id":"n1833","loc":[-85.636369,41.94266]},"n1834":{"id":"n1834","loc":[-85.63582,41.942771],"tags":{"highway":"traffic_signals","traffic_signals":"emergency"}},"n1835":{"id":"n1835","loc":[-85.634873,41.943044]},"n1836":{"id":"n1836","loc":[-85.643482,41.941976]},"n1837":{"id":"n1837","loc":[-85.64345,41.941945]},"n1838":{"id":"n1838","loc":[-85.641885,41.943851]},"n1839":{"id":"n1839","loc":[-85.641915,41.945121]},"n184":{"id":"n184","loc":[-85.637953,41.94184]},"n1840":{"id":"n1840","loc":[-85.639454,41.943871]},"n1841":{"id":"n1841","loc":[-85.639491,41.945191]},"n1842":{"id":"n1842","loc":[-85.635768,41.940113]},"n1843":{"id":"n1843","loc":[-85.638206,41.941345]},"n1844":{"id":"n1844","loc":[-85.640721,41.94513]},"n1845":{"id":"n1845","loc":[-85.643137,41.945103]},"n1846":{"id":"n1846","loc":[-85.638199,41.940079]},"n1847":{"id":"n1847","loc":[-85.640688,41.943861]},"n1848":{"id":"n1848","loc":[-85.643397,41.941924]},"n1849":{"id":"n1849","loc":[-85.643117,41.943841]},"n185":{"id":"n185","loc":[-85.637953,41.941866]},"n1850":{"id":"n1850","loc":[-85.636731,41.94263]},"n1851":{"id":"n1851","loc":[-85.63518,41.942955],"tags":{"highway":"crossing"}},"n1852":{"id":"n1852","loc":[-85.636152,41.942695]},"n1853":{"id":"n1853","loc":[-85.644202,41.941499]},"n1854":{"id":"n1854","loc":[-85.644211,41.942116]},"n1855":{"id":"n1855","loc":[-85.644233,41.942404]},"n1856":{"id":"n1856","loc":[-85.644231,41.942223]},"n1857":{"id":"n1857","loc":[-85.644133,41.941315]},"n1858":{"id":"n1858","loc":[-85.644136,41.941493]},"n1859":{"id":"n1859","loc":[-85.644345,41.942307]},"n186":{"id":"n186","loc":[-85.637873,41.941867]},"n1860":{"id":"n1860","loc":[-85.644232,41.942304]},"n1861":{"id":"n1861","loc":[-85.644134,41.941403]},"n1862":{"id":"n1862","loc":[-85.63607,41.943005],"tags":{"addr:city":"Three Rivers","addr:housenumber":"333","addr:postcode":"49093","addr:state":"MI","addr:street":"Michigan Avenue","amenity":"fire_station","name":"Three Rivers Fire Department"}},"n1863":{"id":"n1863","loc":[-85.637,41.941236]},"n1864":{"id":"n1864","loc":[-85.634476,41.941475]},"n1865":{"id":"n1865","loc":[-85.635036,41.941858]},"n1866":{"id":"n1866","loc":[-85.635362,41.941962]},"n1867":{"id":"n1867","loc":[-85.635796,41.941962]},"n1868":{"id":"n1868","loc":[-85.63295,41.943006]},"n1869":{"id":"n1869","loc":[-85.634692,41.943098]},"n187":{"id":"n187","loc":[-85.637877,41.941975]},"n1870":{"id":"n1870","loc":[-85.633128,41.940484]},"n1871":{"id":"n1871","loc":[-85.633117,41.942798]},"n1872":{"id":"n1872","loc":[-85.633303,41.942412]},"n1873":{"id":"n1873","loc":[-85.633482,41.941912]},"n1874":{"id":"n1874","loc":[-85.633455,41.941359]},"n1875":{"id":"n1875","loc":[-85.633162,41.942679]},"n1876":{"id":"n1876","loc":[-85.634274,41.943479]},"n1877":{"id":"n1877","loc":[-85.634678,41.942909]},"n1878":{"id":"n1878","loc":[-85.6339,41.941453]},"n1879":{"id":"n1879","loc":[-85.634571,41.942774]},"n188":{"id":"n188","loc":[-85.636855,41.942488]},"n1880":{"id":"n1880","loc":[-85.63419,41.941732]},"n1881":{"id":"n1881","loc":[-85.634067,41.941565]},"n1882":{"id":"n1882","loc":[-85.63436,41.942358]},"n1883":{"id":"n1883","loc":[-85.634327,41.942247]},"n1884":{"id":"n1884","loc":[-85.633391,41.941231]},"n1885":{"id":"n1885","loc":[-85.634303,41.941972]},"n1886":{"id":"n1886","loc":[-85.633541,41.940147]},"n1887":{"id":"n1887","loc":[-85.633433,41.940252]},"n1888":{"id":"n1888","loc":[-85.633402,41.940411]},"n1889":{"id":"n1889","loc":[-85.633551,41.941023]},"n189":{"id":"n189","loc":[-85.636702,41.942488]},"n1890":{"id":"n1890","loc":[-85.633719,41.941186]},"n1891":{"id":"n1891","loc":[-85.633067,41.941845]},"n1892":{"id":"n1892","loc":[-85.634902,41.942766]},"n1893":{"id":"n1893","loc":[-85.634603,41.942202]},"n1894":{"id":"n1894","loc":[-85.634858,41.942152]},"n1895":{"id":"n1895","loc":[-85.634842,41.942269]},"n1896":{"id":"n1896","loc":[-85.634907,41.942313]},"n1897":{"id":"n1897","loc":[-85.635049,41.942331]},"n1898":{"id":"n1898","loc":[-85.635101,41.942281]},"n1899":{"id":"n1899","loc":[-85.635129,41.942144]},"n19":{"id":"n19","loc":[-85.633009,41.942229]},"n190":{"id":"n190","loc":[-85.636702,41.942434]},"n1900":{"id":"n1900","loc":[-85.635531,41.942143]},"n1901":{"id":"n1901","loc":[-85.635534,41.942577]},"n1902":{"id":"n1902","loc":[-85.635158,41.942656]},"n1903":{"id":"n1903","loc":[-85.635121,41.942703]},"n1904":{"id":"n1904","loc":[-85.635087,41.941508]},"n1905":{"id":"n1905","loc":[-85.63536,41.941106]},"n1906":{"id":"n1906","loc":[-85.635442,41.941094]},"n1907":{"id":"n1907","loc":[-85.635508,41.941104]},"n1908":{"id":"n1908","loc":[-85.635569,41.941125]},"n1909":{"id":"n1909","loc":[-85.635583,41.941106]},"n191":{"id":"n191","loc":[-85.636761,41.942434]},"n1910":{"id":"n1910","loc":[-85.635555,41.940976]},"n1911":{"id":"n1911","loc":[-85.635501,41.940915]},"n1912":{"id":"n1912","loc":[-85.635392,41.940922]},"n1913":{"id":"n1913","loc":[-85.635276,41.940974]},"n1914":{"id":"n1914","loc":[-85.63517,41.941204]},"n1915":{"id":"n1915","loc":[-85.634888,41.941517]},"n1916":{"id":"n1916","loc":[-85.634897,41.941576]},"n1917":{"id":"n1917","loc":[-85.634961,41.94164]},"n1918":{"id":"n1918","loc":[-85.635028,41.941659]},"n1919":{"id":"n1919","loc":[-85.635118,41.941621]},"n192":{"id":"n192","loc":[-85.636761,41.942369]},"n1920":{"id":"n1920","loc":[-85.635085,41.941558]},"n1921":{"id":"n1921","loc":[-85.63504,41.94136]},"n1922":{"id":"n1922","loc":[-85.635221,41.941077]},"n1923":{"id":"n1923","loc":[-85.634387,41.941559]},"n1924":{"id":"n1924","loc":[-85.634351,41.941587]},"n1925":{"id":"n1925","loc":[-85.634416,41.941756]},"n1926":{"id":"n1926","loc":[-85.634461,41.941797]},"n1927":{"id":"n1927","loc":[-85.634501,41.941819]},"n1928":{"id":"n1928","loc":[-85.634597,41.941816]},"n1929":{"id":"n1929","loc":[-85.634732,41.941724]},"n193":{"id":"n193","loc":[-85.636855,41.942369]},"n1930":{"id":"n1930","loc":[-85.634672,41.941775]},"n1931":{"id":"n1931","loc":[-85.633403,41.939101]},"n1932":{"id":"n1932","loc":[-85.633297,41.939397]},"n1933":{"id":"n1933","loc":[-85.633205,41.939674]},"n1934":{"id":"n1934","loc":[-85.63322,41.939777]},"n1935":{"id":"n1935","loc":[-85.633345,41.939936]},"n1936":{"id":"n1936","loc":[-85.633376,41.940002]},"n1937":{"id":"n1937","loc":[-85.633266,41.940228]},"n1938":{"id":"n1938","loc":[-85.633236,41.940352]},"n1939":{"id":"n1939","loc":[-85.633282,41.94063]},"n194":{"id":"n194","loc":[-85.636645,41.94249]},"n1940":{"id":"n1940","loc":[-85.633364,41.940874]},"n1941":{"id":"n1941","loc":[-85.633439,41.941052]},"n1942":{"id":"n1942","loc":[-85.633582,41.941172]},"n1943":{"id":"n1943","loc":[-85.633748,41.941273]},"n1944":{"id":"n1944","loc":[-85.634317,41.941527]},"n1945":{"id":"n1945","loc":[-85.634389,41.94174]},"n1946":{"id":"n1946","loc":[-85.634441,41.941801]},"n1947":{"id":"n1947","loc":[-85.634514,41.941837]},"n1948":{"id":"n1948","loc":[-85.634485,41.942005]},"n1949":{"id":"n1949","loc":[-85.63457,41.942202]},"n195":{"id":"n195","loc":[-85.636565,41.94249]},"n1950":{"id":"n1950","loc":[-85.634869,41.942769]},"n1951":{"id":"n1951","loc":[-85.634943,41.942792]},"n1952":{"id":"n1952","loc":[-85.635139,41.942882]},"n1953":{"id":"n1953","loc":[-85.634962,41.943161]},"n1954":{"id":"n1954","loc":[-85.635002,41.943131]},"n1955":{"id":"n1955","loc":[-85.635005,41.943091]},"n1956":{"id":"n1956","loc":[-85.635216,41.943033]},"n1957":{"id":"n1957","loc":[-85.634817,41.94267]},"n1958":{"id":"n1958","loc":[-85.634614,41.942599]},"n1959":{"id":"n1959","loc":[-85.634494,41.942381]},"n196":{"id":"n196","loc":[-85.636565,41.942474]},"n1960":{"id":"n1960","loc":[-85.634486,41.9423]},"n1961":{"id":"n1961","loc":[-85.634671,41.941795]},"n1962":{"id":"n1962","loc":[-85.634595,41.941831]},"n1963":{"id":"n1963","loc":[-85.634332,41.941866]},"n1964":{"id":"n1964","loc":[-85.634207,41.941885]},"n1965":{"id":"n1965","loc":[-85.634133,41.941892]},"n1966":{"id":"n1966","loc":[-85.634131,41.942203]},"n1967":{"id":"n1967","loc":[-85.634047,41.942327]},"n1968":{"id":"n1968","loc":[-85.634219,41.942793]},"n1969":{"id":"n1969","loc":[-85.634061,41.942392]},"n197":{"id":"n197","loc":[-85.636514,41.942474]},"n1970":{"id":"n1970","loc":[-85.633989,41.942407]},"n1971":{"id":"n1971","loc":[-85.633971,41.942356]},"n1972":{"id":"n1972","loc":[-85.63361,41.942423]},"n1973":{"id":"n1973","loc":[-85.633714,41.942682]},"n1974":{"id":"n1974","loc":[-85.633698,41.942863]},"n1975":{"id":"n1975","loc":[-85.633882,41.942865]},"n1976":{"id":"n1976","loc":[-85.633941,41.943007]},"n1977":{"id":"n1977","loc":[-85.633887,41.943035]},"n1978":{"id":"n1978","loc":[-85.633768,41.942815]},"n1979":{"id":"n1979","loc":[-85.633682,41.942351]},"n198":{"id":"n198","loc":[-85.636514,41.942326]},"n1980":{"id":"n1980","loc":[-85.634037,41.942273]},"n1981":{"id":"n1981","loc":[-85.634029,41.942252]},"n1982":{"id":"n1982","loc":[-85.633673,41.942331]},"n1983":{"id":"n1983","loc":[-85.634219,41.942571]},"n1984":{"id":"n1984","loc":[-85.634252,41.942565]},"n1985":{"id":"n1985","loc":[-85.634144,41.942299]},"n1986":{"id":"n1986","loc":[-85.634115,41.942306]},"n1987":{"id":"n1987","loc":[-85.634059,41.943094]},"n1988":{"id":"n1988","loc":[-85.633944,41.942903]},"n1989":{"id":"n1989","loc":[-85.634311,41.942821]},"n199":{"id":"n199","loc":[-85.636561,41.942326]},"n1990":{"id":"n1990","loc":[-85.634351,41.94277]},"n1991":{"id":"n1991","loc":[-85.634153,41.942254]},"n1992":{"id":"n1992","loc":[-85.634092,41.94222]},"n1993":{"id":"n1993","loc":[-85.633571,41.942336]},"n1994":{"id":"n1994","loc":[-85.633513,41.942387]},"n1995":{"id":"n1995","loc":[-85.633509,41.942455]},"n1996":{"id":"n1996","loc":[-85.63363,41.942665]},"n1997":{"id":"n1997","loc":[-85.63414,41.94286]},"n1998":{"id":"n1998","loc":[-85.63397,41.942449]},"n1999":{"id":"n1999","loc":[-85.633551,41.942529]},"n2":{"id":"n2","loc":[-85.627421,41.953877]},"n20":{"id":"n20","loc":[-85.633013,41.941438]},"n200":{"id":"n200","loc":[-85.636561,41.942311]},"n2000":{"id":"n2000","loc":[-85.633741,41.942493]},"n2001":{"id":"n2001","loc":[-85.633894,41.942869]},"n2002":{"id":"n2002","loc":[-85.634132,41.941954]},"n2003":{"id":"n2003","loc":[-85.634032,41.942038]},"n2004":{"id":"n2004","loc":[-85.633765,41.942238]},"n2005":{"id":"n2005","loc":[-85.63376,41.942268]},"n2006":{"id":"n2006","loc":[-85.633768,41.942293]},"n2007":{"id":"n2007","loc":[-85.633808,41.942386]},"n2008":{"id":"n2008","loc":[-85.634946,41.941663]},"n2009":{"id":"n2009","loc":[-85.63511,41.941697]},"n201":{"id":"n201","loc":[-85.636621,41.942311]},"n2010":{"id":"n2010","loc":[-85.635337,41.94168]},"n2011":{"id":"n2011","loc":[-85.634997,41.942251]},"n2012":{"id":"n2012","loc":[-85.635013,41.942173]},"n2013":{"id":"n2013","loc":[-85.634876,41.942157]},"n2014":{"id":"n2014","loc":[-85.634859,41.942235]},"n2015":{"id":"n2015","loc":[-85.634992,41.941951]},"n2016":{"id":"n2016","loc":[-85.634952,41.941877]},"n2017":{"id":"n2017","loc":[-85.634844,41.94191]},"n2018":{"id":"n2018","loc":[-85.634884,41.941983]},"n2019":{"id":"n2019","loc":[-85.635189,41.941691]},"n202":{"id":"n202","loc":[-85.636621,41.942351]},"n2020":{"id":"n2020","loc":[-85.635089,41.941896]},"n2021":{"id":"n2021","loc":[-85.635077,41.941964]},"n2022":{"id":"n2022","loc":[-85.635058,41.942147]},"n2023":{"id":"n2023","loc":[-85.635099,41.942161]},"n2024":{"id":"n2024","loc":[-85.635099,41.942213]},"n2025":{"id":"n2025","loc":[-85.635079,41.942285]},"n2026":{"id":"n2026","loc":[-85.635047,41.942316]},"n2027":{"id":"n2027","loc":[-85.634925,41.9423]},"n2028":{"id":"n2028","loc":[-85.634911,41.942276]},"n2029":{"id":"n2029","loc":[-85.634917,41.942242]},"n203":{"id":"n203","loc":[-85.63666,41.942351]},"n2030":{"id":"n2030","loc":[-85.634698,41.941898]},"n2031":{"id":"n2031","loc":[-85.634964,41.941878]},"n2032":{"id":"n2032","loc":[-85.635025,41.941929]},"n2033":{"id":"n2033","loc":[-85.634862,41.941887]},"n2034":{"id":"n2034","loc":[-85.634811,41.94181]},"n2035":{"id":"n2035","loc":[-85.634731,41.941745]},"n2036":{"id":"n2036","loc":[-85.634933,41.94176]},"n2037":{"id":"n2037","loc":[-85.634942,41.942145]},"n2038":{"id":"n2038","loc":[-85.634944,41.942065]},"n2039":{"id":"n2039","loc":[-85.634914,41.941996]},"n204":{"id":"n204","loc":[-85.63666,41.942453]},"n2040":{"id":"n2040","loc":[-85.634981,41.941979]},"n2041":{"id":"n2041","loc":[-85.633419,41.942172]},"n2042":{"id":"n2042","loc":[-85.633509,41.941631]},"n2043":{"id":"n2043","loc":[-85.633686,41.942937]},"n2044":{"id":"n2044","loc":[-85.633371,41.942722]},"n2045":{"id":"n2045","loc":[-85.633291,41.942538]},"n2046":{"id":"n2046","loc":[-85.633902,41.940941]},"n2047":{"id":"n2047","loc":[-85.635254,41.940939]},"n2048":{"id":"n2048","loc":[-85.635686,41.940829]},"n2049":{"id":"n2049","loc":[-85.635712,41.942681]},"n205":{"id":"n205","loc":[-85.636645,41.942453]},"n2050":{"id":"n2050","loc":[-85.633721,41.942118]},"n2051":{"id":"n2051","loc":[-85.633698,41.942057]},"n2052":{"id":"n2052","loc":[-85.633591,41.942079]},"n2053":{"id":"n2053","loc":[-85.633614,41.94214]},"n2054":{"id":"n2054","loc":[-85.633968,41.941099]},"n2055":{"id":"n2055","loc":[-85.633907,41.941138]},"n2056":{"id":"n2056","loc":[-85.633968,41.941197]},"n2057":{"id":"n2057","loc":[-85.63404,41.941162]},"n2058":{"id":"n2058","loc":[-85.634839,41.941665]},"n2059":{"id":"n2059","loc":[-85.635314,41.943035]},"n206":{"id":"n206","loc":[-85.636394,41.942471]},"n2060":{"id":"n2060","loc":[-85.634919,41.943142]},"n2061":{"id":"n2061","loc":[-85.636433,41.942959],"tags":{"addr:city":"Three Rivers","addr:housenumber":"333","addr:postcode":"49093","addr:state":"MI","addr:street":"Michigan Avenue","amenity":"townhall","name":"Three Rivers City Hall"}},"n2062":{"id":"n2062","loc":[-85.637039,41.942789]},"n2063":{"id":"n2063","loc":[-85.636333,41.94279]},"n2064":{"id":"n2064","loc":[-85.634484,41.940726]},"n2065":{"id":"n2065","loc":[-85.634483,41.940603]},"n2066":{"id":"n2066","loc":[-85.634908,41.940601]},"n2067":{"id":"n2067","loc":[-85.634908,41.94053]},"n2068":{"id":"n2068","loc":[-85.634934,41.94053]},"n2069":{"id":"n2069","loc":[-85.634934,41.940496]},"n207":{"id":"n207","loc":[-85.636262,41.942472]},"n2070":{"id":"n2070","loc":[-85.63504,41.940495]},"n2071":{"id":"n2071","loc":[-85.63504,41.940531]},"n2072":{"id":"n2072","loc":[-85.635068,41.940531]},"n2073":{"id":"n2073","loc":[-85.635071,41.940794]},"n2074":{"id":"n2074","loc":[-85.635183,41.940793]},"n2075":{"id":"n2075","loc":[-85.635185,41.940916]},"n2076":{"id":"n2076","loc":[-85.634799,41.940919]},"n2077":{"id":"n2077","loc":[-85.634798,41.940798]},"n2078":{"id":"n2078","loc":[-85.634925,41.940797]},"n2079":{"id":"n2079","loc":[-85.634924,41.940724]},"n208":{"id":"n208","loc":[-85.636261,41.94233]},"n2080":{"id":"n2080","loc":[-85.637448,41.938233]},"n2081":{"id":"n2081","loc":[-85.634168,41.943279]},"n2082":{"id":"n2082","loc":[-85.635744,41.938248]},"n2083":{"id":"n2083","loc":[-85.638744,41.951211]},"n2084":{"id":"n2084","loc":[-85.636421,41.946392]},"n2085":{"id":"n2085","loc":[-85.635965,41.945809]},"n2086":{"id":"n2086","loc":[-85.635683,41.945449]},"n2087":{"id":"n2087","loc":[-85.635281,41.945025]},"n2088":{"id":"n2088","loc":[-85.632443,41.942574]},"n2089":{"id":"n2089","loc":[-85.638243,41.943674]},"n209":{"id":"n209","loc":[-85.636353,41.942329]},"n2090":{"id":"n2090","loc":[-85.638228,41.943747]},"n2091":{"id":"n2091","loc":[-85.638163,41.943797]},"n2092":{"id":"n2092","loc":[-85.638089,41.943832]},"n2093":{"id":"n2093","loc":[-85.637969,41.943841]},"n2094":{"id":"n2094","loc":[-85.637841,41.943833]},"n2095":{"id":"n2095","loc":[-85.637342,41.943734]},"n2096":{"id":"n2096","loc":[-85.637232,41.943707]},"n2097":{"id":"n2097","loc":[-85.637163,41.943668]},"n2098":{"id":"n2098","loc":[-85.637118,41.943615]},"n2099":{"id":"n2099","loc":[-85.637078,41.943494]},"n21":{"id":"n21","loc":[-85.634126,41.942228]},"n210":{"id":"n210","loc":[-85.636354,41.94239]},"n2100":{"id":"n2100","loc":[-85.632903,41.998429],"tags":{"railway":"level_crossing"}},"n2101":{"id":"n2101","loc":[-85.633616,41.943581],"tags":{"railway":"level_crossing"}},"n2102":{"id":"n2102","loc":[-85.636943,41.947311]},"n2103":{"id":"n2103","loc":[-85.6376,41.94854]},"n2104":{"id":"n2104","loc":[-85.634565,41.93631]},"n2105":{"id":"n2105","loc":[-85.629597,41.942562]},"n2106":{"id":"n2106","loc":[-85.630821,41.943077]},"n2107":{"id":"n2107","loc":[-85.627473,41.940659]},"n2108":{"id":"n2108","loc":[-85.629708,41.942872]},"n2109":{"id":"n2109","loc":[-85.634093,41.935448]},"n211":{"id":"n211","loc":[-85.636393,41.94239]},"n2110":{"id":"n2110","loc":[-85.630413,41.94366]},"n2111":{"id":"n2111","loc":[-85.630488,41.942662]},"n2112":{"id":"n2112","loc":[-85.63361,41.936749]},"n2113":{"id":"n2113","loc":[-85.630038,41.941808]},"n2114":{"id":"n2114","loc":[-85.632016,41.942922]},"n2115":{"id":"n2115","loc":[-85.631525,41.944303]},"n2116":{"id":"n2116","loc":[-85.626862,41.94022]},"n2117":{"id":"n2117","loc":[-85.629673,41.94121]},"n2118":{"id":"n2118","loc":[-85.632752,41.943101]},"n2119":{"id":"n2119","loc":[-85.631147,41.943201]},"n212":{"id":"n212","loc":[-85.63444,41.943176]},"n2120":{"id":"n2120","loc":[-85.624974,41.940579]},"n2121":{"id":"n2121","loc":[-85.629518,41.941783]},"n2122":{"id":"n2122","loc":[-85.632349,41.942699]},"n2123":{"id":"n2123","loc":[-85.628418,41.940356]},"n2124":{"id":"n2124","loc":[-85.629147,41.94129]},"n2125":{"id":"n2125","loc":[-85.631111,41.943979]},"n2126":{"id":"n2126","loc":[-85.632087,41.940013]},"n2127":{"id":"n2127","loc":[-85.634469,41.935057]},"n2128":{"id":"n2128","loc":[-85.630097,41.943449]},"n2129":{"id":"n2129","loc":[-85.6331,41.937878]},"n213":{"id":"n213","loc":[-85.63375,41.942814]},"n2130":{"id":"n2130","loc":[-85.625274,41.941114]},"n2131":{"id":"n2131","loc":[-85.632632,41.941217]},"n2132":{"id":"n2132","loc":[-85.632739,41.941926]},"n2133":{"id":"n2133","loc":[-85.631647,41.94366]},"n2134":{"id":"n2134","loc":[-85.635059,41.935456]},"n2135":{"id":"n2135","loc":[-85.631259,41.944349]},"n2136":{"id":"n2136","loc":[-85.626336,41.940811]},"n2137":{"id":"n2137","loc":[-85.631507,41.943875]},"n2138":{"id":"n2138","loc":[-85.625081,41.940859]},"n2139":{"id":"n2139","loc":[-85.625778,41.940093]},"n214":{"id":"n214","loc":[-85.633674,41.942869]},"n2140":{"id":"n2140","loc":[-85.632641,41.942436]},"n2141":{"id":"n2141","loc":[-85.628825,41.941034]},"n2142":{"id":"n2142","loc":[-85.627913,41.940292]},"n2143":{"id":"n2143","loc":[-85.628943,41.940516]},"n2144":{"id":"n2144","loc":[-85.63139,41.943941]},"n2145":{"id":"n2145","loc":[-85.630081,41.94204]},"n2146":{"id":"n2146","loc":[-85.632194,41.93963]},"n2147":{"id":"n2147","loc":[-85.632913,41.93939]},"n2148":{"id":"n2148","loc":[-85.632001,41.943492]},"n2149":{"id":"n2149","loc":[-85.63149,41.943154]},"n215":{"id":"n215","loc":[-85.633542,41.942768]},"n2150":{"id":"n2150","loc":[-85.625167,41.940117]},"n2151":{"id":"n2151","loc":[-85.63287,41.939941]},"n2152":{"id":"n2152","loc":[-85.630789,41.943732]},"n2153":{"id":"n2153","loc":[-85.632173,41.940348]},"n2154":{"id":"n2154","loc":[-85.626587,41.940113]},"n2155":{"id":"n2155","loc":[-85.62684,41.940667]},"n2156":{"id":"n2156","loc":[-85.632527,41.938904]},"n2157":{"id":"n2157","loc":[-85.624866,41.94018]},"n2158":{"id":"n2158","loc":[-85.633267,41.93872]},"n2159":{"id":"n2159","loc":[-85.62934,41.940843]},"n216":{"id":"n216","loc":[-85.633618,41.942714]},"n2160":{"id":"n2160","loc":[-85.62272,41.953817]},"n2161":{"id":"n2161","loc":[-85.622555,41.954453]},"n2162":{"id":"n2162","loc":[-85.637225,41.944128]},"n2163":{"id":"n2163","loc":[-85.622628,41.953683]},"n2164":{"id":"n2164","loc":[-85.635441,41.943989]},"n2165":{"id":"n2165","loc":[-85.622629,41.953807]},"n2166":{"id":"n2166","loc":[-85.62262,41.953807]},"n2167":{"id":"n2167","loc":[-85.62262,41.953837]},"n2168":{"id":"n2168","loc":[-85.622532,41.953838]},"n2169":{"id":"n2169","loc":[-85.637469,41.944579]},"n217":{"id":"n217","loc":[-85.634001,41.942336]},"n2170":{"id":"n2170","loc":[-85.63688,41.943935]},"n2171":{"id":"n2171","loc":[-85.638263,41.946367]},"n2172":{"id":"n2172","loc":[-85.622532,41.953807]},"n2173":{"id":"n2173","loc":[-85.622353,41.953808]},"n2174":{"id":"n2174","loc":[-85.622352,41.953685]},"n2175":{"id":"n2175","loc":[-85.622464,41.953684]},"n2176":{"id":"n2176","loc":[-85.622464,41.953648]},"n2177":{"id":"n2177","loc":[-85.637136,41.94576]},"n2178":{"id":"n2178","loc":[-85.622521,41.953648]},"n2179":{"id":"n2179","loc":[-85.637129,41.945415]},"n218":{"id":"n218","loc":[-85.633825,41.942376]},"n2180":{"id":"n2180","loc":[-85.637473,41.94607]},"n2181":{"id":"n2181","loc":[-85.622521,41.953683]},"n2182":{"id":"n2182","loc":[-85.622717,41.954104]},"n2183":{"id":"n2183","loc":[-85.637769,41.946095]},"n2184":{"id":"n2184","loc":[-85.623872,41.953515]},"n2185":{"id":"n2185","loc":[-85.623851,41.953588]},"n2186":{"id":"n2186","loc":[-85.631385,41.94433]},"n2187":{"id":"n2187","loc":[-85.623608,41.953543]},"n2188":{"id":"n2188","loc":[-85.637308,41.944882]},"n2189":{"id":"n2189","loc":[-85.634898,41.944041]},"n219":{"id":"n219","loc":[-85.633807,41.942334]},"n2190":{"id":"n2190","loc":[-85.623604,41.953442]},"n2191":{"id":"n2191","loc":[-85.623705,41.953442]},"n2192":{"id":"n2192","loc":[-85.623708,41.953493]},"n2193":{"id":"n2193","loc":[-85.624064,41.952655]},"n2194":{"id":"n2194","loc":[-85.62395,41.952654]},"n2195":{"id":"n2195","loc":[-85.623951,41.952579]},"n2196":{"id":"n2196","loc":[-85.637435,41.944342]},"n2197":{"id":"n2197","loc":[-85.624064,41.952579]},"n2198":{"id":"n2198","loc":[-85.623812,41.952648]},"n2199":{"id":"n2199","loc":[-85.623813,41.952705]},"n22":{"id":"n22","loc":[-85.633531,41.942357]},"n220":{"id":"n220","loc":[-85.633983,41.942294]},"n2200":{"id":"n2200","loc":[-85.637169,41.945098]},"n2201":{"id":"n2201","loc":[-85.623552,41.952707]},"n2202":{"id":"n2202","loc":[-85.623551,41.95263]},"n2203":{"id":"n2203","loc":[-85.623701,41.952629]},"n2204":{"id":"n2204","loc":[-85.635894,41.943719]},"n2205":{"id":"n2205","loc":[-85.637297,41.945992]},"n2206":{"id":"n2206","loc":[-85.623724,41.952648]},"n2207":{"id":"n2207","loc":[-85.623812,41.952438]},"n2208":{"id":"n2208","loc":[-85.625239,41.952197]},"n2209":{"id":"n2209","loc":[-85.625232,41.952257]},"n221":{"id":"n221","loc":[-85.634182,41.942495]},"n2210":{"id":"n2210","loc":[-85.635175,41.94408]},"n2211":{"id":"n2211","loc":[-85.636381,41.943761]},"n2212":{"id":"n2212","loc":[-85.625115,41.952249]},"n2213":{"id":"n2213","loc":[-85.638578,41.946644]},"n2214":{"id":"n2214","loc":[-85.625122,41.952189]},"n2215":{"id":"n2215","loc":[-85.625085,41.952031]},"n2216":{"id":"n2216","loc":[-85.636126,41.943713]},"n2217":{"id":"n2217","loc":[-85.635005,41.944041]},"n2218":{"id":"n2218","loc":[-85.63714,41.945328]},"n2219":{"id":"n2219","loc":[-85.634871,41.943292]},"n222":{"id":"n222","loc":[-85.634149,41.942503]},"n2220":{"id":"n2220","loc":[-85.635705,41.943799]},"n2221":{"id":"n2221","loc":[-85.634995,41.943576]},"n2222":{"id":"n2222","loc":[-85.635026,41.943829]},"n2223":{"id":"n2223","loc":[-85.632874,41.941031]},"n2224":{"id":"n2224","loc":[-85.632531,41.940233]},"n2225":{"id":"n2225","loc":[-85.634247,41.936003]},"n2226":{"id":"n2226","loc":[-85.62929,41.941127]},"n2227":{"id":"n2227","loc":[-85.630428,41.943266]},"n2228":{"id":"n2228","loc":[-85.631608,41.943425]},"n2229":{"id":"n2229","loc":[-85.632316,41.943042]},"n223":{"id":"n223","loc":[-85.634098,41.942373]},"n2230":{"id":"n2230","loc":[-85.628711,41.940744]},"n2231":{"id":"n2231","loc":[-85.627831,41.940536]},"n2232":{"id":"n2232","loc":[-85.625514,41.94052]},"n2233":{"id":"n2233","loc":[-85.631127,41.943545]},"n2234":{"id":"n2234","loc":[-85.632909,41.942531]},"n2235":{"id":"n2235","loc":[-85.632917,41.938796]},"n2236":{"id":"n2236","loc":[-85.626716,41.94044]},"n2237":{"id":"n2237","loc":[-85.630122,41.942852]},"n2238":{"id":"n2238","loc":[-85.632509,41.939674]},"n2239":{"id":"n2239","loc":[-85.634762,41.935237]},"n224":{"id":"n224","loc":[-85.634131,41.942366]},"n2240":{"id":"n2240","loc":[-85.63384,41.937025]},"n2241":{"id":"n2241","loc":[-85.629741,41.941909]},"n2242":{"id":"n2242","loc":[-85.635254,41.945001],"tags":{"railway":"level_crossing"}},"n2243":{"id":"n2243","loc":[-85.634005,41.938168]},"n2244":{"id":"n2244","loc":[-85.63393,41.938335]},"n2245":{"id":"n2245","loc":[-85.633859,41.93846]},"n2246":{"id":"n2246","loc":[-85.633663,41.938776]},"n2247":{"id":"n2247","loc":[-85.633513,41.938936]},"n2248":{"id":"n2248","loc":[-85.635295,41.943225]},"n2249":{"id":"n2249","loc":[-85.635393,41.943293]},"n225":{"id":"n225","loc":[-85.635986,41.94177]},"n2250":{"id":"n2250","loc":[-85.635645,41.94332]},"n2251":{"id":"n2251","loc":[-85.63629,41.943328]},"n2252":{"id":"n2252","loc":[-85.636554,41.943372]},"n2253":{"id":"n2253","loc":[-85.636869,41.943526]},"n2254":{"id":"n2254","loc":[-85.637099,41.943704]},"n2255":{"id":"n2255","loc":[-85.637268,41.943773]},"n2256":{"id":"n2256","loc":[-85.637483,41.943821]},"n2257":{"id":"n2257","loc":[-85.637616,41.943929]},"n2258":{"id":"n2258","loc":[-85.637752,41.944114]},"n2259":{"id":"n2259","loc":[-85.638399,41.944308]},"n226":{"id":"n226","loc":[-85.635982,41.941523]},"n2260":{"id":"n2260","loc":[-85.638573,41.944451]},"n2261":{"id":"n2261","loc":[-85.638702,41.944574]},"n2262":{"id":"n2262","loc":[-85.638718,41.944652]},"n2263":{"id":"n2263","loc":[-85.638715,41.944809]},"n2264":{"id":"n2264","loc":[-85.638766,41.944988]},"n2265":{"id":"n2265","loc":[-85.638773,41.945136]},"n2266":{"id":"n2266","loc":[-85.638705,41.945251]},"n2267":{"id":"n2267","loc":[-85.638335,41.944291]},"n2268":{"id":"n2268","loc":[-85.638474,41.944352]},"n2269":{"id":"n2269","loc":[-85.635408,41.943429]},"n227":{"id":"n227","loc":[-85.636108,41.941521]},"n2270":{"id":"n2270","loc":[-85.635271,41.943654]},"n2271":{"id":"n2271","loc":[-85.635266,41.943744]},"n2272":{"id":"n2272","loc":[-85.635271,41.943819]},"n2273":{"id":"n2273","loc":[-85.635192,41.943876]},"n2274":{"id":"n2274","loc":[-85.635129,41.943857]},"n2275":{"id":"n2275","loc":[-85.635122,41.943764]},"n2276":{"id":"n2276","loc":[-85.635124,41.943664]},"n2277":{"id":"n2277","loc":[-85.63515,41.943611]},"n2278":{"id":"n2278","loc":[-85.635106,41.943534]},"n2279":{"id":"n2279","loc":[-85.634972,41.943197]},"n228":{"id":"n228","loc":[-85.636109,41.941559]},"n2280":{"id":"n2280","loc":[-85.633978,41.938227]},"n2281":{"id":"n2281","loc":[-85.634216,41.943255]},"n2282":{"id":"n2282","loc":[-85.634434,41.943622]},"n2283":{"id":"n2283","loc":[-85.632406,41.940854]},"n2284":{"id":"n2284","loc":[-85.632488,41.941063],"tags":{"leisure":"slipway"}},"n2285":{"id":"n2285","loc":[-85.632726,41.941537]},"n2286":{"id":"n2286","loc":[-85.632639,41.94136]},"n2287":{"id":"n2287","loc":[-85.632704,41.941439]},"n2288":{"id":"n2288","loc":[-85.632289,41.940601]},"n2289":{"id":"n2289","loc":[-85.632541,41.942526]},"n229":{"id":"n229","loc":[-85.636145,41.941559]},"n2290":{"id":"n2290","loc":[-85.634058,41.943173]},"n2291":{"id":"n2291","loc":[-85.636175,41.945974]},"n2292":{"id":"n2292","loc":[-85.636528,41.945975]},"n2293":{"id":"n2293","loc":[-85.637092,41.945893]},"n2294":{"id":"n2294","loc":[-85.637881,41.945647]},"n2295":{"id":"n2295","loc":[-85.639329,41.945162]},"n2296":{"id":"n2296","loc":[-85.639323,41.945026]},"n2297":{"id":"n2297","loc":[-85.638826,41.945032]},"n2298":{"id":"n2298","loc":[-85.638817,41.944174]},"n2299":{"id":"n2299","loc":[-85.638291,41.94418]},"n23":{"id":"n23","loc":[-85.633504,41.942418]},"n230":{"id":"n230","loc":[-85.636145,41.941551]},"n2300":{"id":"n2300","loc":[-85.63828,41.943811]},"n2301":{"id":"n2301","loc":[-85.638195,41.943601]},"n2302":{"id":"n2302","loc":[-85.63719,41.943592]},"n2303":{"id":"n2303","loc":[-85.636697,41.943273]},"n2304":{"id":"n2304","loc":[-85.635375,41.943274]},"n2305":{"id":"n2305","loc":[-85.635091,41.943547]},"n2306":{"id":"n2306","loc":[-85.63442,41.944117]},"n2307":{"id":"n2307","loc":[-85.635117,41.943717]},"n2308":{"id":"n2308","loc":[-85.635601,41.945177]},"n2309":{"id":"n2309","loc":[-85.635819,41.945494]},"n231":{"id":"n231","loc":[-85.636312,41.941549]},"n2310":{"id":"n2310","loc":[-85.635303,41.944891]},"n2311":{"id":"n2311","loc":[-85.637674,41.943802]},"n2312":{"id":"n2312","loc":[-85.638263,41.944272]},"n2313":{"id":"n2313","loc":[-85.634267,41.935266]},"n2314":{"id":"n2314","loc":[-85.639788,41.945152]},"n2315":{"id":"n2315","loc":[-85.639645,41.945167]},"n2316":{"id":"n2316","loc":[-85.639362,41.945233]},"n2317":{"id":"n2317","loc":[-85.638616,41.945163]},"n2318":{"id":"n2318","loc":[-85.638514,41.944936]},"n2319":{"id":"n2319","loc":[-85.638578,41.94503]},"n232":{"id":"n232","loc":[-85.636314,41.941649]},"n2320":{"id":"n2320","loc":[-85.638578,41.945215]},"n2321":{"id":"n2321","loc":[-85.640495,41.947015]},"n2322":{"id":"n2322","loc":[-85.639577,41.946495]},"n2323":{"id":"n2323","loc":[-85.638935,41.946087]},"n2324":{"id":"n2324","loc":[-85.637535,41.94584]},"n2325":{"id":"n2325","loc":[-85.638357,41.945404]},"n2326":{"id":"n2326","loc":[-85.638051,41.94553]},"n2327":{"id":"n2327","loc":[-85.637732,41.945555]},"n2328":{"id":"n2328","loc":[-85.637657,41.945524]},"n2329":{"id":"n2329","loc":[-85.637598,41.945467]},"n233":{"id":"n233","loc":[-85.636152,41.94165]},"n2330":{"id":"n2330","loc":[-85.637669,41.945318]},"n2331":{"id":"n2331","loc":[-85.637894,41.945171]},"n2332":{"id":"n2332","loc":[-85.637923,41.945082]},"n2333":{"id":"n2333","loc":[-85.63793,41.944756]},"n2334":{"id":"n2334","loc":[-85.637976,41.944696]},"n2335":{"id":"n2335","loc":[-85.638044,41.944671]},"n2336":{"id":"n2336","loc":[-85.638129,41.944597]},"n2337":{"id":"n2337","loc":[-85.638252,41.944413]},"n2338":{"id":"n2338","loc":[-85.638092,41.945442]},"n2339":{"id":"n2339","loc":[-85.638409,41.945315]},"n234":{"id":"n234","loc":[-85.636152,41.941628]},"n2340":{"id":"n2340","loc":[-85.638325,41.944771]},"n2341":{"id":"n2341","loc":[-85.638103,41.944744]},"n2342":{"id":"n2342","loc":[-85.637976,41.944781]},"n2343":{"id":"n2343","loc":[-85.637983,41.944865]},"n2344":{"id":"n2344","loc":[-85.638063,41.945074]},"n2345":{"id":"n2345","loc":[-85.638041,41.945206]},"n2346":{"id":"n2346","loc":[-85.637907,41.945309]},"n2347":{"id":"n2347","loc":[-85.637925,41.94539]},"n2348":{"id":"n2348","loc":[-85.637998,41.94545]},"n2349":{"id":"n2349","loc":[-85.637135,41.946254]},"n235":{"id":"n235","loc":[-85.63611,41.941628]},"n2350":{"id":"n2350","loc":[-85.636837,41.946615]},"n2351":{"id":"n2351","loc":[-85.637954,41.948909]},"n2352":{"id":"n2352","loc":[-85.638382,41.949786]},"n2353":{"id":"n2353","loc":[-85.639367,41.951242]},"n2354":{"id":"n2354","loc":[-85.640554,41.951777]},"n2355":{"id":"n2355","loc":[-85.6411,41.952234]},"n2356":{"id":"n2356","loc":[-85.641742,41.952657]},"n2357":{"id":"n2357","loc":[-85.642321,41.952941]},"n2358":{"id":"n2358","loc":[-85.64277,41.953228]},"n2359":{"id":"n2359","loc":[-85.643333,41.953825]},"n236":{"id":"n236","loc":[-85.636113,41.941768]},"n2360":{"id":"n2360","loc":[-85.643579,41.954365]},"n2361":{"id":"n2361","loc":[-85.644439,41.954105]},"n2362":{"id":"n2362","loc":[-85.64506,41.954]},"n2363":{"id":"n2363","loc":[-85.645483,41.953911]},"n2364":{"id":"n2364","loc":[-85.646046,41.953853]},"n2365":{"id":"n2365","loc":[-85.646318,41.953717]},"n2366":{"id":"n2366","loc":[-85.646276,41.953414]},"n2367":{"id":"n2367","loc":[-85.631063,41.957478],"tags":{"emergency":"fire_hydrant"}},"n2368":{"id":"n2368","loc":[-85.630996,41.955857],"tags":{"emergency":"fire_hydrant"}},"n2369":{"id":"n2369","loc":[-85.630976,41.954608],"tags":{"emergency":"fire_hydrant"}},"n237":{"id":"n237","loc":[-85.635983,41.941589],"tags":{"entrance":"yes"}},"n2370":{"id":"n2370","loc":[-85.646,41.953154]},"n2371":{"id":"n2371","loc":[-85.645222,41.953193]},"n2372":{"id":"n2372","loc":[-85.644732,41.953181]},"n2373":{"id":"n2373","loc":[-85.644064,41.953298]},"n2374":{"id":"n2374","loc":[-85.643818,41.953177]},"n2375":{"id":"n2375","loc":[-85.644001,41.95284]},"n2376":{"id":"n2376","loc":[-85.628174,41.95456],"tags":{"emergency":"fire_hydrant"}},"n2377":{"id":"n2377","loc":[-85.644267,41.952591]},"n2378":{"id":"n2378","loc":[-85.644288,41.952328]},"n2379":{"id":"n2379","loc":[-85.627276,41.953987],"tags":{"emergency":"fire_hydrant"}},"n238":{"id":"n238","loc":[-85.635906,41.94159]},"n2380":{"id":"n2380","loc":[-85.644262,41.952153]},"n2381":{"id":"n2381","loc":[-85.644168,41.95204]},"n2382":{"id":"n2382","loc":[-85.64421,41.951749]},"n2383":{"id":"n2383","loc":[-85.64385,41.951586]},"n2384":{"id":"n2384","loc":[-85.62736,41.955964],"tags":{"emergency":"fire_hydrant"}},"n2385":{"id":"n2385","loc":[-85.626307,41.957198],"tags":{"emergency":"fire_hydrant"}},"n2386":{"id":"n2386","loc":[-85.643589,41.951323]},"n2387":{"id":"n2387","loc":[-85.62747,41.957509],"tags":{"emergency":"fire_hydrant"}},"n2388":{"id":"n2388","loc":[-85.628665,41.957492],"tags":{"emergency":"fire_hydrant"}},"n2389":{"id":"n2389","loc":[-85.642535,41.951031]},"n239":{"id":"n239","loc":[-85.635883,41.940182]},"n2390":{"id":"n2390","loc":[-85.642269,41.95088]},"n2391":{"id":"n2391","loc":[-85.641878,41.950814]},"n2392":{"id":"n2392","loc":[-85.641549,41.950806]},"n2393":{"id":"n2393","loc":[-85.641103,41.950549]},"n2394":{"id":"n2394","loc":[-85.630864,41.959046],"tags":{"emergency":"fire_hydrant"}},"n2395":{"id":"n2395","loc":[-85.632249,41.958969],"tags":{"emergency":"fire_hydrant"}},"n2396":{"id":"n2396","loc":[-85.641037,41.949821]},"n2397":{"id":"n2397","loc":[-85.641006,41.949433]},"n2398":{"id":"n2398","loc":[-85.632232,41.95859],"tags":{"emergency":"fire_hydrant"}},"n2399":{"id":"n2399","loc":[-85.632071,41.958345],"tags":{"emergency":"fire_hydrant"}},"n24":{"id":"n24","loc":[-85.634346,41.942792]},"n240":{"id":"n240","loc":[-85.635916,41.94264]},"n2400":{"id":"n2400","loc":[-85.632228,41.9573],"tags":{"emergency":"fire_hydrant"}},"n2401":{"id":"n2401","loc":[-85.641152,41.948257]},"n2402":{"id":"n2402","loc":[-85.641055,41.947304]},"n2403":{"id":"n2403","loc":[-85.638022,41.945897]},"n2404":{"id":"n2404","loc":[-85.638672,41.950778]},"n2405":{"id":"n2405","loc":[-85.63666,41.944492],"tags":{"name":"Memory Isle","place":"island"}},"n2406":{"id":"n2406","loc":[-85.635,41.946389],"tags":{"amenity":"post_office","name":"Three Rivers Post Office"}},"n2407":{"id":"n2407","loc":[-85.633676,41.946036]},"n2408":{"id":"n2408","loc":[-85.633736,41.946078]},"n2409":{"id":"n2409","loc":[-85.633997,41.946185]},"n241":{"id":"n241","loc":[-85.635795,41.941906]},"n2410":{"id":"n2410","loc":[-85.634448,41.945626],"tags":{"highway":"traffic_signals","traffic_signals":"signal"}},"n2411":{"id":"n2411","loc":[-85.63456,41.945731],"tags":{"crossing":"zebra","highway":"crossing"}},"n2412":{"id":"n2412","loc":[-85.634592,41.94578]},"n2413":{"id":"n2413","loc":[-85.634607,41.945815]},"n2414":{"id":"n2414","loc":[-85.634614,41.945864]},"n2415":{"id":"n2415","loc":[-85.636066,41.946185]},"n2416":{"id":"n2416","loc":[-85.636128,41.946352]},"n2417":{"id":"n2417","loc":[-85.636142,41.946452]},"n2418":{"id":"n2418","loc":[-85.635327,41.945292]},"n2419":{"id":"n2419","loc":[-85.635648,41.94558]},"n242":{"id":"n242","loc":[-85.635909,41.941906]},"n2420":{"id":"n2420","loc":[-85.635769,41.945729]},"n2421":{"id":"n2421","loc":[-85.637349,41.945897]},"n2422":{"id":"n2422","loc":[-85.632211,41.95596],"tags":{"emergency":"fire_hydrant"}},"n2423":{"id":"n2423","loc":[-85.635942,41.94598]},"n2424":{"id":"n2424","loc":[-85.636443,41.946042]},"n2425":{"id":"n2425","loc":[-85.635819,41.946052]},"n2426":{"id":"n2426","loc":[-85.636669,41.946025]},"n2427":{"id":"n2427","loc":[-85.636832,41.946005]},"n2428":{"id":"n2428","loc":[-85.637039,41.945968]},"n2429":{"id":"n2429","loc":[-85.636291,41.946046]},"n243":{"id":"n243","loc":[-85.636359,41.941904]},"n2430":{"id":"n2430","loc":[-85.634005,41.943367]},"n2431":{"id":"n2431","loc":[-85.633366,41.943724]},"n2432":{"id":"n2432","loc":[-85.634617,41.946057]},"n2433":{"id":"n2433","loc":[-85.636534,41.944793]},"n2434":{"id":"n2434","loc":[-85.637055,41.945188]},"n2435":{"id":"n2435","loc":[-85.636153,41.944618]},"n2436":{"id":"n2436","loc":[-85.636803,41.944944]},"n2437":{"id":"n2437","loc":[-85.633389,41.945735]},"n2438":{"id":"n2438","loc":[-85.633536,41.94585]},"n2439":{"id":"n2439","loc":[-85.63363,41.945993]},"n244":{"id":"n244","loc":[-85.636351,41.941438]},"n2440":{"id":"n2440","loc":[-85.633268,41.94568]},"n2441":{"id":"n2441","loc":[-85.635947,41.94546]},"n2442":{"id":"n2442","loc":[-85.636277,41.945268]},"n2443":{"id":"n2443","loc":[-85.635203,41.944287]},"n2444":{"id":"n2444","loc":[-85.634876,41.944477]},"n2445":{"id":"n2445","loc":[-85.634975,41.944419]},"n2446":{"id":"n2446","loc":[-85.633877,41.943438]},"n2447":{"id":"n2447","loc":[-85.63508,41.945113]},"n2448":{"id":"n2448","loc":[-85.635372,41.944932]},"n2449":{"id":"n2449","loc":[-85.636594,41.945935]},"n245":{"id":"n245","loc":[-85.635903,41.941436]},"n2450":{"id":"n2450","loc":[-85.636901,41.945747]},"n2451":{"id":"n2451","loc":[-85.636329,41.945228]},"n2452":{"id":"n2452","loc":[-85.636025,41.945417]},"n2453":{"id":"n2453","loc":[-85.634002,41.944644]},"n2454":{"id":"n2454","loc":[-85.63407,41.944692]},"n2455":{"id":"n2455","loc":[-85.634114,41.944756]},"n2456":{"id":"n2456","loc":[-85.633762,41.944809]},"n2457":{"id":"n2457","loc":[-85.634184,41.944807]},"n2458":{"id":"n2458","loc":[-85.634291,41.944819]},"n2459":{"id":"n2459","loc":[-85.634639,41.944845]},"n246":{"id":"n246","loc":[-85.635788,41.941436]},"n2460":{"id":"n2460","loc":[-85.633822,41.944861]},"n2461":{"id":"n2461","loc":[-85.63411,41.944855]},"n2462":{"id":"n2462","loc":[-85.63435,41.944872]},"n2463":{"id":"n2463","loc":[-85.63441,41.944903]},"n2464":{"id":"n2464","loc":[-85.633883,41.944913]},"n2465":{"id":"n2465","loc":[-85.634164,41.944896]},"n2466":{"id":"n2466","loc":[-85.633487,41.944926]},"n2467":{"id":"n2467","loc":[-85.634736,41.944929]},"n2468":{"id":"n2468","loc":[-85.633944,41.944965]},"n2469":{"id":"n2469","loc":[-85.633555,41.944983]},"n247":{"id":"n247","loc":[-85.635929,41.941511]},"n2470":{"id":"n2470","loc":[-85.633995,41.945013]},"n2471":{"id":"n2471","loc":[-85.633614,41.945037]},"n2472":{"id":"n2472","loc":[-85.634848,41.945031]},"n2473":{"id":"n2473","loc":[-85.634049,41.945061]},"n2474":{"id":"n2474","loc":[-85.633678,41.945094]},"n2475":{"id":"n2475","loc":[-85.63317,41.945111]},"n2476":{"id":"n2476","loc":[-85.633357,41.945103]},"n2477":{"id":"n2477","loc":[-85.633728,41.945136]},"n2478":{"id":"n2478","loc":[-85.634146,41.945148]},"n2479":{"id":"n2479","loc":[-85.633416,41.945157]},"n248":{"id":"n248","loc":[-85.635929,41.941317]},"n2480":{"id":"n2480","loc":[-85.634625,41.945172]},"n2481":{"id":"n2481","loc":[-85.633239,41.945174]},"n2482":{"id":"n2482","loc":[-85.63469,41.945185]},"n2483":{"id":"n2483","loc":[-85.634661,41.945203]},"n2484":{"id":"n2484","loc":[-85.63348,41.945214]},"n2485":{"id":"n2485","loc":[-85.633578,41.945221]},"n2486":{"id":"n2486","loc":[-85.634742,41.945231]},"n2487":{"id":"n2487","loc":[-85.634251,41.94525]},"n2488":{"id":"n2488","loc":[-85.633524,41.945254]},"n2489":{"id":"n2489","loc":[-85.63468,41.945271]},"n249":{"id":"n249","loc":[-85.636414,41.941316]},"n2490":{"id":"n2490","loc":[-85.633885,41.945272]},"n2491":{"id":"n2491","loc":[-85.634795,41.945288]},"n2492":{"id":"n2492","loc":[-85.634742,41.94532]},"n2493":{"id":"n2493","loc":[-85.633946,41.945327]},"n2494":{"id":"n2494","loc":[-85.634844,41.945331]},"n2495":{"id":"n2495","loc":[-85.63435,41.945349]},"n2496":{"id":"n2496","loc":[-85.633733,41.945357]},"n2497":{"id":"n2497","loc":[-85.633987,41.945375]},"n2498":{"id":"n2498","loc":[-85.634911,41.945419]},"n2499":{"id":"n2499","loc":[-85.634049,41.945431]},"n25":{"id":"n25","loc":[-85.634333,41.942809]},"n250":{"id":"n250","loc":[-85.636414,41.941511]},"n2500":{"id":"n2500","loc":[-85.633705,41.945461]},"n2501":{"id":"n2501","loc":[-85.633642,41.945408]},"n2502":{"id":"n2502","loc":[-85.634493,41.945475]},"n2503":{"id":"n2503","loc":[-85.634106,41.945484]},"n2504":{"id":"n2504","loc":[-85.635008,41.945505]},"n2505":{"id":"n2505","loc":[-85.633757,41.945506]},"n2506":{"id":"n2506","loc":[-85.634542,41.945519]},"n2507":{"id":"n2507","loc":[-85.634162,41.945536]},"n2508":{"id":"n2508","loc":[-85.633843,41.945547]},"n2509":{"id":"n2509","loc":[-85.634919,41.94556]},"n251":{"id":"n251","loc":[-85.636819,41.941617]},"n2510":{"id":"n2510","loc":[-85.633818,41.945561]},"n2511":{"id":"n2511","loc":[-85.634638,41.94559]},"n2512":{"id":"n2512","loc":[-85.633901,41.945598]},"n2513":{"id":"n2513","loc":[-85.634257,41.945626]},"n2514":{"id":"n2514","loc":[-85.633967,41.945652]},"n2515":{"id":"n2515","loc":[-85.634735,41.945676]},"n2516":{"id":"n2516","loc":[-85.635057,41.945683]},"n2517":{"id":"n2517","loc":[-85.635296,41.945703]},"n2518":{"id":"n2518","loc":[-85.635112,41.945703]},"n2519":{"id":"n2519","loc":[-85.634782,41.945729]},"n252":{"id":"n252","loc":[-85.636718,41.941619]},"n2520":{"id":"n2520","loc":[-85.634052,41.945747]},"n2521":{"id":"n2521","loc":[-85.635296,41.945757]},"n2522":{"id":"n2522","loc":[-85.635314,41.945757]},"n2523":{"id":"n2523","loc":[-85.635112,41.945761]},"n2524":{"id":"n2524","loc":[-85.63484,41.945778]},"n2525":{"id":"n2525","loc":[-85.635314,41.945938]},"n2526":{"id":"n2526","loc":[-85.63484,41.945922]},"n2527":{"id":"n2527","loc":[-85.635461,41.944879]},"n2528":{"id":"n2528","loc":[-85.636024,41.945384]},"n2529":{"id":"n2529","loc":[-85.636145,41.945312]},"n253":{"id":"n253","loc":[-85.636716,41.941509]},"n2530":{"id":"n2530","loc":[-85.6356,41.944797]},"n2531":{"id":"n2531","loc":[-85.635135,41.944354]},"n2532":{"id":"n2532","loc":[-85.632988,41.945369]},"n2533":{"id":"n2533","loc":[-85.633376,41.94563]},"n2534":{"id":"n2534","loc":[-85.633539,41.945534]},"n2535":{"id":"n2535","loc":[-85.633238,41.945248]},"n2536":{"id":"n2536","loc":[-85.633166,41.945216]},"n2537":{"id":"n2537","loc":[-85.633114,41.945188]},"n2538":{"id":"n2538","loc":[-85.633078,41.945127]},"n2539":{"id":"n2539","loc":[-85.633066,41.94508]},"n254":{"id":"n254","loc":[-85.636732,41.941509]},"n2540":{"id":"n2540","loc":[-85.633222,41.945358]},"n2541":{"id":"n2541","loc":[-85.633425,41.945541]},"n2542":{"id":"n2542","loc":[-85.63299,41.9455]},"n2543":{"id":"n2543","loc":[-85.634374,41.944327]},"n2544":{"id":"n2544","loc":[-85.633648,41.943697]},"n2545":{"id":"n2545","loc":[-85.633533,41.943764]},"n2546":{"id":"n2546","loc":[-85.634239,41.944417]},"n2547":{"id":"n2547","loc":[-85.634122,41.944395]},"n2548":{"id":"n2548","loc":[-85.634235,41.944326]},"n2549":{"id":"n2549","loc":[-85.633613,41.943787]},"n255":{"id":"n255","loc":[-85.636731,41.941461]},"n2550":{"id":"n2550","loc":[-85.633915,41.943613]},"n2551":{"id":"n2551","loc":[-85.634015,41.943555]},"n2552":{"id":"n2552","loc":[-85.63433,41.943839]},"n2553":{"id":"n2553","loc":[-85.634236,41.943894]},"n2554":{"id":"n2554","loc":[-85.635413,41.946052]},"n2555":{"id":"n2555","loc":[-85.635405,41.94569]},"n2556":{"id":"n2556","loc":[-85.635684,41.945925]},"n2557":{"id":"n2557","loc":[-85.635614,41.945742]},"n2558":{"id":"n2558","loc":[-85.635401,41.945745]},"n2559":{"id":"n2559","loc":[-85.635406,41.945928]},"n256":{"id":"n256","loc":[-85.636799,41.941461]},"n2560":{"id":"n2560","loc":[-85.633478,41.943663]},"n2561":{"id":"n2561","loc":[-85.633291,41.943526]},"n2562":{"id":"n2562","loc":[-85.633094,41.943541]},"n2563":{"id":"n2563","loc":[-85.633302,41.943492]},"n2564":{"id":"n2564","loc":[-85.633047,41.943623]},"n2565":{"id":"n2565","loc":[-85.633275,41.943562]},"n2566":{"id":"n2566","loc":[-85.633351,41.943518]},"n2567":{"id":"n2567","loc":[-85.633224,41.9434]},"n2568":{"id":"n2568","loc":[-85.633235,41.943369]},"n2569":{"id":"n2569","loc":[-85.635179,41.943911]},"n257":{"id":"n257","loc":[-85.6368,41.9415]},"n2570":{"id":"n2570","loc":[-85.635146,41.943918]},"n2571":{"id":"n2571","loc":[-85.634888,41.943905]},"n2572":{"id":"n2572","loc":[-85.634832,41.943911]},"n2573":{"id":"n2573","loc":[-85.634638,41.944007]},"n2574":{"id":"n2574","loc":[-85.634568,41.94405]},"n2575":{"id":"n2575","loc":[-85.635994,41.94501]},"n2576":{"id":"n2576","loc":[-85.636388,41.944608]},"n2577":{"id":"n2577","loc":[-85.636215,41.944787]},"n2578":{"id":"n2578","loc":[-85.637948,41.944587]},"n2579":{"id":"n2579","loc":[-85.637849,41.944567]},"n258":{"id":"n258","loc":[-85.636814,41.9415]},"n2580":{"id":"n2580","loc":[-85.637895,41.944455]},"n2581":{"id":"n2581","loc":[-85.637996,41.944477]},"n2582":{"id":"n2582","loc":[-85.635525,41.94337]},"n2583":{"id":"n2583","loc":[-85.637847,41.943923]},"n2584":{"id":"n2584","loc":[-85.637891,41.944124]},"n2585":{"id":"n2585","loc":[-85.638167,41.944229]},"n2586":{"id":"n2586","loc":[-85.638236,41.944097]},"n2587":{"id":"n2587","loc":[-85.638207,41.944025]},"n2588":{"id":"n2588","loc":[-85.638141,41.943997]},"n2589":{"id":"n2589","loc":[-85.638057,41.944015]},"n259":{"id":"n259","loc":[-85.636815,41.941538]},"n2590":{"id":"n2590","loc":[-85.637902,41.944231]},"n2591":{"id":"n2591","loc":[-85.638134,41.944307]},"n2592":{"id":"n2592","loc":[-85.638242,41.944294]},"n2593":{"id":"n2593","loc":[-85.638274,41.944222]},"n2594":{"id":"n2594","loc":[-85.638236,41.944174]},"n2595":{"id":"n2595","loc":[-85.638207,41.944157]},"n2596":{"id":"n2596","loc":[-85.637818,41.943984]},"n2597":{"id":"n2597","loc":[-85.634996,41.944439]},"n2598":{"id":"n2598","loc":[-85.633946,41.945804]},"n2599":{"id":"n2599","loc":[-85.634102,41.945864]},"n26":{"id":"n26","loc":[-85.634346,41.942744]},"n260":{"id":"n260","loc":[-85.636827,41.941538]},"n2600":{"id":"n2600","loc":[-85.633819,41.945756]},"n2601":{"id":"n2601","loc":[-85.634025,41.945975]},"n2602":{"id":"n2602","loc":[-85.633742,41.945867]},"n2603":{"id":"n2603","loc":[-85.63373,41.946004]},"n2604":{"id":"n2604","loc":[-85.633947,41.946081]},"n2605":{"id":"n2605","loc":[-85.633872,41.945917]},"n2606":{"id":"n2606","loc":[-85.633825,41.945985]},"n2607":{"id":"n2607","loc":[-85.633762,41.94596]},"n2608":{"id":"n2608","loc":[-85.634224,41.946037]},"n2609":{"id":"n2609","loc":[-85.634357,41.945851]},"n261":{"id":"n261","loc":[-85.636828,41.941584]},"n2610":{"id":"n2610","loc":[-85.634398,41.945813]},"n2611":{"id":"n2611","loc":[-85.634461,41.945812]},"n2612":{"id":"n2612","loc":[-85.634501,41.945852]},"n2613":{"id":"n2613","loc":[-85.634503,41.94597]},"n2614":{"id":"n2614","loc":[-85.634462,41.945971]},"n2615":{"id":"n2615","loc":[-85.634465,41.946036]},"n2616":{"id":"n2616","loc":[-85.634235,41.946072]},"n2617":{"id":"n2617","loc":[-85.634447,41.946036]},"n2618":{"id":"n2618","loc":[-85.634448,41.946052]},"n2619":{"id":"n2619","loc":[-85.634494,41.946051]},"n262":{"id":"n262","loc":[-85.636819,41.941585]},"n2620":{"id":"n2620","loc":[-85.634497,41.946144]},"n2621":{"id":"n2621","loc":[-85.634453,41.946144]},"n2622":{"id":"n2622","loc":[-85.634454,41.94616]},"n2623":{"id":"n2623","loc":[-85.634393,41.946161]},"n2624":{"id":"n2624","loc":[-85.634394,41.94618]},"n2625":{"id":"n2625","loc":[-85.634345,41.94618]},"n2626":{"id":"n2626","loc":[-85.634344,41.946162]},"n2627":{"id":"n2627","loc":[-85.63427,41.946163]},"n2628":{"id":"n2628","loc":[-85.634266,41.946071]},"n2629":{"id":"n2629","loc":[-85.634148,41.946163]},"n263":{"id":"n263","loc":[-85.636854,41.941714]},"n2630":{"id":"n2630","loc":[-85.634213,41.946072]},"n2631":{"id":"n2631","loc":[-85.633293,41.946309]},"n2632":{"id":"n2632","loc":[-85.633122,41.946239]},"n2633":{"id":"n2633","loc":[-85.633295,41.946005]},"n2634":{"id":"n2634","loc":[-85.633395,41.946047]},"n2635":{"id":"n2635","loc":[-85.633404,41.946035]},"n2636":{"id":"n2636","loc":[-85.633459,41.946057]},"n2637":{"id":"n2637","loc":[-85.633387,41.946154]},"n2638":{"id":"n2638","loc":[-85.633403,41.946161]},"n2639":{"id":"n2639","loc":[-85.634176,41.946415]},"n264":{"id":"n264","loc":[-85.636855,41.941774]},"n2640":{"id":"n2640","loc":[-85.634179,41.946339]},"n2641":{"id":"n2641","loc":[-85.634455,41.946345]},"n2642":{"id":"n2642","loc":[-85.634452,41.946422]},"n2643":{"id":"n2643","loc":[-85.63437,41.946421]},"n2644":{"id":"n2644","loc":[-85.634367,41.946497]},"n2645":{"id":"n2645","loc":[-85.634289,41.946495]},"n2646":{"id":"n2646","loc":[-85.634291,41.946448]},"n2647":{"id":"n2647","loc":[-85.634269,41.946448]},"n2648":{"id":"n2648","loc":[-85.63427,41.946417]},"n2649":{"id":"n2649","loc":[-85.63484,41.946328]},"n265":{"id":"n265","loc":[-85.636822,41.941774]},"n2650":{"id":"n2650","loc":[-85.634839,41.946187]},"n2651":{"id":"n2651","loc":[-85.635148,41.946186]},"n2652":{"id":"n2652","loc":[-85.635148,41.946216]},"n2653":{"id":"n2653","loc":[-85.63521,41.946216]},"n2654":{"id":"n2654","loc":[-85.63521,41.946348]},"n2655":{"id":"n2655","loc":[-85.635154,41.946348]},"n2656":{"id":"n2656","loc":[-85.635153,41.946327]},"n2657":{"id":"n2657","loc":[-85.634037,41.946957]},"n2658":{"id":"n2658","loc":[-85.634253,41.946953]},"n2659":{"id":"n2659","loc":[-85.63481,41.946543]},"n266":{"id":"n266","loc":[-85.636822,41.941778]},"n2660":{"id":"n2660","loc":[-85.634809,41.946459]},"n2661":{"id":"n2661","loc":[-85.635154,41.946458]},"n2662":{"id":"n2662","loc":[-85.635155,41.946554]},"n2663":{"id":"n2663","loc":[-85.635022,41.946547]},"n2664":{"id":"n2664","loc":[-85.635022,41.946573]},"n2665":{"id":"n2665","loc":[-85.634909,41.946574]},"n2666":{"id":"n2666","loc":[-85.634909,41.946561]},"n2667":{"id":"n2667","loc":[-85.634896,41.947159]},"n2668":{"id":"n2668","loc":[-85.634894,41.947032]},"n2669":{"id":"n2669","loc":[-85.635024,41.947031]},"n267":{"id":"n267","loc":[-85.636756,41.941779]},"n2670":{"id":"n2670","loc":[-85.635026,41.947158]},"n2671":{"id":"n2671","loc":[-85.635233,41.947105]},"n2672":{"id":"n2672","loc":[-85.635236,41.946991]},"n2673":{"id":"n2673","loc":[-85.635369,41.946993]},"n2674":{"id":"n2674","loc":[-85.635366,41.947107]},"n2675":{"id":"n2675","loc":[-85.634824,41.946929]},"n2676":{"id":"n2676","loc":[-85.634825,41.946818]},"n2677":{"id":"n2677","loc":[-85.63512,41.946819]},"n2678":{"id":"n2678","loc":[-85.635119,41.94693]},"n2679":{"id":"n2679","loc":[-85.634796,41.946806]},"n268":{"id":"n268","loc":[-85.636756,41.941774]},"n2680":{"id":"n2680","loc":[-85.634792,41.946604]},"n2681":{"id":"n2681","loc":[-85.634948,41.946602]},"n2682":{"id":"n2682","loc":[-85.634949,41.946645]},"n2683":{"id":"n2683","loc":[-85.634975,41.946644]},"n2684":{"id":"n2684","loc":[-85.634974,41.946599]},"n2685":{"id":"n2685","loc":[-85.635117,41.946598]},"n2686":{"id":"n2686","loc":[-85.635122,41.946801]},"n2687":{"id":"n2687","loc":[-85.634981,41.946803]},"n2688":{"id":"n2688","loc":[-85.634979,41.946752]},"n2689":{"id":"n2689","loc":[-85.634952,41.946752]},"n269":{"id":"n269","loc":[-85.636721,41.941774]},"n2690":{"id":"n2690","loc":[-85.634953,41.946804]},"n2691":{"id":"n2691","loc":[-85.634649,41.946841]},"n2692":{"id":"n2692","loc":[-85.634331,41.94684]},"n2693":{"id":"n2693","loc":[-85.634183,41.946809]},"n2694":{"id":"n2694","loc":[-85.633699,41.946607]},"n2695":{"id":"n2695","loc":[-85.634487,41.946664]},"n2696":{"id":"n2696","loc":[-85.634486,41.946598]},"n2697":{"id":"n2697","loc":[-85.63423,41.946599]},"n2698":{"id":"n2698","loc":[-85.634231,41.946662]},"n2699":{"id":"n2699","loc":[-85.634284,41.946662]},"n27":{"id":"n27","loc":[-85.634136,41.943183]},"n270":{"id":"n270","loc":[-85.63672,41.941714]},"n2700":{"id":"n2700","loc":[-85.634284,41.946679]},"n2701":{"id":"n2701","loc":[-85.634365,41.946679]},"n2702":{"id":"n2702","loc":[-85.634365,41.946664]},"n2703":{"id":"n2703","loc":[-85.635443,41.947015]},"n2704":{"id":"n2704","loc":[-85.635442,41.946801]},"n2705":{"id":"n2705","loc":[-85.63603,41.9468]},"n2706":{"id":"n2706","loc":[-85.636028,41.947016]},"n2707":{"id":"n2707","loc":[-85.635457,41.946582]},"n2708":{"id":"n2708","loc":[-85.635455,41.946211]},"n2709":{"id":"n2709","loc":[-85.635636,41.946579]},"n271":{"id":"n271","loc":[-85.636767,41.941713]},"n2710":{"id":"n2710","loc":[-85.635716,41.9468]},"n2711":{"id":"n2711","loc":[-85.635969,41.9468]},"n2712":{"id":"n2712","loc":[-85.635973,41.946295]},"n2713":{"id":"n2713","loc":[-85.636019,41.946484]},"n2714":{"id":"n2714","loc":[-85.636022,41.946388]},"n2715":{"id":"n2715","loc":[-85.635961,41.946493]},"n2716":{"id":"n2716","loc":[-85.635713,41.94621]},"n2717":{"id":"n2717","loc":[-85.635416,41.946142]},"n2718":{"id":"n2718","loc":[-85.635759,41.946203]},"n2719":{"id":"n2719","loc":[-85.636153,41.946747]},"n272":{"id":"n272","loc":[-85.636767,41.941706]},"n2720":{"id":"n2720","loc":[-85.635417,41.946915]},"n2721":{"id":"n2721","loc":[-85.636154,41.946915]},"n2722":{"id":"n2722","loc":[-85.635866,41.946473]},"n2723":{"id":"n2723","loc":[-85.635717,41.946633]},"n2724":{"id":"n2724","loc":[-85.635556,41.946166]},"n2725":{"id":"n2725","loc":[-85.63556,41.946556]},"n2726":{"id":"n2726","loc":[-85.635731,41.946594]},"n2727":{"id":"n2727","loc":[-85.635866,41.946595]},"n2728":{"id":"n2728","loc":[-85.635456,41.947028]},"n2729":{"id":"n2729","loc":[-85.635796,41.947023]},"n273":{"id":"n273","loc":[-85.636779,41.941698]},"n2730":{"id":"n2730","loc":[-85.635798,41.947091]},"n2731":{"id":"n2731","loc":[-85.63573,41.947092]},"n2732":{"id":"n2732","loc":[-85.635733,41.947233]},"n2733":{"id":"n2733","loc":[-85.636283,41.946863]},"n2734":{"id":"n2734","loc":[-85.63628,41.946706]},"n2735":{"id":"n2735","loc":[-85.636341,41.946705]},"n2736":{"id":"n2736","loc":[-85.636273,41.946584]},"n2737":{"id":"n2737","loc":[-85.636396,41.946545]},"n2738":{"id":"n2738","loc":[-85.636474,41.946684]},"n2739":{"id":"n2739","loc":[-85.636511,41.946861]},"n274":{"id":"n274","loc":[-85.636798,41.941697]},"n2740":{"id":"n2740","loc":[-85.633713,41.947184]},"n2741":{"id":"n2741","loc":[-85.633651,41.94716]},"n2742":{"id":"n2742","loc":[-85.633704,41.947085]},"n2743":{"id":"n2743","loc":[-85.6336,41.947044]},"n2744":{"id":"n2744","loc":[-85.633506,41.947177]},"n2745":{"id":"n2745","loc":[-85.629586,41.952469]},"n2746":{"id":"n2746","loc":[-85.634723,41.953681]},"n2747":{"id":"n2747","loc":[-85.63478,41.959007]},"n2748":{"id":"n2748","loc":[-85.632793,41.94405],"tags":{"highway":"traffic_signals","traffic_signals":"signal"}},"n2749":{"id":"n2749","loc":[-85.634648,41.947325]},"n275":{"id":"n275","loc":[-85.63681,41.941705]},"n2750":{"id":"n2750","loc":[-85.625078,41.952097]},"n2751":{"id":"n2751","loc":[-85.633195,41.94734]},"n2752":{"id":"n2752","loc":[-85.626447,41.957168]},"n2753":{"id":"n2753","loc":[-85.632023,41.949012]},"n2754":{"id":"n2754","loc":[-85.630835,41.950656]},"n2755":{"id":"n2755","loc":[-85.634655,41.948612]},"n2756":{"id":"n2756","loc":[-85.636182,41.948605]},"n2757":{"id":"n2757","loc":[-85.634729,41.954667]},"n2758":{"id":"n2758","loc":[-85.634686,41.951159]},"n2759":{"id":"n2759","loc":[-85.636206,41.951146]},"n276":{"id":"n276","loc":[-85.63681,41.941714]},"n2760":{"id":"n2760","loc":[-85.634668,41.949891]},"n2761":{"id":"n2761","loc":[-85.634701,41.952422]},"n2762":{"id":"n2762","loc":[-85.634747,41.955907]},"n2763":{"id":"n2763","loc":[-85.627975,41.954695]},"n2764":{"id":"n2764","loc":[-85.626832,41.954698]},"n2765":{"id":"n2765","loc":[-85.632278,41.948624]},"n2766":{"id":"n2766","loc":[-85.628639,41.953725]},"n2767":{"id":"n2767","loc":[-85.636233,41.95241]},"n2768":{"id":"n2768","loc":[-85.631385,41.949913]},"n2769":{"id":"n2769","loc":[-85.630486,41.951194]},"n277":{"id":"n277","loc":[-85.636861,41.942041]},"n2770":{"id":"n2770","loc":[-85.624937,41.952088]},"n2771":{"id":"n2771","loc":[-85.624945,41.952022]},"n2772":{"id":"n2772","loc":[-85.636162,41.94731]},"n2773":{"id":"n2773","loc":[-85.636188,41.949881]},"n2774":{"id":"n2774","loc":[-85.631422,41.948294]},"n2775":{"id":"n2775","loc":[-85.632844,41.945547]},"n2776":{"id":"n2776","loc":[-85.632484,41.945344]},"n2777":{"id":"n2777","loc":[-85.631775,41.944636]},"n2778":{"id":"n2778","loc":[-85.632656,41.945471]},"n2779":{"id":"n2779","loc":[-85.631959,41.944827]},"n278":{"id":"n278","loc":[-85.636862,41.942099]},"n2780":{"id":"n2780","loc":[-85.631679,41.94438]},"n2781":{"id":"n2781","loc":[-85.625129,41.959272]},"n2782":{"id":"n2782","loc":[-85.632446,41.944861]},"n2783":{"id":"n2783","loc":[-85.632804,41.945477]},"n2784":{"id":"n2784","loc":[-85.632255,41.944962]},"n2785":{"id":"n2785","loc":[-85.632736,41.944757]},"n2786":{"id":"n2786","loc":[-85.632543,41.94486]},"n2787":{"id":"n2787","loc":[-85.632889,41.945561]},"n2788":{"id":"n2788","loc":[-85.632091,41.944949]},"n2789":{"id":"n2789","loc":[-85.632537,41.944713]},"n279":{"id":"n279","loc":[-85.636807,41.942099]},"n2790":{"id":"n2790","loc":[-85.632279,41.94485]},"n2791":{"id":"n2791","loc":[-85.632749,41.943247]},"n2792":{"id":"n2792","loc":[-85.632824,41.943152]},"n2793":{"id":"n2793","loc":[-85.632929,41.94317]},"n2794":{"id":"n2794","loc":[-85.632897,41.943078]},"n2795":{"id":"n2795","loc":[-85.632626,41.943231]},"n2796":{"id":"n2796","loc":[-85.634048,41.947257]},"n2797":{"id":"n2797","loc":[-85.634264,41.947252]},"n2798":{"id":"n2798","loc":[-85.635418,41.947317]},"n2799":{"id":"n2799","loc":[-85.635461,41.947237]},"n28":{"id":"n28","loc":[-85.63821,41.944308]},"n280":{"id":"n280","loc":[-85.636807,41.942126]},"n2800":{"id":"n2800","loc":[-85.632868,41.946229]},"n2801":{"id":"n2801","loc":[-85.633673,41.947242]},"n2802":{"id":"n2802","loc":[-85.623604,41.945881],"tags":{"amenity":"school","name":"Barrows School"}},"n2803":{"id":"n2803","loc":[-85.627401,41.943496]},"n2804":{"id":"n2804","loc":[-85.627403,41.943625]},"n2805":{"id":"n2805","loc":[-85.626409,41.943215]},"n2806":{"id":"n2806","loc":[-85.624884,41.943508]},"n2807":{"id":"n2807","loc":[-85.625191,41.943509]},"n2808":{"id":"n2808","loc":[-85.624882,41.94382]},"n2809":{"id":"n2809","loc":[-85.624893,41.945618]},"n281":{"id":"n281","loc":[-85.636726,41.942126]},"n2810":{"id":"n2810","loc":[-85.624912,41.946524]},"n2811":{"id":"n2811","loc":[-85.622721,41.946535]},"n2812":{"id":"n2812","loc":[-85.627399,41.94469]},"n2813":{"id":"n2813","loc":[-85.622716,41.945622]},"n2814":{"id":"n2814","loc":[-85.624886,41.944724]},"n2815":{"id":"n2815","loc":[-85.622674,41.944737]},"n2816":{"id":"n2816","loc":[-85.625092,41.945063]},"n2817":{"id":"n2817","loc":[-85.625233,41.945064]},"n2818":{"id":"n2818","loc":[-85.625229,41.944871]},"n2819":{"id":"n2819","loc":[-85.625066,41.944871]},"n282":{"id":"n282","loc":[-85.636726,41.942098]},"n2820":{"id":"n2820","loc":[-85.625024,41.944901]},"n2821":{"id":"n2821","loc":[-85.625025,41.944924]},"n2822":{"id":"n2822","loc":[-85.625087,41.944926]},"n2823":{"id":"n2823","loc":[-85.625349,41.944506]},"n2824":{"id":"n2824","loc":[-85.625347,41.944388]},"n2825":{"id":"n2825","loc":[-85.625152,41.94439]},"n2826":{"id":"n2826","loc":[-85.625152,41.944431]},"n2827":{"id":"n2827","loc":[-85.625134,41.944431]},"n2828":{"id":"n2828","loc":[-85.625136,41.944508]},"n2829":{"id":"n2829","loc":[-85.623236,41.946341]},"n283":{"id":"n283","loc":[-85.636708,41.942098]},"n2830":{"id":"n2830","loc":[-85.623241,41.946067]},"n2831":{"id":"n2831","loc":[-85.623207,41.946067]},"n2832":{"id":"n2832","loc":[-85.623212,41.945827]},"n2833":{"id":"n2833","loc":[-85.622981,41.945825]},"n2834":{"id":"n2834","loc":[-85.622976,41.946063]},"n2835":{"id":"n2835","loc":[-85.623006,41.946063]},"n2836":{"id":"n2836","loc":[-85.623002,41.946256]},"n2837":{"id":"n2837","loc":[-85.623075,41.946256]},"n2838":{"id":"n2838","loc":[-85.623074,41.946339]},"n2839":{"id":"n2839","loc":[-85.624574,41.951755]},"n284":{"id":"n284","loc":[-85.636708,41.942041]},"n2840":{"id":"n2840","loc":[-85.62498,41.951844]},"n2841":{"id":"n2841","loc":[-85.625086,41.95188]},"n2842":{"id":"n2842","loc":[-85.625135,41.951922]},"n2843":{"id":"n2843","loc":[-85.615273,41.945637]},"n2844":{"id":"n2844","loc":[-85.620172,41.945627]},"n2845":{"id":"n2845","loc":[-85.625167,41.951985]},"n2846":{"id":"n2846","loc":[-85.622741,41.947437]},"n2847":{"id":"n2847","loc":[-85.624907,41.947428]},"n2848":{"id":"n2848","loc":[-85.627046,41.940995]},"n2849":{"id":"n2849","loc":[-85.627295,41.941304]},"n285":{"id":"n285","loc":[-85.635618,41.941852]},"n2850":{"id":"n2850","loc":[-85.627352,41.94148]},"n2851":{"id":"n2851","loc":[-85.62737,41.942261]},"n2852":{"id":"n2852","loc":[-85.6264,41.942263]},"n2853":{"id":"n2853","loc":[-85.622769,41.949228]},"n2854":{"id":"n2854","loc":[-85.624937,41.949218]},"n2855":{"id":"n2855","loc":[-85.630001,41.944664]},"n2856":{"id":"n2856","loc":[-85.624873,41.942022]},"n2857":{"id":"n2857","loc":[-85.622761,41.948333]},"n2858":{"id":"n2858","loc":[-85.624924,41.948334]},"n2859":{"id":"n2859","loc":[-85.620051,41.94383]},"n286":{"id":"n286","loc":[-85.635621,41.94202]},"n2860":{"id":"n2860","loc":[-85.627629,41.946498]},"n2861":{"id":"n2861","loc":[-85.622757,41.950111]},"n2862":{"id":"n2862","loc":[-85.623685,41.954624]},"n2863":{"id":"n2863","loc":[-85.621459,41.944756]},"n2864":{"id":"n2864","loc":[-85.628637,41.944676]},"n2865":{"id":"n2865","loc":[-85.630125,41.944654]},"n2866":{"id":"n2866","loc":[-85.625196,41.952097]},"n2867":{"id":"n2867","loc":[-85.630257,41.944637]},"n2868":{"id":"n2868","loc":[-85.631247,41.944459]},"n2869":{"id":"n2869","loc":[-85.624867,41.94159]},"n287":{"id":"n287","loc":[-85.63524,41.942023]},"n2870":{"id":"n2870","loc":[-85.624958,41.950343]},"n2871":{"id":"n2871","loc":[-85.624948,41.950484]},"n2872":{"id":"n2872","loc":[-85.624813,41.950983]},"n2873":{"id":"n2873","loc":[-85.624723,41.951789]},"n2874":{"id":"n2874","loc":[-85.624262,41.9512]},"n2875":{"id":"n2875","loc":[-85.62414,41.951201]},"n2876":{"id":"n2876","loc":[-85.624139,41.95112]},"n2877":{"id":"n2877","loc":[-85.628481,41.945611]},"n2878":{"id":"n2878","loc":[-85.620072,41.946538]},"n2879":{"id":"n2879","loc":[-85.622763,41.95099]},"n288":{"id":"n288","loc":[-85.635237,41.941855]},"n2880":{"id":"n2880","loc":[-85.62814,41.946963]},"n2881":{"id":"n2881","loc":[-85.628245,41.947031]},"n2882":{"id":"n2882","loc":[-85.628331,41.947066]},"n2883":{"id":"n2883","loc":[-85.629722,41.944444],"tags":{"leisure":"park","name":"Scouter Park"}},"n2884":{"id":"n2884","loc":[-85.629977,41.943907]},"n2885":{"id":"n2885","loc":[-85.629947,41.943775]},"n2886":{"id":"n2886","loc":[-85.629899,41.943625]},"n2887":{"id":"n2887","loc":[-85.632286,41.944257]},"n2888":{"id":"n2888","loc":[-85.632523,41.944179]},"n2889":{"id":"n2889","loc":[-85.632141,41.944293]},"n289":{"id":"n289","loc":[-85.635568,41.940475]},"n2890":{"id":"n2890","loc":[-85.631571,41.9444]},"n2891":{"id":"n2891","loc":[-85.643236,41.941895]},"n2892":{"id":"n2892","loc":[-85.62865,41.945353]},"n2893":{"id":"n2893","loc":[-85.628594,41.945481]},"n2894":{"id":"n2894","loc":[-85.628581,41.947169]},"n2895":{"id":"n2895","loc":[-85.631843,41.943793]},"n2896":{"id":"n2896","loc":[-85.632299,41.943472]},"n2897":{"id":"n2897","loc":[-85.631519,41.944881]},"n2898":{"id":"n2898","loc":[-85.628429,41.947219]},"n2899":{"id":"n2899","loc":[-85.63145,41.945162]},"n29":{"id":"n29","loc":[-85.637963,41.944263]},"n290":{"id":"n290","loc":[-85.634584,41.940477]},"n2900":{"id":"n2900","loc":[-85.630939,41.945519]},"n2901":{"id":"n2901","loc":[-85.62903,41.945719]},"n2902":{"id":"n2902","loc":[-85.630521,41.945559]},"n2903":{"id":"n2903","loc":[-85.629294,41.945585]},"n2904":{"id":"n2904","loc":[-85.629845,41.945543]},"n2905":{"id":"n2905","loc":[-85.631497,41.944625]},"n2906":{"id":"n2906","loc":[-85.630281,41.945553]},"n2907":{"id":"n2907","loc":[-85.628553,41.946973]},"n2908":{"id":"n2908","loc":[-85.631383,41.945338]},"n2909":{"id":"n2909","loc":[-85.628843,41.946103]},"n291":{"id":"n291","loc":[-85.634583,41.940203]},"n2910":{"id":"n2910","loc":[-85.631193,41.945473]},"n2911":{"id":"n2911","loc":[-85.628897,41.945944]},"n2912":{"id":"n2912","loc":[-85.628789,41.946454]},"n2913":{"id":"n2913","loc":[-85.632548,41.944563]},"n2914":{"id":"n2914","loc":[-85.627527,41.944555]},"n2915":{"id":"n2915","loc":[-85.62752,41.943726]},"n2916":{"id":"n2916","loc":[-85.627894,41.943723]},"n2917":{"id":"n2917","loc":[-85.627897,41.943919]},"n2918":{"id":"n2918","loc":[-85.627991,41.943934]},"n2919":{"id":"n2919","loc":[-85.628082,41.943966]},"n292":{"id":"n292","loc":[-85.635567,41.940201]},"n2920":{"id":"n2920","loc":[-85.628177,41.944015]},"n2921":{"id":"n2921","loc":[-85.628193,41.944048]},"n2922":{"id":"n2922","loc":[-85.628167,41.944054]},"n2923":{"id":"n2923","loc":[-85.628193,41.944094]},"n2924":{"id":"n2924","loc":[-85.628213,41.944144]},"n2925":{"id":"n2925","loc":[-85.628214,41.944199]},"n2926":{"id":"n2926","loc":[-85.62833,41.944196]},"n2927":{"id":"n2927","loc":[-85.628328,41.944262]},"n2928":{"id":"n2928","loc":[-85.628173,41.944262]},"n2929":{"id":"n2929","loc":[-85.628171,41.944293]},"n293":{"id":"n293","loc":[-85.635816,41.942673],"tags":{"crossing":"zebra","highway":"crossing"}},"n2930":{"id":"n2930","loc":[-85.628039,41.944296]},"n2931":{"id":"n2931","loc":[-85.62804,41.944329]},"n2932":{"id":"n2932","loc":[-85.627829,41.944335]},"n2933":{"id":"n2933","loc":[-85.627835,41.94455]},"n2936":{"id":"n2936","loc":[-85.632823,41.945994]},"n294":{"id":"n294","loc":[-85.635696,41.942712]},"n2940":{"id":"n2940","loc":[-85.632192,41.945973]},"n2941":{"id":"n2941","loc":[-85.63226,41.94587]},"n2942":{"id":"n2942","loc":[-85.632721,41.946036]},"n2943":{"id":"n2943","loc":[-85.632641,41.946142]},"n2944":{"id":"n2944","loc":[-85.62937,41.947467]},"n2945":{"id":"n2945","loc":[-85.62959,41.942936]},"n2946":{"id":"n2946","loc":[-85.629551,41.94284]},"n2947":{"id":"n2947","loc":[-85.629501,41.942704]},"n2948":{"id":"n2948","loc":[-85.629472,41.942578]},"n2949":{"id":"n2949","loc":[-85.629361,41.941801]},"n295":{"id":"n295","loc":[-85.635679,41.941962]},"n2950":{"id":"n2950","loc":[-85.629339,41.941716]},"n2951":{"id":"n2951","loc":[-85.629315,41.94166]},"n2952":{"id":"n2952","loc":[-85.629279,41.941602]},"n2953":{"id":"n2953","loc":[-85.629227,41.941556]},"n2954":{"id":"n2954","loc":[-85.624261,41.95112]},"n2955":{"id":"n2955","loc":[-85.629153,41.941524]},"n2956":{"id":"n2956","loc":[-85.626904,41.941098]},"n2957":{"id":"n2957","loc":[-85.624588,41.951294]},"n2958":{"id":"n2958","loc":[-85.631844,41.942945]},"n2959":{"id":"n2959","loc":[-85.625854,41.949222]},"n296":{"id":"n296","loc":[-85.635672,41.941337]},"n2960":{"id":"n2960","loc":[-85.625146,41.955238]},"n2961":{"id":"n2961","loc":[-85.626745,41.948296]},"n2962":{"id":"n2962","loc":[-85.625721,41.95524]},"n2963":{"id":"n2963","loc":[-85.624706,41.952317]},"n2964":{"id":"n2964","loc":[-85.62609,41.956147]},"n2965":{"id":"n2965","loc":[-85.624401,41.954928]},"n2966":{"id":"n2966","loc":[-85.626558,41.955367]},"n2967":{"id":"n2967","loc":[-85.62468,41.955096]},"n2968":{"id":"n2968","loc":[-85.624159,41.953929]},"n2969":{"id":"n2969","loc":[-85.62506,41.951113]},"n297":{"id":"n297","loc":[-85.635658,41.941284]},"n2970":{"id":"n2970","loc":[-85.624942,41.951591]},"n2971":{"id":"n2971","loc":[-85.627399,41.947546]},"n2972":{"id":"n2972","loc":[-85.627695,41.947404]},"n2973":{"id":"n2973","loc":[-85.625925,41.94896]},"n2974":{"id":"n2974","loc":[-85.625725,41.950211]},"n2975":{"id":"n2975","loc":[-85.627008,41.947963]},"n2976":{"id":"n2976","loc":[-85.624373,41.953458]},"n2977":{"id":"n2977","loc":[-85.624137,41.954392]},"n2978":{"id":"n2978","loc":[-85.628257,41.947307]},"n2979":{"id":"n2979","loc":[-85.625281,41.95066]},"n298":{"id":"n298","loc":[-85.635602,41.941166]},"n2980":{"id":"n2980","loc":[-85.625865,41.949804]},"n2981":{"id":"n2981","loc":[-85.626508,41.955932]},"n2982":{"id":"n2982","loc":[-85.626333,41.955216]},"n2983":{"id":"n2983","loc":[-85.626637,41.955676]},"n2984":{"id":"n2984","loc":[-85.624223,41.954599]},"n2985":{"id":"n2985","loc":[-85.626219,41.948671]},"n2986":{"id":"n2986","loc":[-85.624556,41.953043]},"n2987":{"id":"n2987","loc":[-85.625598,41.956302]},"n2988":{"id":"n2988","loc":[-85.624571,41.952971]},"n2989":{"id":"n2989","loc":[-85.627141,41.940727]},"n299":{"id":"n299","loc":[-85.635598,41.941138]},"n2990":{"id":"n2990","loc":[-85.627102,41.939144]},"n2991":{"id":"n2991","loc":[-85.627127,41.940086]},"n2992":{"id":"n2992","loc":[-85.627116,41.940843]},"n2993":{"id":"n2993","loc":[-85.627132,41.9402]},"n2994":{"id":"n2994","loc":[-85.629734,41.940078]},"n2995":{"id":"n2995","loc":[-85.6276,41.937412]},"n2996":{"id":"n2996","loc":[-85.627451,41.937549]},"n2997":{"id":"n2997","loc":[-85.627375,41.937618]},"n2998":{"id":"n2998","loc":[-85.627278,41.937728]},"n2999":{"id":"n2999","loc":[-85.627199,41.937842]},"n3":{"id":"n3","loc":[-85.627345,41.953983]},"n30":{"id":"n30","loc":[-85.637882,41.944205]},"n300":{"id":"n300","loc":[-85.635614,41.941076]},"n3000":{"id":"n3000","loc":[-85.627141,41.937981]},"n3001":{"id":"n3001","loc":[-85.627109,41.938153]},"n3002":{"id":"n3002","loc":[-85.627101,41.938699]},"n3003":{"id":"n3003","loc":[-85.628311,41.942261]},"n3004":{"id":"n3004","loc":[-85.628439,41.940082]},"n3005":{"id":"n3005","loc":[-85.619538,41.942622],"tags":{"leisure":"slipway"}},"n3006":{"id":"n3006","loc":[-85.619872,41.942618]},"n3007":{"id":"n3007","loc":[-85.619755,41.942612]},"n3008":{"id":"n3008","loc":[-85.619647,41.942628]},"n3009":{"id":"n3009","loc":[-85.619415,41.942626]},"n301":{"id":"n301","loc":[-85.635659,41.940956]},"n3010":{"id":"n3010","loc":[-85.619212,41.942623]},"n3011":{"id":"n3011","loc":[-85.631485,41.942472]},"n3012":{"id":"n3012","loc":[-85.630986,41.941786]},"n3013":{"id":"n3013","loc":[-85.631797,41.942006]},"n3014":{"id":"n3014","loc":[-85.630972,41.941162]},"n3015":{"id":"n3015","loc":[-85.631396,41.941611],"tags":{"railway":"level_crossing"}},"n3016":{"id":"n3016","loc":[-85.631878,41.941545]},"n3017":{"id":"n3017","loc":[-85.630461,41.94055]},"n3018":{"id":"n3018","loc":[-85.629751,41.939539],"tags":{"railway":"level_crossing"}},"n3019":{"id":"n3019","loc":[-85.631663,41.941513]},"n302":{"id":"n302","loc":[-85.635666,41.940922]},"n3020":{"id":"n3020","loc":[-85.631328,41.941375]},"n3021":{"id":"n3021","loc":[-85.632554,41.941779]},"n3022":{"id":"n3022","loc":[-85.63245,41.941769]},"n3023":{"id":"n3023","loc":[-85.632475,41.941644]},"n3024":{"id":"n3024","loc":[-85.632581,41.941654]},"n3025":{"id":"n3025","loc":[-85.631957,41.941352]},"n3026":{"id":"n3026","loc":[-85.632293,41.941139]},"n3027":{"id":"n3027","loc":[-85.632315,41.941153]},"n3028":{"id":"n3028","loc":[-85.632302,41.941262]},"n3029":{"id":"n3029","loc":[-85.63237,41.941267]},"n303":{"id":"n303","loc":[-85.635667,41.940877]},"n3030":{"id":"n3030","loc":[-85.632356,41.941538]},"n3031":{"id":"n3031","loc":[-85.632134,41.941678]},"n3032":{"id":"n3032","loc":[-85.631942,41.941687]},"n3033":{"id":"n3033","loc":[-85.63203,41.941694]},"n3034":{"id":"n3034","loc":[-85.632166,41.941555]},"n3035":{"id":"n3035","loc":[-85.632412,41.941416]},"n3036":{"id":"n3036","loc":[-85.63248,41.941342]},"n3037":{"id":"n3037","loc":[-85.632502,41.941259]},"n3038":{"id":"n3038","loc":[-85.632453,41.941161]},"n3039":{"id":"n3039","loc":[-85.63235,41.941103]},"n304":{"id":"n304","loc":[-85.635668,41.940655]},"n3040":{"id":"n3040","loc":[-85.632236,41.941118]},"n3041":{"id":"n3041","loc":[-85.631894,41.941355]},"n3042":{"id":"n3042","loc":[-85.631859,41.941411]},"n3043":{"id":"n3043","loc":[-85.632011,41.941587]},"n3044":{"id":"n3044","loc":[-85.632446,41.941379]},"n3045":{"id":"n3045","loc":[-85.632511,41.941416]},"n3046":{"id":"n3046","loc":[-85.632545,41.941634]},"n3047":{"id":"n3047","loc":[-85.632612,41.94164]},"n3048":{"id":"n3048","loc":[-85.632595,41.942197]},"n3049":{"id":"n3049","loc":[-85.632565,41.942241]},"n305":{"id":"n305","loc":[-85.635628,41.940617]},"n3050":{"id":"n3050","loc":[-85.632515,41.942256]},"n3051":{"id":"n3051","loc":[-85.63245,41.94223]},"n3052":{"id":"n3052","loc":[-85.632401,41.942174]},"n3053":{"id":"n3053","loc":[-85.632391,41.942115]},"n3054":{"id":"n3054","loc":[-85.632029,41.941859]},"n3055":{"id":"n3055","loc":[-85.631828,41.941639]},"n3056":{"id":"n3056","loc":[-85.631829,41.941508]},"n3057":{"id":"n3057","loc":[-85.631281,41.94312]},"n3058":{"id":"n3058","loc":[-85.631421,41.943065]},"n3059":{"id":"n3059","loc":[-85.631339,41.942949]},"n306":{"id":"n306","loc":[-85.635623,41.940272]},"n3060":{"id":"n3060","loc":[-85.631199,41.943004]},"n3061":{"id":"n3061","loc":[-85.631102,41.942931]},"n3062":{"id":"n3062","loc":[-85.631009,41.942809]},"n3063":{"id":"n3063","loc":[-85.631383,41.94265]},"n3064":{"id":"n3064","loc":[-85.631477,41.942773]},"n3065":{"id":"n3065","loc":[-85.630638,41.942809]},"n3066":{"id":"n3066","loc":[-85.630738,41.942943]},"n3067":{"id":"n3067","loc":[-85.630841,41.9429]},"n3068":{"id":"n3068","loc":[-85.630741,41.942766]},"n3069":{"id":"n3069","loc":[-85.63054,41.942603]},"n307":{"id":"n307","loc":[-85.635651,41.940183]},"n3070":{"id":"n3070","loc":[-85.630498,41.942619]},"n3071":{"id":"n3071","loc":[-85.630567,41.942718]},"n3072":{"id":"n3072","loc":[-85.630616,41.942698]},"n3073":{"id":"n3073","loc":[-85.630642,41.94273]},"n3074":{"id":"n3074","loc":[-85.630686,41.942714]},"n3075":{"id":"n3075","loc":[-85.630715,41.942754]},"n3076":{"id":"n3076","loc":[-85.6309,41.942681]},"n3077":{"id":"n3077","loc":[-85.630843,41.942605]},"n3078":{"id":"n3078","loc":[-85.6309,41.942581]},"n3079":{"id":"n3079","loc":[-85.630832,41.942487]},"n308":{"id":"n308","loc":[-85.63577,41.940183],"tags":{"crossing":"zebra","highway":"crossing"}},"n3080":{"id":"n3080","loc":[-85.630773,41.942509]},"n3081":{"id":"n3081","loc":[-85.630718,41.942436]},"n3082":{"id":"n3082","loc":[-85.630485,41.942524]},"n3083":{"id":"n3083","loc":[-85.631468,41.941233]},"n3084":{"id":"n3084","loc":[-85.631334,41.94114]},"n3085":{"id":"n3085","loc":[-85.632052,41.940568]},"n3086":{"id":"n3086","loc":[-85.63219,41.940663]},"n3087":{"id":"n3087","loc":[-85.631323,41.940834]},"n3088":{"id":"n3088","loc":[-85.631122,41.941002]},"n3089":{"id":"n3089","loc":[-85.631321,41.941133]},"n309":{"id":"n309","loc":[-85.636939,41.942544]},"n3090":{"id":"n3090","loc":[-85.631521,41.940966]},"n3091":{"id":"n3091","loc":[-85.631103,41.940253]},"n3092":{"id":"n3092","loc":[-85.631226,41.940211]},"n3093":{"id":"n3093","loc":[-85.631597,41.940805]},"n3094":{"id":"n3094","loc":[-85.631474,41.940847]},"n3095":{"id":"n3095","loc":[-85.631811,41.940534]},"n3096":{"id":"n3096","loc":[-85.631588,41.94061]},"n3097":{"id":"n3097","loc":[-85.631438,41.940366]},"n3098":{"id":"n3098","loc":[-85.631661,41.94029]},"n3099":{"id":"n3099","loc":[-85.630621,41.940041]},"n31":{"id":"n31","loc":[-85.63827,41.944203]},"n310":{"id":"n310","loc":[-85.636323,41.942552]},"n3100":{"id":"n3100","loc":[-85.630436,41.939773]},"n3101":{"id":"n3101","loc":[-85.63059,41.939714]},"n3102":{"id":"n3102","loc":[-85.630775,41.939983]},"n3103":{"id":"n3103","loc":[-85.63047,41.940167]},"n3104":{"id":"n3104","loc":[-85.63013,41.939686]},"n3105":{"id":"n3105","loc":[-85.630302,41.939618]},"n3106":{"id":"n3106","loc":[-85.630641,41.9401]},"n3107":{"id":"n3107","loc":[-85.630966,41.940619]},"n3108":{"id":"n3108","loc":[-85.630874,41.940493]},"n3109":{"id":"n3109","loc":[-85.630933,41.940469]},"n311":{"id":"n311","loc":[-85.636257,41.942555]},"n3110":{"id":"n3110","loc":[-85.630763,41.940236]},"n3111":{"id":"n3111","loc":[-85.63088,41.940189]},"n3112":{"id":"n3112","loc":[-85.631142,41.940548]},"n3113":{"id":"n3113","loc":[-85.630958,41.940871]},"n3114":{"id":"n3114","loc":[-85.630874,41.940778]},"n3115":{"id":"n3115","loc":[-85.631062,41.940684]},"n3116":{"id":"n3116","loc":[-85.631146,41.940777]},"n3117":{"id":"n3117","loc":[-85.632031,41.940575]},"n3118":{"id":"n3118","loc":[-85.631777,41.940186]},"n3119":{"id":"n3119","loc":[-85.631346,41.940179]},"n312":{"id":"n312","loc":[-85.636208,41.942561]},"n3120":{"id":"n3120","loc":[-85.631342,41.94012]},"n3121":{"id":"n3121","loc":[-85.631831,41.940118]},"n3122":{"id":"n3122","loc":[-85.632115,41.940543]},"n3123":{"id":"n3123","loc":[-85.631031,41.941683]},"n3124":{"id":"n3124","loc":[-85.630981,41.941608]},"n3125":{"id":"n3125","loc":[-85.631209,41.941516]},"n3126":{"id":"n3126","loc":[-85.631264,41.941586]},"n3127":{"id":"n3127","loc":[-85.630938,41.94155]},"n3128":{"id":"n3128","loc":[-85.631156,41.941462]},"n3129":{"id":"n3129","loc":[-85.631197,41.94152]},"n313":{"id":"n313","loc":[-85.636159,41.942573]},"n3130":{"id":"n3130","loc":[-85.630895,41.941485]},"n3131":{"id":"n3131","loc":[-85.630824,41.941389]},"n3132":{"id":"n3132","loc":[-85.630986,41.941323]},"n3133":{"id":"n3133","loc":[-85.631057,41.941419]},"n3134":{"id":"n3134","loc":[-85.630777,41.941328]},"n3135":{"id":"n3135","loc":[-85.630907,41.941274]},"n3136":{"id":"n3136","loc":[-85.630953,41.941335]},"n3137":{"id":"n3137","loc":[-85.630797,41.941247]},"n3138":{"id":"n3138","loc":[-85.630701,41.94117]},"n3139":{"id":"n3139","loc":[-85.630829,41.941113]},"n314":{"id":"n314","loc":[-85.635743,41.942881]},"n3140":{"id":"n3140","loc":[-85.6309,41.941201]},"n3141":{"id":"n3141","loc":[-85.630765,41.941206]},"n3142":{"id":"n3142","loc":[-85.630739,41.941218]},"n3143":{"id":"n3143","loc":[-85.630582,41.941039]},"n3144":{"id":"n3144","loc":[-85.630412,41.940818]},"n3145":{"id":"n3145","loc":[-85.630509,41.940777]},"n3146":{"id":"n3146","loc":[-85.630678,41.941004]},"n3147":{"id":"n3147","loc":[-85.630773,41.942166]},"n3148":{"id":"n3148","loc":[-85.630708,41.942074]},"n3149":{"id":"n3149","loc":[-85.630863,41.942013]},"n315":{"id":"n315","loc":[-85.635452,41.942966]},"n3150":{"id":"n3150","loc":[-85.630928,41.942105]},"n3151":{"id":"n3151","loc":[-85.630701,41.942026]},"n3152":{"id":"n3152","loc":[-85.630665,41.941971]},"n3153":{"id":"n3153","loc":[-85.630793,41.941918]},"n3154":{"id":"n3154","loc":[-85.630837,41.94197]},"n3155":{"id":"n3155","loc":[-85.630757,41.941871]},"n3156":{"id":"n3156","loc":[-85.630629,41.941923]},"n3157":{"id":"n3157","loc":[-85.630694,41.941783]},"n3158":{"id":"n3158","loc":[-85.630534,41.941847]},"n3159":{"id":"n3159","loc":[-85.630598,41.941935]},"n316":{"id":"n316","loc":[-85.634911,41.943118]},"n3160":{"id":"n3160","loc":[-85.631548,41.93938]},"n3161":{"id":"n3161","loc":[-85.631525,41.939919]},"n3162":{"id":"n3162","loc":[-85.631648,41.940043]},"n3163":{"id":"n3163","loc":[-85.624586,41.951121]},"n3164":{"id":"n3164","loc":[-85.622139,41.952064]},"n3165":{"id":"n3165","loc":[-85.622141,41.952144]},"n3166":{"id":"n3166","loc":[-85.621977,41.952146]},"n3167":{"id":"n3167","loc":[-85.621978,41.952211]},"n3168":{"id":"n3168","loc":[-85.62191,41.952212]},"n3169":{"id":"n3169","loc":[-85.633628,41.935437]},"n317":{"id":"n317","loc":[-85.634743,41.943167]},"n3170":{"id":"n3170","loc":[-85.632849,41.935518]},"n3171":{"id":"n3171","loc":[-85.632376,41.93574]},"n3172":{"id":"n3172","loc":[-85.631517,41.935897]},"n3173":{"id":"n3173","loc":[-85.630433,41.936124]},"n3174":{"id":"n3174","loc":[-85.630207,41.936427]},"n3175":{"id":"n3175","loc":[-85.630346,41.936795]},"n3176":{"id":"n3176","loc":[-85.62996,41.936974]},"n3177":{"id":"n3177","loc":[-85.629916,41.937488]},"n3178":{"id":"n3178","loc":[-85.629946,41.937802]},"n3179":{"id":"n3179","loc":[-85.629977,41.937905]},"n318":{"id":"n318","loc":[-85.634401,41.94328]},"n3180":{"id":"n3180","loc":[-85.63016,41.937909]},"n3181":{"id":"n3181","loc":[-85.630804,41.937791]},"n3182":{"id":"n3182","loc":[-85.631688,41.937808]},"n3183":{"id":"n3183","loc":[-85.631685,41.938008]},"n3184":{"id":"n3184","loc":[-85.631845,41.938116]},"n3185":{"id":"n3185","loc":[-85.63207,41.938181]},"n3186":{"id":"n3186","loc":[-85.632143,41.938371]},"n3187":{"id":"n3187","loc":[-85.632056,41.938435]},"n3188":{"id":"n3188","loc":[-85.631787,41.938457]},"n3189":{"id":"n3189","loc":[-85.631657,41.938728]},"n319":{"id":"n319","loc":[-85.634345,41.943299]},"n3190":{"id":"n3190","loc":[-85.631595,41.93775]},"n3191":{"id":"n3191","loc":[-85.630264,41.937839]},"n3192":{"id":"n3192","loc":[-85.628591,41.948536]},"n3193":{"id":"n3193","loc":[-85.63205,41.951181]},"n3194":{"id":"n3194","loc":[-85.632034,41.949909]},"n3195":{"id":"n3195","loc":[-85.630841,41.951191]},"n3196":{"id":"n3196","loc":[-85.632083,41.9537]},"n3197":{"id":"n3197","loc":[-85.630929,41.959037]},"n3198":{"id":"n3198","loc":[-85.632151,41.959028]},"n3199":{"id":"n3199","loc":[-85.630911,41.957428]},"n32":{"id":"n32","loc":[-85.638273,41.944246]},"n320":{"id":"n320","loc":[-85.634287,41.943326]},"n3200":{"id":"n3200","loc":[-85.63213,41.957427]},"n3201":{"id":"n3201","loc":[-85.632072,41.952447]},"n3202":{"id":"n3202","loc":[-85.632095,41.954677]},"n3203":{"id":"n3203","loc":[-85.632111,41.955911]},"n3204":{"id":"n3204","loc":[-85.630855,41.952457]},"n3205":{"id":"n3205","loc":[-85.630869,41.953709]},"n3206":{"id":"n3206","loc":[-85.63088,41.954682]},"n3207":{"id":"n3207","loc":[-85.630894,41.955913]},"n3208":{"id":"n3208","loc":[-85.633214,41.948619]},"n3209":{"id":"n3209","loc":[-85.633253,41.951171]},"n321":{"id":"n321","loc":[-85.634233,41.943354]},"n3210":{"id":"n3210","loc":[-85.633234,41.949901]},"n3211":{"id":"n3211","loc":[-85.633922,41.948616]},"n3212":{"id":"n3212","loc":[-85.625188,41.947832]},"n3213":{"id":"n3213","loc":[-85.625208,41.947775]},"n3214":{"id":"n3214","loc":[-85.625229,41.94776]},"n3215":{"id":"n3215","loc":[-85.625201,41.947749]},"n3216":{"id":"n3216","loc":[-85.625168,41.947707]},"n3217":{"id":"n3217","loc":[-85.625171,41.947609]},"n3218":{"id":"n3218","loc":[-85.625213,41.947564]},"n3219":{"id":"n3219","loc":[-85.62529,41.94756]},"n322":{"id":"n322","loc":[-85.634099,41.943429]},"n3220":{"id":"n3220","loc":[-85.625303,41.947533]},"n3221":{"id":"n3221","loc":[-85.625344,41.947482]},"n3222":{"id":"n3222","loc":[-85.625442,41.947468]},"n3223":{"id":"n3223","loc":[-85.62565,41.947494]},"n3224":{"id":"n3224","loc":[-85.625726,41.947613]},"n3225":{"id":"n3225","loc":[-85.625703,41.947728]},"n3226":{"id":"n3226","loc":[-85.625534,41.94781]},"n3227":{"id":"n3227","loc":[-85.625391,41.947822]},"n3228":{"id":"n3228","loc":[-85.625304,41.947859]},"n3229":{"id":"n3229","loc":[-85.625203,41.947885]},"n323":{"id":"n323","loc":[-85.633958,41.943507],"tags":{"highway":"crossing"}},"n3230":{"id":"n3230","loc":[-85.624691,41.948659]},"n3231":{"id":"n3231","loc":[-85.624328,41.948661]},"n3232":{"id":"n3232","loc":[-85.624331,41.949046]},"n3233":{"id":"n3233","loc":[-85.624694,41.949045]},"n3234":{"id":"n3234","loc":[-85.623623,41.949606]},"n3235":{"id":"n3235","loc":[-85.623623,41.9497]},"n3236":{"id":"n3236","loc":[-85.623357,41.9497]},"n3237":{"id":"n3237","loc":[-85.623357,41.949614]},"n3238":{"id":"n3238","loc":[-85.623974,41.949429]},"n3239":{"id":"n3239","loc":[-85.623974,41.949605]},"n324":{"id":"n324","loc":[-85.633698,41.943651],"tags":{"railway":"crossing"}},"n3240":{"id":"n3240","loc":[-85.624501,41.951226]},"n3241":{"id":"n3241","loc":[-85.624501,41.951123]},"n3242":{"id":"n3242","loc":[-85.624319,41.951123]},"n3243":{"id":"n3243","loc":[-85.624319,41.951226]},"n3244":{"id":"n3244","loc":[-85.624121,41.950866]},"n3245":{"id":"n3245","loc":[-85.624115,41.950525]},"n3246":{"id":"n3246","loc":[-85.624315,41.950523]},"n3247":{"id":"n3247","loc":[-85.62432,41.950865]},"n3248":{"id":"n3248","loc":[-85.624393,41.950867]},"n3249":{"id":"n3249","loc":[-85.62439,41.950596]},"n325":{"id":"n325","loc":[-85.633508,41.943757]},"n3250":{"id":"n3250","loc":[-85.624673,41.950594]},"n3251":{"id":"n3251","loc":[-85.624675,41.95082]},"n3252":{"id":"n3252","loc":[-85.62451,41.950821]},"n3253":{"id":"n3253","loc":[-85.62451,41.950866]},"n3254":{"id":"n3254","loc":[-85.624101,41.949346]},"n3255":{"id":"n3255","loc":[-85.624244,41.949346]},"n3256":{"id":"n3256","loc":[-85.624244,41.949368]},"n3257":{"id":"n3257","loc":[-85.62434,41.949368]},"n3258":{"id":"n3258","loc":[-85.624342,41.949351]},"n3259":{"id":"n3259","loc":[-85.624725,41.949348]},"n326":{"id":"n326","loc":[-85.634839,41.942974]},"n3260":{"id":"n3260","loc":[-85.624755,41.950495]},"n3261":{"id":"n3261","loc":[-85.624121,41.950502]},"n3262":{"id":"n3262","loc":[-85.625453,41.950163]},"n3263":{"id":"n3263","loc":[-85.625454,41.949976]},"n3264":{"id":"n3264","loc":[-85.625549,41.949977]},"n3265":{"id":"n3265","loc":[-85.62555,41.949833]},"n3266":{"id":"n3266","loc":[-85.625577,41.949833]},"n3267":{"id":"n3267","loc":[-85.625578,41.949656]},"n3268":{"id":"n3268","loc":[-85.625195,41.949655]},"n3269":{"id":"n3269","loc":[-85.625192,41.950162]},"n327":{"id":"n327","loc":[-85.634657,41.943028]},"n3270":{"id":"n3270","loc":[-85.622992,41.949614]},"n3271":{"id":"n3271","loc":[-85.622991,41.949431]},"n3272":{"id":"n3272","loc":[-85.620103,41.951]},"n3273":{"id":"n3273","loc":[-85.605644,41.947468]},"n3274":{"id":"n3274","loc":[-85.617421,41.947457]},"n3275":{"id":"n3275","loc":[-85.620078,41.947444]},"n3276":{"id":"n3276","loc":[-85.620087,41.94924]},"n3277":{"id":"n3277","loc":[-85.62156,41.948333]},"n3278":{"id":"n3278","loc":[-85.620106,41.950132]},"n3279":{"id":"n3279","loc":[-85.637412,41.951136]},"n328":{"id":"n328","loc":[-85.634222,41.943152]},"n3280":{"id":"n3280","loc":[-85.635429,41.948608]},"n3281":{"id":"n3281","loc":[-85.635047,41.947788]},"n3282":{"id":"n3282","loc":[-85.635048,41.947796]},"n3283":{"id":"n3283","loc":[-85.635002,41.947797]},"n3284":{"id":"n3284","loc":[-85.635002,41.947788]},"n3285":{"id":"n3285","loc":[-85.634914,41.94779]},"n3286":{"id":"n3286","loc":[-85.634913,41.947753]},"n3287":{"id":"n3287","loc":[-85.63494,41.947753]},"n3288":{"id":"n3288","loc":[-85.634938,41.947708]},"n3289":{"id":"n3289","loc":[-85.635124,41.947705]},"n329":{"id":"n329","loc":[-85.634099,41.943202]},"n3290":{"id":"n3290","loc":[-85.635126,41.947787]},"n3291":{"id":"n3291","loc":[-85.634972,41.947599]},"n3292":{"id":"n3292","loc":[-85.634921,41.9476]},"n3293":{"id":"n3293","loc":[-85.63485,41.947546]},"n3294":{"id":"n3294","loc":[-85.63485,41.947508]},"n3295":{"id":"n3295","loc":[-85.634924,41.947457]},"n3296":{"id":"n3296","loc":[-85.634967,41.947456]},"n3297":{"id":"n3297","loc":[-85.635041,41.947512]},"n3298":{"id":"n3298","loc":[-85.635041,41.947542]},"n3299":{"id":"n3299","loc":[-85.634244,41.947839]},"n33":{"id":"n33","loc":[-85.638257,41.944188]},"n330":{"id":"n330","loc":[-85.634093,41.943138]},"n3300":{"id":"n3300","loc":[-85.634243,41.947793]},"n3301":{"id":"n3301","loc":[-85.634244,41.947686]},"n3302":{"id":"n3302","loc":[-85.634243,41.947657]},"n3303":{"id":"n3303","loc":[-85.634462,41.947653]},"n3304":{"id":"n3304","loc":[-85.634468,41.947835]},"n3305":{"id":"n3305","loc":[-85.634416,41.948006]},"n3306":{"id":"n3306","loc":[-85.634415,41.947898]},"n3307":{"id":"n3307","loc":[-85.634275,41.947899]},"n3308":{"id":"n3308","loc":[-85.634275,41.947927]},"n3309":{"id":"n3309","loc":[-85.63425,41.947927]},"n331":{"id":"n331","loc":[-85.633938,41.943291]},"n3310":{"id":"n3310","loc":[-85.63425,41.947976]},"n3311":{"id":"n3311","loc":[-85.634274,41.947976]},"n3312":{"id":"n3312","loc":[-85.634275,41.948007]},"n3313":{"id":"n3313","loc":[-85.634342,41.947635]},"n3314":{"id":"n3314","loc":[-85.634339,41.947497]},"n3315":{"id":"n3315","loc":[-85.634313,41.94748]},"n3316":{"id":"n3316","loc":[-85.634287,41.947474]},"n3317":{"id":"n3317","loc":[-85.63498,41.94815]},"n3318":{"id":"n3318","loc":[-85.634891,41.94815]},"n3319":{"id":"n3319","loc":[-85.634892,41.948169]},"n332":{"id":"n332","loc":[-85.633535,41.943511],"tags":{"railway":"crossing"}},"n3320":{"id":"n3320","loc":[-85.634852,41.948169]},"n3321":{"id":"n3321","loc":[-85.634853,41.948268]},"n3322":{"id":"n3322","loc":[-85.634832,41.948268]},"n3323":{"id":"n3323","loc":[-85.634832,41.948296]},"n3324":{"id":"n3324","loc":[-85.634965,41.948295]},"n3325":{"id":"n3325","loc":[-85.634966,41.948321]},"n3326":{"id":"n3326","loc":[-85.634999,41.948321]},"n3327":{"id":"n3327","loc":[-85.634999,41.948295]},"n3328":{"id":"n3328","loc":[-85.635175,41.948293]},"n3329":{"id":"n3329","loc":[-85.635175,41.948262]},"n333":{"id":"n333","loc":[-85.63339,41.943596]},"n3330":{"id":"n3330","loc":[-85.635159,41.948262]},"n3331":{"id":"n3331","loc":[-85.635158,41.948152]},"n3332":{"id":"n3332","loc":[-85.635067,41.948152]},"n3333":{"id":"n3333","loc":[-85.635065,41.947966]},"n3334":{"id":"n3334","loc":[-85.634979,41.947966]},"n3335":{"id":"n3335","loc":[-85.634307,41.948326]},"n3336":{"id":"n3336","loc":[-85.634305,41.948298]},"n3337":{"id":"n3337","loc":[-85.634331,41.948055]},"n3338":{"id":"n3338","loc":[-85.634331,41.948046]},"n3339":{"id":"n3339","loc":[-85.634435,41.948047]},"n334":{"id":"n334","loc":[-85.632842,41.943895]},"n3340":{"id":"n3340","loc":[-85.634434,41.948375]},"n3341":{"id":"n3341","loc":[-85.634463,41.948373]},"n3342":{"id":"n3342","loc":[-85.634464,41.948456]},"n3343":{"id":"n3343","loc":[-85.63443,41.948457]},"n3344":{"id":"n3344","loc":[-85.634432,41.948505]},"n3345":{"id":"n3345","loc":[-85.637386,41.94906]},"n3346":{"id":"n3346","loc":[-85.637113,41.9486]},"n3347":{"id":"n3347","loc":[-85.635448,41.949424]},"n335":{"id":"n335","loc":[-85.633856,41.943315]},"n3352":{"id":"n3352","loc":[-85.635457,41.949787]},"n3353":{"id":"n3353","loc":[-85.635459,41.949886]},"n336":{"id":"n336","loc":[-85.633697,41.943405]},"n337":{"id":"n337","loc":[-85.63347,41.943181]},"n3372":{"id":"n3372","loc":[-85.634423,41.950964]},"n3373":{"id":"n3373","loc":[-85.634424,41.95074]},"n3374":{"id":"n3374","loc":[-85.634394,41.950284]},"n3375":{"id":"n3375","loc":[-85.634398,41.950626]},"n3376":{"id":"n3376","loc":[-85.63452,41.951063]},"n3377":{"id":"n3377","loc":[-85.634511,41.949977]},"n3378":{"id":"n3378","loc":[-85.637409,41.949873]},"n3379":{"id":"n3379","loc":[-85.634824,41.94996]},"n338":{"id":"n338","loc":[-85.633597,41.943109]},"n3380":{"id":"n3380","loc":[-85.635437,41.949954]},"n3381":{"id":"n3381","loc":[-85.634844,41.951064]},"n3382":{"id":"n3382","loc":[-85.635458,41.951058]},"n3383":{"id":"n3383","loc":[-85.633921,41.947333]},"n3384":{"id":"n3384","loc":[-85.634208,41.947793]},"n3385":{"id":"n3385","loc":[-85.634204,41.947687]},"n3386":{"id":"n3386","loc":[-85.63424,41.947475]},"n3387":{"id":"n3387","loc":[-85.63424,41.947635]},"n3388":{"id":"n3388","loc":[-85.634089,41.948328]},"n3389":{"id":"n3389","loc":[-85.63424,41.948299]},"n339":{"id":"n339","loc":[-85.633673,41.943184]},"n3390":{"id":"n3390","loc":[-85.634239,41.948212]},"n3391":{"id":"n3391","loc":[-85.634086,41.948214]},"n3392":{"id":"n3392","loc":[-85.63408,41.948056]},"n3393":{"id":"n3393","loc":[-85.634093,41.948506]},"n3394":{"id":"n3394","loc":[-85.64344,41.941866]},"n3395":{"id":"n3395","loc":[-85.63378,41.95099]},"n3396":{"id":"n3396","loc":[-85.633779,41.950967]},"n3397":{"id":"n3397","loc":[-85.63375,41.950746]},"n3398":{"id":"n3398","loc":[-85.63375,41.950697]},"n3399":{"id":"n3399","loc":[-85.633903,41.950696]},"n34":{"id":"n34","loc":[-85.638176,41.944312]},"n340":{"id":"n340","loc":[-85.633714,41.94316]},"n3400":{"id":"n3400","loc":[-85.633901,41.950436]},"n3401":{"id":"n3401","loc":[-85.633492,41.950438]},"n3402":{"id":"n3402","loc":[-85.633494,41.950756]},"n3403":{"id":"n3403","loc":[-85.633454,41.950756]},"n3404":{"id":"n3404","loc":[-85.633456,41.950992]},"n3405":{"id":"n3405","loc":[-85.633994,41.950284]},"n3406":{"id":"n3406","loc":[-85.633998,41.950628]},"n3407":{"id":"n3407","loc":[-85.633364,41.951068]},"n3408":{"id":"n3408","loc":[-85.633356,41.949982]},"n3409":{"id":"n3409","loc":[-85.643327,41.941903]},"n341":{"id":"n341","loc":[-85.633811,41.943256]},"n3410":{"id":"n3410","loc":[-85.633292,41.953691]},"n3411":{"id":"n3411","loc":[-85.637432,41.952399]},"n3412":{"id":"n3412","loc":[-85.633349,41.957422]},"n3413":{"id":"n3413","loc":[-85.633326,41.955909]},"n3414":{"id":"n3414","loc":[-85.633307,41.954673]},"n3415":{"id":"n3415","loc":[-85.633273,41.952436]},"n3416":{"id":"n3416","loc":[-85.633361,41.95823],"tags":{"highway":"turning_circle"}},"n3417":{"id":"n3417","loc":[-85.619899,41.945527]},"n3418":{"id":"n3418","loc":[-85.643422,41.941946]},"n3419":{"id":"n3419","loc":[-85.643505,41.942033]},"n342":{"id":"n342","loc":[-85.633801,41.943261]},"n3420":{"id":"n3420","loc":[-85.620088,41.945571]},"n3421":{"id":"n3421","loc":[-85.620051,41.945505]},"n3422":{"id":"n3422","loc":[-85.62001,41.94541]},"n3423":{"id":"n3423","loc":[-85.620982,41.944742]},"n3424":{"id":"n3424","loc":[-85.621305,41.944782]},"n3425":{"id":"n3425","loc":[-85.621174,41.944819]},"n3426":{"id":"n3426","loc":[-85.621029,41.944871]},"n3427":{"id":"n3427","loc":[-85.620741,41.945011]},"n3428":{"id":"n3428","loc":[-85.620616,41.945085]},"n3429":{"id":"n3429","loc":[-85.620506,41.945172]},"n343":{"id":"n343","loc":[-85.63374,41.943514]},"n3430":{"id":"n3430","loc":[-85.620394,41.945273]},"n3431":{"id":"n3431","loc":[-85.620316,41.94536]},"n3432":{"id":"n3432","loc":[-85.620257,41.945452]},"n3433":{"id":"n3433","loc":[-85.620212,41.945535]},"n3434":{"id":"n3434","loc":[-85.620101,41.945811]},"n3435":{"id":"n3435","loc":[-85.620081,41.945937]},"n3436":{"id":"n3436","loc":[-85.619899,41.943718]},"n3437":{"id":"n3437","loc":[-85.619969,41.943211]},"n3438":{"id":"n3438","loc":[-85.619894,41.943292]},"n3439":{"id":"n3439","loc":[-85.620047,41.944738]},"n344":{"id":"n344","loc":[-85.633665,41.943441]},"n3440":{"id":"n3440","loc":[-85.620226,41.946088]},"n3441":{"id":"n3441","loc":[-85.620225,41.945864]},"n3442":{"id":"n3442","loc":[-85.620518,41.945863]},"n3443":{"id":"n3443","loc":[-85.620519,41.945944]},"n3444":{"id":"n3444","loc":[-85.620388,41.945944]},"n3445":{"id":"n3445","loc":[-85.620389,41.946088]},"n3446":{"id":"n3446","loc":[-85.618405,41.946566]},"n3447":{"id":"n3447","loc":[-85.619156,41.946562]},"n3448":{"id":"n3448","loc":[-85.619154,41.946319]},"n3449":{"id":"n3449","loc":[-85.618736,41.946322]},"n345":{"id":"n345","loc":[-85.633162,41.942947]},"n3450":{"id":"n3450","loc":[-85.618733,41.94612]},"n3451":{"id":"n3451","loc":[-85.619317,41.946116]},"n3452":{"id":"n3452","loc":[-85.619316,41.946023]},"n3453":{"id":"n3453","loc":[-85.619622,41.946021]},"n3454":{"id":"n3454","loc":[-85.619624,41.946171]},"n3455":{"id":"n3455","loc":[-85.61977,41.94617]},"n3456":{"id":"n3456","loc":[-85.619769,41.94602]},"n3457":{"id":"n3457","loc":[-85.619732,41.94602]},"n3458":{"id":"n3458","loc":[-85.619731,41.945856]},"n3459":{"id":"n3459","loc":[-85.619617,41.945857]},"n346":{"id":"n346","loc":[-85.633598,41.943083]},"n3460":{"id":"n3460","loc":[-85.619616,41.945776]},"n3461":{"id":"n3461","loc":[-85.619447,41.945777]},"n3462":{"id":"n3462","loc":[-85.619415,41.945778]},"n3463":{"id":"n3463","loc":[-85.618378,41.945788]},"n3464":{"id":"n3464","loc":[-85.618384,41.946132]},"n3465":{"id":"n3465","loc":[-85.618503,41.94613]},"n3466":{"id":"n3466","loc":[-85.618506,41.946319]},"n3467":{"id":"n3467","loc":[-85.6184,41.94632]},"n3468":{"id":"n3468","loc":[-85.618248,41.946416]},"n3469":{"id":"n3469","loc":[-85.618247,41.946319]},"n347":{"id":"n347","loc":[-85.63343,41.943179]},"n3470":{"id":"n3470","loc":[-85.618039,41.946321]},"n3471":{"id":"n3471","loc":[-85.61804,41.946418]},"n3472":{"id":"n3472","loc":[-85.620118,41.951895]},"n3473":{"id":"n3473","loc":[-85.617075,41.95469]},"n3474":{"id":"n3474","loc":[-85.620107,41.952113]},"n3475":{"id":"n3475","loc":[-85.620091,41.95232]},"n3476":{"id":"n3476","loc":[-85.620047,41.952505]},"n3477":{"id":"n3477","loc":[-85.61998,41.952715]},"n3478":{"id":"n3478","loc":[-85.619861,41.952986]},"n3479":{"id":"n3479","loc":[-85.619622,41.953365]},"n348":{"id":"n348","loc":[-85.633669,41.94341]},"n3480":{"id":"n3480","loc":[-85.619441,41.953567]},"n3481":{"id":"n3481","loc":[-85.619259,41.953741]},"n3482":{"id":"n3482","loc":[-85.618835,41.954056]},"n3483":{"id":"n3483","loc":[-85.618602,41.954194]},"n3484":{"id":"n3484","loc":[-85.618305,41.954347]},"n3485":{"id":"n3485","loc":[-85.618006,41.954466]},"n3486":{"id":"n3486","loc":[-85.617611,41.954587]},"n3487":{"id":"n3487","loc":[-85.615094,41.943412]},"n3488":{"id":"n3488","loc":[-85.619337,41.943025]},"n3489":{"id":"n3489","loc":[-85.610477,41.945527]},"n349":{"id":"n349","loc":[-85.633566,41.943466]},"n3490":{"id":"n3490","loc":[-85.610477,41.943718]},"n3491":{"id":"n3491","loc":[-85.619804,41.942976]},"n3492":{"id":"n3492","loc":[-85.61921,41.942672]},"n3493":{"id":"n3493","loc":[-85.619862,41.942836]},"n3494":{"id":"n3494","loc":[-85.616326,41.942769]},"n3495":{"id":"n3495","loc":[-85.617953,41.942917]},"n3496":{"id":"n3496","loc":[-85.61972,41.942728]},"n3497":{"id":"n3497","loc":[-85.61944,41.942784]},"n3498":{"id":"n3498","loc":[-85.615323,41.942841]},"n3499":{"id":"n3499","loc":[-85.612923,41.943718]},"n35":{"id":"n35","loc":[-85.637928,41.944249]},"n350":{"id":"n350","loc":[-85.633031,41.942986]},"n3500":{"id":"n3500","loc":[-85.61958,41.942756]},"n3501":{"id":"n3501","loc":[-85.619643,41.942647],"tags":{"leisure":"fishing"}},"n3502":{"id":"n3502","loc":[-85.619935,41.942962]},"n3503":{"id":"n3503","loc":[-85.629677,41.954687]},"n3504":{"id":"n3504","loc":[-85.629083,41.953722]},"n3505":{"id":"n3505","loc":[-85.621907,41.952067]},"n3506":{"id":"n3506","loc":[-85.621788,41.952058]},"n3507":{"id":"n3507","loc":[-85.629665,41.953718]},"n3508":{"id":"n3508","loc":[-85.624454,41.954707]},"n3509":{"id":"n3509","loc":[-85.634609,41.954585]},"n351":{"id":"n351","loc":[-85.633238,41.94283]},"n3510":{"id":"n3510","loc":[-85.634595,41.953772]},"n3511":{"id":"n3511","loc":[-85.633425,41.953783]},"n3512":{"id":"n3512","loc":[-85.633439,41.954596]},"n3517":{"id":"n3517","loc":[-85.621789,41.952179]},"n3518":{"id":"n3518","loc":[-85.624105,41.954704]},"n3519":{"id":"n3519","loc":[-85.623306,41.954542]},"n352":{"id":"n352","loc":[-85.633173,41.943556]},"n3520":{"id":"n3520","loc":[-85.623123,41.954502]},"n3521":{"id":"n3521","loc":[-85.622965,41.954473]},"n3522":{"id":"n3522","loc":[-85.622822,41.954455]},"n3523":{"id":"n3523","loc":[-85.62269,41.954448]},"n3524":{"id":"n3524","loc":[-85.622388,41.954467]},"n3525":{"id":"n3525","loc":[-85.62403,41.954895]},"n3526":{"id":"n3526","loc":[-85.623579,41.954855]},"n3527":{"id":"n3527","loc":[-85.623836,41.954951]},"n3528":{"id":"n3528","loc":[-85.622473,41.954592]},"n3529":{"id":"n3529","loc":[-85.622753,41.95458]},"n353":{"id":"n353","loc":[-85.633127,41.943552]},"n3530":{"id":"n3530","loc":[-85.62404,41.955078]},"n3531":{"id":"n3531","loc":[-85.624126,41.954999]},"n3532":{"id":"n3532","loc":[-85.623171,41.954687]},"n3533":{"id":"n3533","loc":[-85.624276,41.955206]},"n3534":{"id":"n3534","loc":[-85.62491,41.952801]},"n3535":{"id":"n3535","loc":[-85.625186,41.952756]},"n3536":{"id":"n3536","loc":[-85.625552,41.952792]},"n3537":{"id":"n3537","loc":[-85.626001,41.952948]},"n3538":{"id":"n3538","loc":[-85.626528,41.952984]},"n3539":{"id":"n3539","loc":[-85.626942,41.952886]},"n354":{"id":"n354","loc":[-85.632745,41.943222]},"n3540":{"id":"n3540","loc":[-85.627092,41.952685]},"n3541":{"id":"n3541","loc":[-85.627212,41.95244]},"n3542":{"id":"n3542","loc":[-85.627158,41.952226]},"n3543":{"id":"n3543","loc":[-85.627002,41.951972]},"n3544":{"id":"n3544","loc":[-85.626822,41.951838]},"n3545":{"id":"n3545","loc":[-85.626528,41.951807]},"n3546":{"id":"n3546","loc":[-85.625653,41.951852]},"n3547":{"id":"n3547","loc":[-85.625348,41.951834]},"n3548":{"id":"n3548","loc":[-85.625114,41.951767]},"n3549":{"id":"n3549","loc":[-85.620627,41.954682]},"n355":{"id":"n355","loc":[-85.632756,41.943199]},"n3550":{"id":"n3550","loc":[-85.622758,41.951884]},"n3551":{"id":"n3551","loc":[-85.618135,41.954734]},"n3552":{"id":"n3552","loc":[-85.620229,41.95472]},"n3553":{"id":"n3553","loc":[-85.624491,41.955573]},"n3554":{"id":"n3554","loc":[-85.621792,41.958314]},"n3555":{"id":"n3555","loc":[-85.623395,41.960001]},"n3556":{"id":"n3556","loc":[-85.620461,41.956212]},"n3557":{"id":"n3557","loc":[-85.62109,41.956766]},"n3558":{"id":"n3558","loc":[-85.620246,41.956224]},"n3559":{"id":"n3559","loc":[-85.625017,41.956068]},"n356":{"id":"n356","loc":[-85.632855,41.943147]},"n3560":{"id":"n3560","loc":[-85.622795,41.959702]},"n3561":{"id":"n3561","loc":[-85.621573,41.958457]},"n3562":{"id":"n3562","loc":[-85.619631,41.9573]},"n3563":{"id":"n3563","loc":[-85.62095,41.956311]},"n3564":{"id":"n3564","loc":[-85.619694,41.957408]},"n3565":{"id":"n3565","loc":[-85.621079,41.957751]},"n3566":{"id":"n3566","loc":[-85.622426,41.961142]},"n3567":{"id":"n3567","loc":[-85.623251,41.960484]},"n3568":{"id":"n3568","loc":[-85.619084,41.956291]},"n3569":{"id":"n3569","loc":[-85.622227,41.959303]},"n357":{"id":"n357","loc":[-85.632888,41.94315]},"n3570":{"id":"n3570","loc":[-85.620976,41.959104]},"n3571":{"id":"n3571","loc":[-85.621208,41.95653]},"n3572":{"id":"n3572","loc":[-85.623531,41.95951]},"n3573":{"id":"n3573","loc":[-85.623556,41.957935]},"n3574":{"id":"n3574","loc":[-85.623037,41.95746]},"n3575":{"id":"n3575","loc":[-85.621175,41.956427]},"n3576":{"id":"n3576","loc":[-85.622651,41.960109]},"n3577":{"id":"n3577","loc":[-85.621803,41.960747]},"n3578":{"id":"n3578","loc":[-85.620791,41.961874]},"n3579":{"id":"n3579","loc":[-85.625295,41.956786]},"n358":{"id":"n358","loc":[-85.633232,41.943547]},"n3580":{"id":"n3580","loc":[-85.619662,41.956894]},"n3581":{"id":"n3581","loc":[-85.622442,41.958708]},"n3582":{"id":"n3582","loc":[-85.621744,41.955864]},"n3583":{"id":"n3583","loc":[-85.621336,41.959212]},"n3584":{"id":"n3584","loc":[-85.622801,41.957304]},"n3585":{"id":"n3585","loc":[-85.619973,41.957433]},"n3586":{"id":"n3586","loc":[-85.619556,41.955717]},"n3587":{"id":"n3587","loc":[-85.622978,41.958601]},"n3588":{"id":"n3588","loc":[-85.625396,41.956264]},"n3589":{"id":"n3589","loc":[-85.623525,41.958034]},"n359":{"id":"n359","loc":[-85.633302,41.94351]},"n3590":{"id":"n3590","loc":[-85.623299,41.959631]},"n3591":{"id":"n3591","loc":[-85.622678,41.959873]},"n3592":{"id":"n3592","loc":[-85.625553,41.956179]},"n3593":{"id":"n3593","loc":[-85.623557,41.959231]},"n3594":{"id":"n3594","loc":[-85.622843,41.957373]},"n3595":{"id":"n3595","loc":[-85.619378,41.955677]},"n3596":{"id":"n3596","loc":[-85.620092,41.955425]},"n3597":{"id":"n3597","loc":[-85.622666,41.96044]},"n3598":{"id":"n3598","loc":[-85.621996,41.960256]},"n3599":{"id":"n3599","loc":[-85.623273,41.959997]},"n36":{"id":"n36","loc":[-85.637894,41.945551]},"n360":{"id":"n360","loc":[-85.633442,41.943794],"tags":{"highway":"crossing"}},"n3600":{"id":"n3600","loc":[-85.62477,41.95689]},"n3601":{"id":"n3601","loc":[-85.621641,41.955015]},"n3602":{"id":"n3602","loc":[-85.622495,41.960392]},"n3603":{"id":"n3603","loc":[-85.61918,41.955565]},"n3604":{"id":"n3604","loc":[-85.620017,41.955505]},"n3605":{"id":"n3605","loc":[-85.621739,41.956315]},"n3606":{"id":"n3606","loc":[-85.622957,41.959837]},"n3607":{"id":"n3607","loc":[-85.620912,41.960919]},"n3608":{"id":"n3608","loc":[-85.625231,41.956235]},"n3609":{"id":"n3609","loc":[-85.620976,41.961868]},"n361":{"id":"n361","loc":[-85.633381,41.94383]},"n3610":{"id":"n3610","loc":[-85.620956,41.958908]},"n3611":{"id":"n3611","loc":[-85.619035,41.956139]},"n3612":{"id":"n3612","loc":[-85.623643,41.958669]},"n3613":{"id":"n3613","loc":[-85.61949,41.956539]},"n3614":{"id":"n3614","loc":[-85.621927,41.958242]},"n3615":{"id":"n3615","loc":[-85.620826,41.955721]},"n3616":{"id":"n3616","loc":[-85.621202,41.961321]},"n3617":{"id":"n3617","loc":[-85.624877,41.95594]},"n3618":{"id":"n3618","loc":[-85.62065,41.958369]},"n3619":{"id":"n3619","loc":[-85.621524,41.956279]},"n362":{"id":"n362","loc":[-85.632977,41.944053]},"n3620":{"id":"n3620","loc":[-85.624662,41.955932]},"n3621":{"id":"n3621","loc":[-85.623048,41.958509]},"n3622":{"id":"n3622","loc":[-85.62111,41.95754]},"n3623":{"id":"n3623","loc":[-85.621508,41.954847]},"n3624":{"id":"n3624","loc":[-85.620655,41.958601]},"n3625":{"id":"n3625","loc":[-85.62154,41.954971]},"n3626":{"id":"n3626","loc":[-85.621691,41.955521]},"n3627":{"id":"n3627","loc":[-85.62154,41.954739]},"n3628":{"id":"n3628","loc":[-85.621996,41.959913]},"n3629":{"id":"n3629","loc":[-85.622286,41.960699]},"n363":{"id":"n363","loc":[-85.632915,41.943981],"tags":{"crossing":"zebra","highway":"crossing"}},"n3630":{"id":"n3630","loc":[-85.622844,41.9572]},"n3631":{"id":"n3631","loc":[-85.620252,41.955446]},"n3632":{"id":"n3632","loc":[-85.623434,41.957528]},"n3633":{"id":"n3633","loc":[-85.623429,41.956858]},"n3634":{"id":"n3634","loc":[-85.622957,41.957137]},"n3635":{"id":"n3635","loc":[-85.622554,41.959027]},"n3636":{"id":"n3636","loc":[-85.623289,41.958314]},"n3637":{"id":"n3637","loc":[-85.622977,41.960855]},"n3638":{"id":"n3638","loc":[-85.624008,41.956953]},"n3639":{"id":"n3639","loc":[-85.621278,41.960855]},"n364":{"id":"n364","loc":[-85.632724,41.943969],"tags":{"crossing":"zebra","highway":"crossing"}},"n3640":{"id":"n3640","loc":[-85.623128,41.956993]},"n3641":{"id":"n3641","loc":[-85.622452,41.959183]},"n3642":{"id":"n3642","loc":[-85.621095,41.961082]},"n3643":{"id":"n3643","loc":[-85.622011,41.960544]},"n3644":{"id":"n3644","loc":[-85.621637,41.955385]},"n3645":{"id":"n3645","loc":[-85.620999,41.959271]},"n3646":{"id":"n3646","loc":[-85.620044,41.956347]},"n3647":{"id":"n3647","loc":[-85.621936,41.959682]},"n3648":{"id":"n3648","loc":[-85.623761,41.95685]},"n3649":{"id":"n3649","loc":[-85.621239,41.959343]},"n365":{"id":"n365","loc":[-85.632621,41.944034]},"n3650":{"id":"n3650","loc":[-85.621073,41.956012]},"n3651":{"id":"n3651","loc":[-85.621271,41.956184]},"n3652":{"id":"n3652","loc":[-85.623444,41.95778]},"n3653":{"id":"n3653","loc":[-85.62125,41.96186]},"n3654":{"id":"n3654","loc":[-85.62169,41.961059]},"n3655":{"id":"n3655","loc":[-85.620012,41.955637]},"n3656":{"id":"n3656","loc":[-85.621058,41.9573]},"n3657":{"id":"n3657","loc":[-85.621138,41.957663]},"n3658":{"id":"n3658","loc":[-85.620773,41.957895]},"n3659":{"id":"n3659","loc":[-85.62007,41.957157]},"n366":{"id":"n366","loc":[-85.632684,41.944109],"tags":{"crossing":"zebra","highway":"crossing"}},"n3660":{"id":"n3660","loc":[-85.624534,41.955844]},"n3661":{"id":"n3661","loc":[-85.621932,41.960807]},"n3662":{"id":"n3662","loc":[-85.623358,41.958138]},"n3663":{"id":"n3663","loc":[-85.620456,41.955514]},"n3664":{"id":"n3664","loc":[-85.623504,41.957607]},"n3665":{"id":"n3665","loc":[-85.621444,41.960751]},"n3666":{"id":"n3666","loc":[-85.623492,41.960213]},"n3667":{"id":"n3667","loc":[-85.621669,41.954655]},"n3668":{"id":"n3668","loc":[-85.623106,41.958685]},"n3669":{"id":"n3669","loc":[-85.620922,41.957867]},"n367":{"id":"n367","loc":[-85.632738,41.944172]},"n3670":{"id":"n3670","loc":[-85.620092,41.957296]},"n3671":{"id":"n3671","loc":[-85.621669,41.955222]},"n3672":{"id":"n3672","loc":[-85.621614,41.960967]},"n3673":{"id":"n3673","loc":[-85.621691,41.955732]},"n3674":{"id":"n3674","loc":[-85.619207,41.956419]},"n3675":{"id":"n3675","loc":[-85.621116,41.956603]},"n3676":{"id":"n3676","loc":[-85.623311,41.956929]},"n3677":{"id":"n3677","loc":[-85.625671,41.956499]},"n3678":{"id":"n3678","loc":[-85.623525,41.956738]},"n3679":{"id":"n3679","loc":[-85.625381,41.956634]},"n368":{"id":"n368","loc":[-85.63287,41.944135],"tags":{"crossing":"zebra","highway":"crossing"}},"n3680":{"id":"n3680","loc":[-85.620096,41.95677]},"n3681":{"id":"n3681","loc":[-85.623803,41.958745]},"n3682":{"id":"n3682","loc":[-85.623498,41.958457]},"n3683":{"id":"n3683","loc":[-85.624223,41.957009]},"n3684":{"id":"n3684","loc":[-85.620026,41.956946]},"n3685":{"id":"n3685","loc":[-85.623005,41.960124]},"n3686":{"id":"n3686","loc":[-85.619073,41.955832]},"n3687":{"id":"n3687","loc":[-85.621744,41.95501]},"n3688":{"id":"n3688","loc":[-85.620804,41.958781]},"n3689":{"id":"n3689","loc":[-85.619844,41.957448]},"n369":{"id":"n369","loc":[-85.63298,41.944076]},"n3690":{"id":"n3690","loc":[-85.623713,41.958872]},"n3691":{"id":"n3691","loc":[-85.622329,41.960507]},"n3692":{"id":"n3692","loc":[-85.620804,41.956244]},"n3693":{"id":"n3693","loc":[-85.621818,41.955968]},"n3694":{"id":"n3694","loc":[-85.621405,41.958697]},"n3695":{"id":"n3695","loc":[-85.620998,41.960996]},"n3696":{"id":"n3696","loc":[-85.621621,41.960444]},"n3697":{"id":"n3697","loc":[-85.620941,41.961637]},"n3698":{"id":"n3698","loc":[-85.622195,41.958333]},"n3699":{"id":"n3699","loc":[-85.621668,41.961529]},"n37":{"id":"n37","loc":[-85.637611,41.945383]},"n370":{"id":"n370","loc":[-85.633191,41.944471]},"n3700":{"id":"n3700","loc":[-85.621015,41.957049]},"n3701":{"id":"n3701","loc":[-85.619368,41.955521]},"n3702":{"id":"n3702","loc":[-85.651578,41.942534]},"n3703":{"id":"n3703","loc":[-85.651541,41.943847]},"n3704":{"id":"n3704","loc":[-85.651365,41.944817]},"n3705":{"id":"n3705","loc":[-85.651076,41.945985]},"n3706":{"id":"n3706","loc":[-85.650626,41.947213]},"n3707":{"id":"n3707","loc":[-85.649669,41.949161]},"n3708":{"id":"n3708","loc":[-85.641802,41.961801]},"n3709":{"id":"n3709","loc":[-85.623333,41.961987]},"n371":{"id":"n371","loc":[-85.633132,41.94372]},"n3710":{"id":"n3710","loc":[-85.620621,41.965658]},"n3711":{"id":"n3711","loc":[-85.605673,41.965764]},"n3712":{"id":"n3712","loc":[-85.605664,41.962094]},"n3713":{"id":"n3713","loc":[-85.583774,41.962178]},"n3714":{"id":"n3714","loc":[-85.583774,41.961789]},"n3715":{"id":"n3715","loc":[-85.581303,41.961783]},"n3716":{"id":"n3716","loc":[-85.581245,41.958394]},"n3717":{"id":"n3717","loc":[-85.585299,41.955483]},"n3718":{"id":"n3718","loc":[-85.585588,41.955331]},"n3719":{"id":"n3719","loc":[-85.586053,41.955163]},"n372":{"id":"n372","loc":[-85.633011,41.943788]},"n3720":{"id":"n3720","loc":[-85.58632,41.955076]},"n3721":{"id":"n3721","loc":[-85.586478,41.955025]},"n3722":{"id":"n3722","loc":[-85.58692,41.954947]},"n3723":{"id":"n3723","loc":[-85.587345,41.954913]},"n3724":{"id":"n3724","loc":[-85.605592,41.954766]},"n3725":{"id":"n3725","loc":[-85.605303,41.936236]},"n3726":{"id":"n3726","loc":[-85.606941,41.936117]},"n3727":{"id":"n3727","loc":[-85.60876,41.935856]},"n3728":{"id":"n3728","loc":[-85.610092,41.935451]},"n3729":{"id":"n3729","loc":[-85.610681,41.935247]},"n373":{"id":"n373","loc":[-85.632854,41.943632]},"n3730":{"id":"n3730","loc":[-85.611446,41.934955]},"n3731":{"id":"n3731","loc":[-85.612057,41.934696]},"n3732":{"id":"n3732","loc":[-85.613256,41.934084]},"n3733":{"id":"n3733","loc":[-85.613948,41.933682]},"n3734":{"id":"n3734","loc":[-85.614638,41.933212]},"n3735":{"id":"n3735","loc":[-85.619801,41.929305]},"n3736":{"id":"n3736","loc":[-85.619768,41.925548]},"n3737":{"id":"n3737","loc":[-85.625761,41.925597]},"n3738":{"id":"n3738","loc":[-85.6263,41.927323]},"n3739":{"id":"n3739","loc":[-85.633708,41.927402]},"n374":{"id":"n374","loc":[-85.632974,41.943565]},"n3740":{"id":"n3740","loc":[-85.633927,41.929109]},"n3741":{"id":"n3741","loc":[-85.639213,41.929088]},"n3742":{"id":"n3742","loc":[-85.639204,41.925488]},"n3743":{"id":"n3743","loc":[-85.651425,41.925406]},"n3744":{"id":"n3744","loc":[-85.643386,41.941933]},"n3745":{"id":"n3745","loc":[-85.642776,41.941161]},"n3746":{"id":"n3746","loc":[-85.637277,41.948812]},"n3747":{"id":"n3747","loc":[-85.637366,41.94897]},"n3748":{"id":"n3748","loc":[-85.637329,41.94889]},"n3749":{"id":"n3749","loc":[-85.629649,41.952596]},"n375":{"id":"n375","loc":[-85.632741,41.943351]},"n3750":{"id":"n3750","loc":[-85.630291,41.954684]},"n3751":{"id":"n3751","loc":[-85.630284,41.953713]},"n3752":{"id":"n3752","loc":[-85.630269,41.952463]},"n3753":{"id":"n3753","loc":[-85.633933,41.949896]},"n3754":{"id":"n3754","loc":[-85.629339,41.941467]},"n3755":{"id":"n3755","loc":[-85.629857,41.94316]},"n3756":{"id":"n3756","loc":[-85.629987,41.944025]},"n3757":{"id":"n3757","loc":[-85.628538,41.948604]},"n3758":{"id":"n3758","loc":[-85.627415,41.957442]},"n3759":{"id":"n3759","loc":[-85.627019,41.957369]},"n376":{"id":"n376","loc":[-85.63251,41.943481]},"n3760":{"id":"n3760","loc":[-85.62167,41.952179]},"n3761":{"id":"n3761","loc":[-85.62167,41.952138]},"n3762":{"id":"n3762","loc":[-85.621562,41.952139]},"n3763":{"id":"n3763","loc":[-85.621562,41.952058]},"n3764":{"id":"n3764","loc":[-85.621476,41.952043]},"n3765":{"id":"n3765","loc":[-85.621477,41.952132]},"n3766":{"id":"n3766","loc":[-85.621386,41.952132]},"n3767":{"id":"n3767","loc":[-85.621387,41.95214]},"n3768":{"id":"n3768","loc":[-85.621262,41.95214]},"n3769":{"id":"n3769","loc":[-85.621261,41.952038]},"n377":{"id":"n377","loc":[-85.632706,41.943715]},"n3770":{"id":"n3770","loc":[-85.621389,41.952038]},"n3771":{"id":"n3771","loc":[-85.621389,41.952043]},"n3772":{"id":"n3772","loc":[-85.620898,41.952024]},"n3773":{"id":"n3773","loc":[-85.620898,41.952085]},"n3774":{"id":"n3774","loc":[-85.620774,41.952084]},"n3775":{"id":"n3775","loc":[-85.620774,41.952023]},"n3776":{"id":"n3776","loc":[-85.620749,41.952036]},"n3777":{"id":"n3777","loc":[-85.620723,41.952097]},"n3778":{"id":"n3778","loc":[-85.626158,41.958996]},"n3779":{"id":"n3779","loc":[-85.626319,41.958686]},"n378":{"id":"n378","loc":[-85.638683,41.943295]},"n3780":{"id":"n3780","loc":[-85.626119,41.958629]},"n3781":{"id":"n3781","loc":[-85.626064,41.958733]},"n3782":{"id":"n3782","loc":[-85.626155,41.958759]},"n3783":{"id":"n3783","loc":[-85.626048,41.958965]},"n3784":{"id":"n3784","loc":[-85.620648,41.952079]},"n3785":{"id":"n3785","loc":[-85.63826,41.961213]},"n3786":{"id":"n3786","loc":[-85.638003,41.961614]},"n3787":{"id":"n3787","loc":[-85.638817,41.961902]},"n3788":{"id":"n3788","loc":[-85.639073,41.961501]},"n3789":{"id":"n3789","loc":[-85.620674,41.952018]},"n379":{"id":"n379","loc":[-85.638684,41.94323]},"n3790":{"id":"n3790","loc":[-85.62082,41.952106]},"n3791":{"id":"n3791","loc":[-85.620819,41.952143]},"n3792":{"id":"n3792","loc":[-85.620778,41.952143]},"n3793":{"id":"n3793","loc":[-85.620778,41.952106]},"n3794":{"id":"n3794","loc":[-85.620563,41.952276]},"n3795":{"id":"n3795","loc":[-85.620543,41.95238]},"n3796":{"id":"n3796","loc":[-85.620422,41.952367]},"n3797":{"id":"n3797","loc":[-85.620441,41.952263]},"n3798":{"id":"n3798","loc":[-85.620561,41.952266]},"n3799":{"id":"n3799","loc":[-85.620444,41.952254]},"n38":{"id":"n38","loc":[-85.63879,41.943295]},"n380":{"id":"n380","loc":[-85.638627,41.94322]},"n3800":{"id":"n3800","loc":[-85.620773,41.955585]},"n3801":{"id":"n3801","loc":[-85.621265,41.955989]},"n3802":{"id":"n3802","loc":[-85.620692,41.954969]},"n3803":{"id":"n3803","loc":[-85.620691,41.955367]},"n3804":{"id":"n3804","loc":[-85.620458,41.952178]},"n3805":{"id":"n3805","loc":[-85.620575,41.95219]},"n3806":{"id":"n3806","loc":[-85.617609,41.952712]},"n3807":{"id":"n3807","loc":[-85.617533,41.952801],"tags":{"entrance":"yes"}},"n3808":{"id":"n3808","loc":[-85.616816,41.952911]},"n3809":{"id":"n3809","loc":[-85.616797,41.952901]},"n381":{"id":"n381","loc":[-85.638624,41.943294]},"n3810":{"id":"n3810","loc":[-85.616343,41.952694]},"n3811":{"id":"n3811","loc":[-85.616336,41.952729]},"n3812":{"id":"n3812","loc":[-85.616343,41.952772]},"n3813":{"id":"n3813","loc":[-85.628479,41.948649]},"n3814":{"id":"n3814","loc":[-85.628413,41.948679]},"n3815":{"id":"n3815","loc":[-85.628336,41.948694]},"n3816":{"id":"n3816","loc":[-85.62826,41.948694]},"n3817":{"id":"n3817","loc":[-85.628185,41.948679]},"n3818":{"id":"n3818","loc":[-85.628103,41.948649]},"n3819":{"id":"n3819","loc":[-85.627482,41.948395]},"n382":{"id":"n382","loc":[-85.638437,41.943291]},"n3820":{"id":"n3820","loc":[-85.619957,41.951168]},"n3821":{"id":"n3821","loc":[-85.619955,41.952077]},"n3822":{"id":"n3822","loc":[-85.619843,41.952666]},"n3823":{"id":"n3823","loc":[-85.619513,41.95324]},"n3824":{"id":"n3824","loc":[-85.619163,41.953668]},"n3825":{"id":"n3825","loc":[-85.618813,41.953947]},"n3826":{"id":"n3826","loc":[-85.618265,41.954252]},"n3827":{"id":"n3827","loc":[-85.617691,41.954458]},"n3828":{"id":"n3828","loc":[-85.616978,41.95459]},"n3829":{"id":"n3829","loc":[-85.615408,41.954628]},"n383":{"id":"n383","loc":[-85.63844,41.943209]},"n3830":{"id":"n3830","loc":[-85.615374,41.951076]},"n3831":{"id":"n3831","loc":[-85.61932,41.947564]},"n3832":{"id":"n3832","loc":[-85.610553,41.94755]},"n3833":{"id":"n3833","loc":[-85.610572,41.951065]},"n3834":{"id":"n3834","loc":[-85.617548,41.94757]},"n3835":{"id":"n3835","loc":[-85.619842,41.947939]},"n3836":{"id":"n3836","loc":[-85.619874,41.950905]},"n3837":{"id":"n3837","loc":[-85.619695,41.950911]},"n3838":{"id":"n3838","loc":[-85.617591,41.951078]},"n3839":{"id":"n3839","loc":[-85.619551,41.951065]},"n384":{"id":"n384","loc":[-85.632616,41.944021]},"n3840":{"id":"n3840","loc":[-85.626813,41.947337]},"n3841":{"id":"n3841","loc":[-85.616371,41.952814]},"n3842":{"id":"n3842","loc":[-85.617205,41.951308]},"n3843":{"id":"n3843","loc":[-85.616795,41.950953]},"n3844":{"id":"n3844","loc":[-85.617441,41.950889]},"n3845":{"id":"n3845","loc":[-85.619155,41.949377]},"n3846":{"id":"n3846","loc":[-85.618556,41.949377]},"n3847":{"id":"n3847","loc":[-85.618557,41.948372]},"n3848":{"id":"n3848","loc":[-85.619156,41.948372]},"n3849":{"id":"n3849","loc":[-85.61927,41.949796]},"n385":{"id":"n385","loc":[-85.632319,41.944172]},"n3850":{"id":"n3850","loc":[-85.61926,41.948344]},"n3851":{"id":"n3851","loc":[-85.619219,41.948264]},"n3852":{"id":"n3852","loc":[-85.619147,41.948196]},"n3853":{"id":"n3853","loc":[-85.619049,41.948144]},"n3854":{"id":"n3854","loc":[-85.618942,41.948116]},"n3855":{"id":"n3855","loc":[-85.618822,41.948109]},"n3856":{"id":"n3856","loc":[-85.618699,41.94813]},"n3857":{"id":"n3857","loc":[-85.618937,41.951943]},"n3858":{"id":"n3858","loc":[-85.616755,41.952231]},"n3859":{"id":"n3859","loc":[-85.616799,41.95472]},"n386":{"id":"n386","loc":[-85.63221,41.944066]},"n3860":{"id":"n3860","loc":[-85.616458,41.954735]},"n3861":{"id":"n3861","loc":[-85.61763,41.951515]},"n3862":{"id":"n3862","loc":[-85.617735,41.951572]},"n3863":{"id":"n3863","loc":[-85.61929,41.951573]},"n3864":{"id":"n3864","loc":[-85.617134,41.951348]},"n3865":{"id":"n3865","loc":[-85.616598,41.95192]},"n3866":{"id":"n3866","loc":[-85.616572,41.951992]},"n3867":{"id":"n3867","loc":[-85.616583,41.952076]},"n3868":{"id":"n3868","loc":[-85.616636,41.952145]},"n3869":{"id":"n3869","loc":[-85.616916,41.952279]},"n387":{"id":"n387","loc":[-85.632524,41.943912]},"n3870":{"id":"n3870","loc":[-85.617088,41.952254]},"n3871":{"id":"n3871","loc":[-85.61892,41.951467]},"n3872":{"id":"n3872","loc":[-85.618035,41.951473]},"n3873":{"id":"n3873","loc":[-85.618036,41.951572]},"n3874":{"id":"n3874","loc":[-85.61892,41.951573]},"n3875":{"id":"n3875","loc":[-85.618919,41.951957]},"n3876":{"id":"n3876","loc":[-85.619457,41.952237]},"n3877":{"id":"n3877","loc":[-85.618178,41.953618]},"n3878":{"id":"n3878","loc":[-85.617658,41.953366]},"n3879":{"id":"n3879","loc":[-85.617987,41.953024]},"n388":{"id":"n388","loc":[-85.632268,41.943621]},"n3880":{"id":"n3880","loc":[-85.618429,41.953248]},"n3881":{"id":"n3881","loc":[-85.618554,41.953119]},"n3882":{"id":"n3882","loc":[-85.618077,41.952868]},"n3883":{"id":"n3883","loc":[-85.618039,41.952886]},"n3884":{"id":"n3884","loc":[-85.619375,41.952169]},"n3885":{"id":"n3885","loc":[-85.618137,41.953538]},"n3886":{"id":"n3886","loc":[-85.61799,41.953555]},"n3887":{"id":"n3887","loc":[-85.617729,41.953423]},"n3888":{"id":"n3888","loc":[-85.618101,41.953029]},"n3889":{"id":"n3889","loc":[-85.618516,41.953119]},"n389":{"id":"n389","loc":[-85.631951,41.943773]},"n3890":{"id":"n3890","loc":[-85.619132,41.952042]},"n3891":{"id":"n3891","loc":[-85.618235,41.952981]},"n3892":{"id":"n3892","loc":[-85.618485,41.952425]},"n3893":{"id":"n3893","loc":[-85.618676,41.952519]},"n3894":{"id":"n3894","loc":[-85.618942,41.952648]},"n3895":{"id":"n3895","loc":[-85.618287,41.953122]},"n3896":{"id":"n3896","loc":[-85.617914,41.953516]},"n3897":{"id":"n3897","loc":[-85.617836,41.953573]},"n3898":{"id":"n3898","loc":[-85.616477,41.95289]},"n3899":{"id":"n3899","loc":[-85.618441,41.953201]},"n39":{"id":"n39","loc":[-85.619931,41.951013]},"n390":{"id":"n390","loc":[-85.631981,41.943654]},"n3900":{"id":"n3900","loc":[-85.617537,41.953335]},"n3901":{"id":"n3901","loc":[-85.617221,41.953166]},"n3902":{"id":"n3902","loc":[-85.617253,41.953135]},"n3903":{"id":"n3903","loc":[-85.617211,41.953114]},"n3904":{"id":"n3904","loc":[-85.617197,41.95313]},"n3905":{"id":"n3905","loc":[-85.616802,41.952925]},"n3906":{"id":"n3906","loc":[-85.616771,41.952928]},"n3907":{"id":"n3907","loc":[-85.616493,41.952785]},"n3908":{"id":"n3908","loc":[-85.616823,41.952426]},"n3909":{"id":"n3909","loc":[-85.617191,41.952616]},"n391":{"id":"n391","loc":[-85.631886,41.943699]},"n3910":{"id":"n3910","loc":[-85.61724,41.952559]},"n3911":{"id":"n3911","loc":[-85.61721,41.952542]},"n3912":{"id":"n3912","loc":[-85.617395,41.952351]},"n3913":{"id":"n3913","loc":[-85.617426,41.952368]},"n3914":{"id":"n3914","loc":[-85.617483,41.952309]},"n3915":{"id":"n3915","loc":[-85.617332,41.952229]},"n3916":{"id":"n3916","loc":[-85.617451,41.952102]},"n3917":{"id":"n3917","loc":[-85.617477,41.952115]},"n3918":{"id":"n3918","loc":[-85.617658,41.951923]},"n3919":{"id":"n3919","loc":[-85.617634,41.95191]},"n392":{"id":"n392","loc":[-85.631807,41.943606]},"n3920":{"id":"n3920","loc":[-85.617747,41.951786]},"n3921":{"id":"n3921","loc":[-85.618268,41.952056]},"n3922":{"id":"n3922","loc":[-85.618211,41.952122]},"n3923":{"id":"n3923","loc":[-85.618386,41.95222]},"n3924":{"id":"n3924","loc":[-85.618098,41.952527]},"n3925":{"id":"n3925","loc":[-85.617916,41.95243]},"n3926":{"id":"n3926","loc":[-85.617854,41.952498]},"n3927":{"id":"n3927","loc":[-85.617769,41.952453]},"n3928":{"id":"n3928","loc":[-85.617476,41.952773]},"n3929":{"id":"n3929","loc":[-85.617876,41.952973]},"n393":{"id":"n393","loc":[-85.631902,41.943561]},"n3930":{"id":"n3930","loc":[-85.617174,41.953638]},"n3931":{"id":"n3931","loc":[-85.618016,41.953578]},"n3932":{"id":"n3932","loc":[-85.618107,41.953628]},"n3933":{"id":"n3933","loc":[-85.618067,41.954268]},"n3934":{"id":"n3934","loc":[-85.617864,41.954263]},"n3935":{"id":"n3935","loc":[-85.61762,41.954205]},"n3936":{"id":"n3936","loc":[-85.617437,41.954103]},"n3937":{"id":"n3937","loc":[-85.617294,41.953978]},"n3938":{"id":"n3938","loc":[-85.617217,41.95384]},"n3939":{"id":"n3939","loc":[-85.616814,41.954327]},"n394":{"id":"n394","loc":[-85.63236,41.943543]},"n3940":{"id":"n3940","loc":[-85.616778,41.95381]},"n3941":{"id":"n3941","loc":[-85.616585,41.953707]},"n3942":{"id":"n3942","loc":[-85.616458,41.954318]},"n3943":{"id":"n3943","loc":[-85.616643,41.954345]},"n3944":{"id":"n3944","loc":[-85.618133,41.951412]},"n3945":{"id":"n3945","loc":[-85.618326,41.951411]},"n3946":{"id":"n3946","loc":[-85.618503,41.95141]},"n3947":{"id":"n3947","loc":[-85.618681,41.951409]},"n3948":{"id":"n3948","loc":[-85.618868,41.951408]},"n3949":{"id":"n3949","loc":[-85.617047,41.95136]},"n395":{"id":"n395","loc":[-85.633839,41.944082]},"n3950":{"id":"n3950","loc":[-85.616494,41.951959]},"n3951":{"id":"n3951","loc":[-85.616497,41.952072]},"n3952":{"id":"n3952","loc":[-85.616565,41.952165]},"n3953":{"id":"n3953","loc":[-85.616663,41.952218]},"n3954":{"id":"n3954","loc":[-85.616733,41.952255]},"n3955":{"id":"n3955","loc":[-85.617238,41.952512],"tags":{"entrance":"yes"}},"n3956":{"id":"n3956","loc":[-85.617043,41.952406]},"n3957":{"id":"n3957","loc":[-85.617691,41.951711]},"n3958":{"id":"n3958","loc":[-85.617773,41.951679]},"n3959":{"id":"n3959","loc":[-85.619085,41.951681]},"n396":{"id":"n396","loc":[-85.63376,41.944097]},"n3960":{"id":"n3960","loc":[-85.617943,41.952895]},"n3961":{"id":"n3961","loc":[-85.618039,41.952938]},"n3962":{"id":"n3962","loc":[-85.61763,41.95336]},"n3963":{"id":"n3963","loc":[-85.617554,41.95344]},"n3964":{"id":"n3964","loc":[-85.617381,41.952366],"tags":{"entrance":"yes"}},"n3965":{"id":"n3965","loc":[-85.617184,41.952254]},"n3966":{"id":"n3966","loc":[-85.617208,41.952496]},"n3967":{"id":"n3967","loc":[-85.617124,41.952581],"tags":{"entrance":"yes"}},"n3968":{"id":"n3968","loc":[-85.618094,41.952735]},"n3969":{"id":"n3969","loc":[-85.617702,41.952525],"tags":{"entrance":"yes"}},"n397":{"id":"n397","loc":[-85.63361,41.943957]},"n3970":{"id":"n3970","loc":[-85.617554,41.952686],"tags":{"entrance":"yes"}},"n3971":{"id":"n3971","loc":[-85.617959,41.952878]},"n3972":{"id":"n3972","loc":[-85.616367,41.952655]},"n3973":{"id":"n3973","loc":[-85.616416,41.952851]},"n3974":{"id":"n3974","loc":[-85.619777,41.951075]},"n3975":{"id":"n3975","loc":[-85.618611,41.94817]},"n3976":{"id":"n3976","loc":[-85.618538,41.948229]},"n3977":{"id":"n3977","loc":[-85.617421,41.947559]},"n3978":{"id":"n3978","loc":[-85.617395,41.951039]},"n3979":{"id":"n3979","loc":[-85.618488,41.94829]},"n398":{"id":"n398","loc":[-85.633309,41.943886]},"n3980":{"id":"n3980","loc":[-85.610238,41.954774]},"n3981":{"id":"n3981","loc":[-85.617449,41.950756]},"n3982":{"id":"n3982","loc":[-85.617288,41.951286]},"n3983":{"id":"n3983","loc":[-85.61745,41.950197]},"n3984":{"id":"n3984","loc":[-85.617436,41.948908]},"n3985":{"id":"n3985","loc":[-85.615915,41.953804]},"n3986":{"id":"n3986","loc":[-85.615953,41.953968]},"n3987":{"id":"n3987","loc":[-85.616031,41.954085]},"n3988":{"id":"n3988","loc":[-85.616135,41.954181]},"n3989":{"id":"n3989","loc":[-85.616273,41.954263]},"n399":{"id":"n399","loc":[-85.633226,41.943931]},"n3990":{"id":"n3990","loc":[-85.618327,41.951083]},"n3991":{"id":"n3991","loc":[-85.618135,41.951084]},"n3992":{"id":"n3992","loc":[-85.618503,41.951082]},"n3993":{"id":"n3993","loc":[-85.618682,41.951081]},"n3994":{"id":"n3994","loc":[-85.618864,41.951082]},"n3995":{"id":"n3995","loc":[-85.616761,41.950101]},"n3996":{"id":"n3996","loc":[-85.617317,41.947558]},"n3997":{"id":"n3997","loc":[-85.617336,41.948883]},"n3998":{"id":"n3998","loc":[-85.616779,41.949295]},"n3999":{"id":"n3999","loc":[-85.616754,41.949349]},"n4":{"id":"n4","loc":[-85.622764,41.950892],"tags":{"highway":"stop"}},"n40":{"id":"n40","loc":[-85.619841,41.951037]},"n400":{"id":"n400","loc":[-85.63326,41.943966]},"n4000":{"id":"n4000","loc":[-85.616761,41.950865]},"n4001":{"id":"n4001","loc":[-85.616883,41.951041]},"n4002":{"id":"n4002","loc":[-85.617004,41.951142]},"n4003":{"id":"n4003","loc":[-85.617062,41.951248]},"n4004":{"id":"n4004","loc":[-85.616809,41.949273]},"n4005":{"id":"n4005","loc":[-85.616755,41.949489]},"n4006":{"id":"n4006","loc":[-85.616759,41.949971]},"n4007":{"id":"n4007","loc":[-85.616757,41.949702]},"n4008":{"id":"n4008","loc":[-85.618456,41.94836]},"n4009":{"id":"n4009","loc":[-85.618447,41.948428]},"n401":{"id":"n401","loc":[-85.63324,41.943976]},"n4010":{"id":"n4010","loc":[-85.618437,41.949322]},"n4011":{"id":"n4011","loc":[-85.618447,41.949418]},"n4012":{"id":"n4012","loc":[-85.618478,41.949491]},"n4013":{"id":"n4013","loc":[-85.618535,41.949559]},"n4014":{"id":"n4014","loc":[-85.618623,41.94962]},"n4015":{"id":"n4015","loc":[-85.618721,41.94966]},"n4016":{"id":"n4016","loc":[-85.618838,41.949674]},"n4017":{"id":"n4017","loc":[-85.618967,41.949667]},"n4018":{"id":"n4018","loc":[-85.619065,41.949632]},"n4019":{"id":"n4019","loc":[-85.61915,41.949578]},"n402":{"id":"n402","loc":[-85.63327,41.944006]},"n4020":{"id":"n4020","loc":[-85.619216,41.949507]},"n4021":{"id":"n4021","loc":[-85.61927,41.949399]},"n4022":{"id":"n4022","loc":[-85.619074,41.947639]},"n4023":{"id":"n4023","loc":[-85.619073,41.947793]},"n4024":{"id":"n4024","loc":[-85.618912,41.947793]},"n4025":{"id":"n4025","loc":[-85.618911,41.947947]},"n4026":{"id":"n4026","loc":[-85.618752,41.947947]},"n4027":{"id":"n4027","loc":[-85.618754,41.947637]},"n4028":{"id":"n4028","loc":[-85.617896,41.947599]},"n4029":{"id":"n4029","loc":[-85.617898,41.947811]},"n403":{"id":"n403","loc":[-85.633278,41.944002]},"n4030":{"id":"n4030","loc":[-85.617717,41.947812]},"n4031":{"id":"n4031","loc":[-85.617715,41.9476]},"n4032":{"id":"n4032","loc":[-85.619003,41.949828]},"n4033":{"id":"n4033","loc":[-85.619003,41.949882]},"n4034":{"id":"n4034","loc":[-85.618926,41.949882]},"n4035":{"id":"n4035","loc":[-85.618926,41.949828]},"n4036":{"id":"n4036","loc":[-85.618861,41.949809]},"n4037":{"id":"n4037","loc":[-85.618861,41.949898]},"n4038":{"id":"n4038","loc":[-85.618688,41.949898]},"n4039":{"id":"n4039","loc":[-85.618687,41.94981]},"n404":{"id":"n404","loc":[-85.63331,41.944036]},"n4040":{"id":"n4040","loc":[-85.618349,41.949473]},"n4041":{"id":"n4041","loc":[-85.618287,41.949473]},"n4042":{"id":"n4042","loc":[-85.618287,41.94942]},"n4043":{"id":"n4043","loc":[-85.618348,41.949419]},"n4044":{"id":"n4044","loc":[-85.62316,41.951604]},"n4045":{"id":"n4045","loc":[-85.623026,41.951605]},"n4046":{"id":"n4046","loc":[-85.623023,41.951466]},"n4047":{"id":"n4047","loc":[-85.623134,41.951465]},"n4048":{"id":"n4048","loc":[-85.623136,41.951539]},"n4049":{"id":"n4049","loc":[-85.623159,41.951539]},"n405":{"id":"n405","loc":[-85.633348,41.944015]},"n4050":{"id":"n4050","loc":[-85.623025,41.95155]},"n4051":{"id":"n4051","loc":[-85.622955,41.951551]},"n4052":{"id":"n4052","loc":[-85.622953,41.951507]},"n4053":{"id":"n4053","loc":[-85.623024,41.951506]},"n4054":{"id":"n4054","loc":[-85.623318,41.951242]},"n4055":{"id":"n4055","loc":[-85.623175,41.951241]},"n4056":{"id":"n4056","loc":[-85.623176,41.951153]},"n4057":{"id":"n4057","loc":[-85.623319,41.951154]},"n4058":{"id":"n4058","loc":[-85.623077,41.951191]},"n4059":{"id":"n4059","loc":[-85.622973,41.951191]},"n406":{"id":"n406","loc":[-85.63338,41.944048]},"n4060":{"id":"n4060","loc":[-85.622972,41.951349]},"n4061":{"id":"n4061","loc":[-85.623059,41.95135]},"n4062":{"id":"n4062","loc":[-85.62306,41.951301]},"n4063":{"id":"n4063","loc":[-85.623077,41.951301]},"n4064":{"id":"n4064","loc":[-85.623117,41.951405]},"n4065":{"id":"n4065","loc":[-85.62312,41.951087]},"n4066":{"id":"n4066","loc":[-85.623118,41.951274]},"n4067":{"id":"n4067","loc":[-85.62328,41.951275]},"n4068":{"id":"n4068","loc":[-85.62328,41.951242]},"n4069":{"id":"n4069","loc":[-85.623179,41.951392]},"n407":{"id":"n407","loc":[-85.633431,41.94402]},"n4070":{"id":"n4070","loc":[-85.623141,41.951392]},"n4071":{"id":"n4071","loc":[-85.623142,41.95136]},"n4072":{"id":"n4072","loc":[-85.623179,41.951361]},"n4073":{"id":"n4073","loc":[-85.622565,41.951639]},"n4074":{"id":"n4074","loc":[-85.622565,41.951741]},"n4075":{"id":"n4075","loc":[-85.622463,41.95174]},"n4076":{"id":"n4076","loc":[-85.622463,41.95173]},"n4077":{"id":"n4077","loc":[-85.622442,41.95173]},"n4078":{"id":"n4078","loc":[-85.622442,41.951742]},"n4079":{"id":"n4079","loc":[-85.622361,41.951742]},"n408":{"id":"n408","loc":[-85.633425,41.944014]},"n4080":{"id":"n4080","loc":[-85.622362,41.951667]},"n4081":{"id":"n4081","loc":[-85.622441,41.951667]},"n4082":{"id":"n4082","loc":[-85.622441,41.951688]},"n4083":{"id":"n4083","loc":[-85.622461,41.951688]},"n4084":{"id":"n4084","loc":[-85.622461,41.951638]},"n4085":{"id":"n4085","loc":[-85.62255,41.951587]},"n4086":{"id":"n4086","loc":[-85.622449,41.95159]},"n4087":{"id":"n4087","loc":[-85.622441,41.951448]},"n4088":{"id":"n4088","loc":[-85.62253,41.951445]},"n4089":{"id":"n4089","loc":[-85.622532,41.951486]},"n409":{"id":"n409","loc":[-85.633457,41.943997]},"n4090":{"id":"n4090","loc":[-85.622555,41.951485]},"n4091":{"id":"n4091","loc":[-85.622558,41.951531]},"n4092":{"id":"n4092","loc":[-85.622547,41.951531]},"n4093":{"id":"n4093","loc":[-85.622451,41.95159]},"n4094":{"id":"n4094","loc":[-85.622452,41.95161]},"n4095":{"id":"n4095","loc":[-85.622106,41.951617]},"n4096":{"id":"n4096","loc":[-85.622133,41.951443]},"n4097":{"id":"n4097","loc":[-85.622552,41.951379]},"n4098":{"id":"n4098","loc":[-85.622443,41.95138]},"n4099":{"id":"n4099","loc":[-85.622441,41.951281]},"n41":{"id":"n41","loc":[-85.636233,41.942764]},"n410":{"id":"n410","loc":[-85.633429,41.943969]},"n4100":{"id":"n4100","loc":[-85.62255,41.95128]},"n4101":{"id":"n4101","loc":[-85.622541,41.951437]},"n4102":{"id":"n4102","loc":[-85.622441,41.951438]},"n4103":{"id":"n4103","loc":[-85.621561,41.951444]},"n4104":{"id":"n4104","loc":[-85.622302,41.951479]},"n4105":{"id":"n4105","loc":[-85.6223,41.95152]},"n4106":{"id":"n4106","loc":[-85.622169,41.951517]},"n4107":{"id":"n4107","loc":[-85.622171,41.951476]},"n4108":{"id":"n4108","loc":[-85.622543,41.951228]},"n4109":{"id":"n4109","loc":[-85.622433,41.951228]},"n411":{"id":"n411","loc":[-85.633442,41.943962]},"n4110":{"id":"n4110","loc":[-85.622433,41.951133]},"n4111":{"id":"n4111","loc":[-85.622543,41.951133]},"n4112":{"id":"n4112","loc":[-85.622356,41.951256]},"n4113":{"id":"n4113","loc":[-85.622293,41.951256]},"n4114":{"id":"n4114","loc":[-85.622292,41.9512]},"n4115":{"id":"n4115","loc":[-85.622313,41.9512]},"n4116":{"id":"n4116","loc":[-85.622312,41.951173]},"n4117":{"id":"n4117","loc":[-85.622364,41.951173]},"n4118":{"id":"n4118","loc":[-85.622365,41.951231]},"n4119":{"id":"n4119","loc":[-85.622355,41.951231]},"n412":{"id":"n412","loc":[-85.633411,41.943932]},"n4120":{"id":"n4120","loc":[-85.62197,41.951155]},"n4121":{"id":"n4121","loc":[-85.62197,41.951213]},"n4122":{"id":"n4122","loc":[-85.621848,41.951213]},"n4123":{"id":"n4123","loc":[-85.621848,41.951155]},"n4124":{"id":"n4124","loc":[-85.622193,41.951268]},"n4125":{"id":"n4125","loc":[-85.622194,41.951305]},"n4126":{"id":"n4126","loc":[-85.622121,41.951306]},"n4127":{"id":"n4127","loc":[-85.622121,41.951322]},"n4128":{"id":"n4128","loc":[-85.621984,41.951324]},"n4129":{"id":"n4129","loc":[-85.621983,41.951271]},"n413":{"id":"n413","loc":[-85.633421,41.943926]},"n4130":{"id":"n4130","loc":[-85.622171,41.9514]},"n4131":{"id":"n4131","loc":[-85.622148,41.951382]},"n4132":{"id":"n4132","loc":[-85.6221,41.951414]},"n4133":{"id":"n4133","loc":[-85.622122,41.951433]},"n4134":{"id":"n4134","loc":[-85.621782,41.951148]},"n4135":{"id":"n4135","loc":[-85.621783,41.951219]},"n4136":{"id":"n4136","loc":[-85.62164,41.951221]},"n4137":{"id":"n4137","loc":[-85.62164,41.951236]},"n4138":{"id":"n4138","loc":[-85.621556,41.951237]},"n4139":{"id":"n4139","loc":[-85.621555,41.95117]},"n414":{"id":"n414","loc":[-85.633376,41.94388]},"n4140":{"id":"n4140","loc":[-85.621644,41.951169]},"n4141":{"id":"n4141","loc":[-85.621643,41.951139]},"n4142":{"id":"n4142","loc":[-85.621719,41.951138]},"n4143":{"id":"n4143","loc":[-85.621719,41.951148]},"n4144":{"id":"n4144","loc":[-85.621409,41.951322]},"n4145":{"id":"n4145","loc":[-85.621338,41.951322]},"n4146":{"id":"n4146","loc":[-85.621336,41.95115]},"n4147":{"id":"n4147","loc":[-85.621521,41.951149]},"n4148":{"id":"n4148","loc":[-85.621522,41.951228]},"n4149":{"id":"n4149","loc":[-85.621408,41.951228]},"n415":{"id":"n415","loc":[-85.633348,41.943895]},"n4150":{"id":"n4150","loc":[-85.621284,41.951219]},"n4151":{"id":"n4151","loc":[-85.621153,41.951219]},"n4152":{"id":"n4152","loc":[-85.621152,41.951152]},"n4153":{"id":"n4153","loc":[-85.621283,41.951152]},"n4154":{"id":"n4154","loc":[-85.621159,41.951241]},"n4155":{"id":"n4155","loc":[-85.62116,41.951301]},"n4156":{"id":"n4156","loc":[-85.621088,41.951302]},"n4157":{"id":"n4157","loc":[-85.621088,41.951241]},"n4158":{"id":"n4158","loc":[-85.621049,41.951158]},"n4159":{"id":"n4159","loc":[-85.62105,41.951229]},"n416":{"id":"n416","loc":[-85.633341,41.943888]},"n4160":{"id":"n4160","loc":[-85.620976,41.951229]},"n4161":{"id":"n4161","loc":[-85.620977,41.951295]},"n4162":{"id":"n4162","loc":[-85.620887,41.951296]},"n4163":{"id":"n4163","loc":[-85.620886,41.951229]},"n4164":{"id":"n4164","loc":[-85.620862,41.951229]},"n4165":{"id":"n4165","loc":[-85.620861,41.951159]},"n4166":{"id":"n4166","loc":[-85.620626,41.951133]},"n4167":{"id":"n4167","loc":[-85.620626,41.951205]},"n4168":{"id":"n4168","loc":[-85.620412,41.951206]},"n4169":{"id":"n4169","loc":[-85.620411,41.951134]},"n417":{"id":"n417","loc":[-85.633321,41.943898]},"n4170":{"id":"n4170","loc":[-85.621775,41.951443]},"n4171":{"id":"n4171","loc":[-85.621777,41.951264]},"n4172":{"id":"n4172","loc":[-85.621565,41.951654]},"n4173":{"id":"n4173","loc":[-85.621331,41.951439]},"n4174":{"id":"n4174","loc":[-85.621031,41.951443]},"n4175":{"id":"n4175","loc":[-85.621836,41.951724]},"n4176":{"id":"n4176","loc":[-85.621834,41.951621]},"n4177":{"id":"n4177","loc":[-85.62197,41.951619]},"n4178":{"id":"n4178","loc":[-85.621972,41.951722]},"n4179":{"id":"n4179","loc":[-85.621772,41.951638]},"n418":{"id":"n418","loc":[-85.633547,41.943896]},"n4180":{"id":"n4180","loc":[-85.621772,41.951715]},"n4181":{"id":"n4181","loc":[-85.621699,41.951716]},"n4182":{"id":"n4182","loc":[-85.6217,41.951722]},"n4183":{"id":"n4183","loc":[-85.621641,41.951722]},"n4184":{"id":"n4184","loc":[-85.62164,41.951639]},"n4185":{"id":"n4185","loc":[-85.621505,41.951655]},"n4186":{"id":"n4186","loc":[-85.621505,41.951729]},"n4187":{"id":"n4187","loc":[-85.621389,41.951729]},"n4188":{"id":"n4188","loc":[-85.62139,41.951654]},"n4189":{"id":"n4189","loc":[-85.621105,41.951635]},"n419":{"id":"n419","loc":[-85.633467,41.944075]},"n4190":{"id":"n4190","loc":[-85.621104,41.951576]},"n4191":{"id":"n4191","loc":[-85.621168,41.951576]},"n4192":{"id":"n4192","loc":[-85.621168,41.951595]},"n4193":{"id":"n4193","loc":[-85.621261,41.951595]},"n4194":{"id":"n4194","loc":[-85.621261,41.951646]},"n4195":{"id":"n4195","loc":[-85.621294,41.951646]},"n4196":{"id":"n4196","loc":[-85.621294,41.951732]},"n4197":{"id":"n4197","loc":[-85.621251,41.951732]},"n4198":{"id":"n4198","loc":[-85.621251,41.95174]},"n4199":{"id":"n4199","loc":[-85.621175,41.951741]},"n42":{"id":"n42","loc":[-85.635996,41.942727]},"n420":{"id":"n420","loc":[-85.633578,41.944055]},"n4200":{"id":"n4200","loc":[-85.621175,41.951651]},"n4201":{"id":"n4201","loc":[-85.621189,41.951651]},"n4202":{"id":"n4202","loc":[-85.621189,41.951635]},"n4203":{"id":"n4203","loc":[-85.620554,41.951641]},"n4204":{"id":"n4204","loc":[-85.620555,41.951742]},"n4205":{"id":"n4205","loc":[-85.620719,41.951742]},"n4206":{"id":"n4206","loc":[-85.620719,41.951731]},"n4207":{"id":"n4207","loc":[-85.620803,41.95173]},"n4208":{"id":"n4208","loc":[-85.620803,41.951603]},"n4209":{"id":"n4209","loc":[-85.62072,41.951603]},"n421":{"id":"n421","loc":[-85.633462,41.944125]},"n4210":{"id":"n4210","loc":[-85.620721,41.951641]},"n4211":{"id":"n4211","loc":[-85.620269,41.953053]},"n4212":{"id":"n4212","loc":[-85.620229,41.953051]},"n4213":{"id":"n4213","loc":[-85.620231,41.953013]},"n4214":{"id":"n4214","loc":[-85.620271,41.953015]},"n4215":{"id":"n4215","loc":[-85.620215,41.953133]},"n4216":{"id":"n4216","loc":[-85.62013,41.953134]},"n4217":{"id":"n4217","loc":[-85.620129,41.953083]},"n4218":{"id":"n4218","loc":[-85.620214,41.953082]},"n4219":{"id":"n4219","loc":[-85.62016,41.953272]},"n422":{"id":"n422","loc":[-85.633372,41.944061]},"n4220":{"id":"n4220","loc":[-85.620046,41.953273]},"n4221":{"id":"n4221","loc":[-85.620045,41.953171]},"n4222":{"id":"n4222","loc":[-85.620088,41.953171]},"n4223":{"id":"n4223","loc":[-85.620087,41.953162]},"n4224":{"id":"n4224","loc":[-85.620121,41.953162]},"n4225":{"id":"n4225","loc":[-85.620121,41.953173]},"n4226":{"id":"n4226","loc":[-85.620157,41.953173]},"n4227":{"id":"n4227","loc":[-85.620158,41.953196]},"n4228":{"id":"n4228","loc":[-85.620189,41.953196]},"n4229":{"id":"n4229","loc":[-85.620189,41.953246]},"n423":{"id":"n423","loc":[-85.633509,41.943981]},"n4230":{"id":"n4230","loc":[-85.62016,41.953246]},"n4231":{"id":"n4231","loc":[-85.6195,41.954012]},"n4232":{"id":"n4232","loc":[-85.619438,41.954057]},"n4233":{"id":"n4233","loc":[-85.619418,41.954043]},"n4234":{"id":"n4234","loc":[-85.619381,41.954069]},"n4235":{"id":"n4235","loc":[-85.619399,41.954083]},"n4236":{"id":"n4236","loc":[-85.619339,41.954126]},"n4237":{"id":"n4237","loc":[-85.619584,41.954313]},"n4238":{"id":"n4238","loc":[-85.619743,41.954198]},"n4239":{"id":"n4239","loc":[-85.619453,41.954727]},"n424":{"id":"n424","loc":[-85.635421,41.945367]},"n4240":{"id":"n4240","loc":[-85.619503,41.954581]},"n4241":{"id":"n4241","loc":[-85.619597,41.954472]},"n4242":{"id":"n4242","loc":[-85.619862,41.95419]},"n4243":{"id":"n4243","loc":[-85.619506,41.953907]},"n4244":{"id":"n4244","loc":[-85.619261,41.9541]},"n4245":{"id":"n4245","loc":[-85.619246,41.954139]},"n4246":{"id":"n4246","loc":[-85.619244,41.9542]},"n4247":{"id":"n4247","loc":[-85.619259,41.954243]},"n4248":{"id":"n4248","loc":[-85.619285,41.954274]},"n4249":{"id":"n4249","loc":[-85.619123,41.954381]},"n425":{"id":"n425","loc":[-85.634425,41.943552]},"n4250":{"id":"n4250","loc":[-85.619641,41.954607]},"n4251":{"id":"n4251","loc":[-85.619383,41.954615]},"n4252":{"id":"n4252","loc":[-85.61896,41.954391]},"n4253":{"id":"n4253","loc":[-85.619211,41.954178]},"n4254":{"id":"n4254","loc":[-85.619115,41.954102]},"n4255":{"id":"n4255","loc":[-85.619519,41.953821]},"n4256":{"id":"n4256","loc":[-85.619956,41.954156]},"n4257":{"id":"n4257","loc":[-85.619851,41.954266]},"n4258":{"id":"n4258","loc":[-85.619779,41.95436]},"n4259":{"id":"n4259","loc":[-85.620525,41.954364]},"n426":{"id":"n426","loc":[-85.634248,41.943654]},"n4260":{"id":"n4260","loc":[-85.620398,41.954365]},"n4261":{"id":"n4261","loc":[-85.620398,41.954324]},"n4262":{"id":"n4262","loc":[-85.620525,41.954323]},"n4263":{"id":"n4263","loc":[-85.620359,41.954588]},"n4264":{"id":"n4264","loc":[-85.620321,41.954588]},"n4265":{"id":"n4265","loc":[-85.620321,41.954599]},"n4266":{"id":"n4266","loc":[-85.620296,41.954599]},"n4267":{"id":"n4267","loc":[-85.620296,41.954587]},"n4268":{"id":"n4268","loc":[-85.620262,41.954588]},"n4269":{"id":"n4269","loc":[-85.620261,41.954516]},"n427":{"id":"n427","loc":[-85.634177,41.943585]},"n4270":{"id":"n4270","loc":[-85.620282,41.954516]},"n4271":{"id":"n4271","loc":[-85.620282,41.954373]},"n4272":{"id":"n4272","loc":[-85.620378,41.954373]},"n4273":{"id":"n4273","loc":[-85.620379,41.954486]},"n4274":{"id":"n4274","loc":[-85.620348,41.954486]},"n4275":{"id":"n4275","loc":[-85.620348,41.954537]},"n4276":{"id":"n4276","loc":[-85.620359,41.954537]},"n4277":{"id":"n4277","loc":[-85.620463,41.95521]},"n4278":{"id":"n4278","loc":[-85.620409,41.955273]},"n4279":{"id":"n4279","loc":[-85.620205,41.955177]},"n428":{"id":"n428","loc":[-85.634354,41.943484]},"n4280":{"id":"n4280","loc":[-85.620288,41.955079]},"n4281":{"id":"n4281","loc":[-85.620379,41.955121]},"n4282":{"id":"n4282","loc":[-85.620349,41.955157]},"n4283":{"id":"n4283","loc":[-85.620083,41.955101]},"n4284":{"id":"n4284","loc":[-85.620083,41.954986]},"n4285":{"id":"n4285","loc":[-85.620016,41.954986]},"n4286":{"id":"n4286","loc":[-85.620016,41.954999]},"n4287":{"id":"n4287","loc":[-85.619941,41.954999]},"n4288":{"id":"n4288","loc":[-85.619941,41.954988]},"n4289":{"id":"n4289","loc":[-85.619815,41.954988]},"n429":{"id":"n429","loc":[-85.638577,41.943212]},"n4290":{"id":"n4290","loc":[-85.619815,41.955075]},"n4291":{"id":"n4291","loc":[-85.619948,41.955075]},"n4292":{"id":"n4292","loc":[-85.619948,41.955082]},"n4293":{"id":"n4293","loc":[-85.620004,41.955082]},"n4294":{"id":"n4294","loc":[-85.620004,41.955101]},"n4295":{"id":"n4295","loc":[-85.619293,41.955127]},"n4296":{"id":"n4296","loc":[-85.619208,41.955124]},"n4297":{"id":"n4297","loc":[-85.619212,41.955061]},"n4298":{"id":"n4298","loc":[-85.619297,41.955064]},"n4299":{"id":"n4299","loc":[-85.619068,41.954936]},"n43":{"id":"n43","loc":[-85.637047,41.943054]},"n430":{"id":"n430","loc":[-85.638576,41.943219]},"n4300":{"id":"n4300","loc":[-85.619003,41.954936]},"n4301":{"id":"n4301","loc":[-85.619004,41.955003]},"n4302":{"id":"n4302","loc":[-85.618994,41.955003]},"n4303":{"id":"n4303","loc":[-85.618994,41.955016]},"n4304":{"id":"n4304","loc":[-85.618973,41.955016]},"n4305":{"id":"n4305","loc":[-85.618973,41.955071]},"n4306":{"id":"n4306","loc":[-85.619061,41.955071]},"n4307":{"id":"n4307","loc":[-85.61906,41.955024]},"n4308":{"id":"n4308","loc":[-85.619105,41.955024]},"n4309":{"id":"n4309","loc":[-85.619105,41.954956]},"n431":{"id":"n431","loc":[-85.638653,41.943078]},"n4310":{"id":"n4310","loc":[-85.619068,41.954956]},"n4311":{"id":"n4311","loc":[-85.618294,41.954596]},"n4312":{"id":"n4312","loc":[-85.618235,41.954602]},"n4313":{"id":"n4313","loc":[-85.618222,41.954535]},"n4314":{"id":"n4314","loc":[-85.618281,41.954529]},"n4315":{"id":"n4315","loc":[-85.618593,41.954556]},"n4316":{"id":"n4316","loc":[-85.618551,41.954565]},"n4317":{"id":"n4317","loc":[-85.618545,41.954552]},"n4318":{"id":"n4318","loc":[-85.618493,41.954563]},"n4319":{"id":"n4319","loc":[-85.618449,41.954455]},"n432":{"id":"n432","loc":[-85.638654,41.943148]},"n4320":{"id":"n4320","loc":[-85.618544,41.954434]},"n4321":{"id":"n4321","loc":[-85.622545,41.950775]},"n4322":{"id":"n4322","loc":[-85.622546,41.950843]},"n4323":{"id":"n4323","loc":[-85.622503,41.950844]},"n4324":{"id":"n4324","loc":[-85.622503,41.950853]},"n4325":{"id":"n4325","loc":[-85.622479,41.950853]},"n4326":{"id":"n4326","loc":[-85.622478,41.950843]},"n4327":{"id":"n4327","loc":[-85.622425,41.950843]},"n4328":{"id":"n4328","loc":[-85.622425,41.950808]},"n4329":{"id":"n4329","loc":[-85.622366,41.950809]},"n433":{"id":"n433","loc":[-85.638387,41.943151]},"n4330":{"id":"n4330","loc":[-85.622364,41.950673]},"n4331":{"id":"n4331","loc":[-85.622448,41.950673]},"n4332":{"id":"n4332","loc":[-85.622449,41.950732]},"n4333":{"id":"n4333","loc":[-85.622479,41.950731]},"n4334":{"id":"n4334","loc":[-85.622479,41.950775]},"n4335":{"id":"n4335","loc":[-85.621909,41.950641]},"n4336":{"id":"n4336","loc":[-85.621864,41.950641]},"n4337":{"id":"n4337","loc":[-85.621865,41.950567]},"n4338":{"id":"n4338","loc":[-85.62191,41.950567]},"n4339":{"id":"n4339","loc":[-85.621787,41.950829]},"n434":{"id":"n434","loc":[-85.638386,41.94308]},"n4340":{"id":"n4340","loc":[-85.621786,41.950775]},"n4341":{"id":"n4341","loc":[-85.621588,41.950776]},"n4342":{"id":"n4342","loc":[-85.621589,41.950848]},"n4343":{"id":"n4343","loc":[-85.621737,41.950847]},"n4344":{"id":"n4344","loc":[-85.621737,41.950829]},"n4345":{"id":"n4345","loc":[-85.621509,41.950846]},"n4346":{"id":"n4346","loc":[-85.621399,41.950846]},"n4347":{"id":"n4347","loc":[-85.621398,41.95073]},"n4348":{"id":"n4348","loc":[-85.621509,41.95073]},"n4349":{"id":"n4349","loc":[-85.621217,41.950841]},"n435":{"id":"n435","loc":[-85.634427,41.943533]},"n4350":{"id":"n4350","loc":[-85.6211,41.95084]},"n4351":{"id":"n4351","loc":[-85.6211,41.950777]},"n4352":{"id":"n4352","loc":[-85.621218,41.950778]},"n4353":{"id":"n4353","loc":[-85.621055,41.950764]},"n4354":{"id":"n4354","loc":[-85.621054,41.950826]},"n4355":{"id":"n4355","loc":[-85.620988,41.950826]},"n4356":{"id":"n4356","loc":[-85.620988,41.950843]},"n4357":{"id":"n4357","loc":[-85.620842,41.950843]},"n4358":{"id":"n4358","loc":[-85.620842,41.950764]},"n4359":{"id":"n4359","loc":[-85.620825,41.950922]},"n436":{"id":"n436","loc":[-85.63428,41.943229]},"n4360":{"id":"n4360","loc":[-85.620824,41.950553]},"n4361":{"id":"n4361","loc":[-85.620543,41.950771]},"n4362":{"id":"n4362","loc":[-85.620431,41.950772]},"n4363":{"id":"n4363","loc":[-85.62043,41.950585]},"n4364":{"id":"n4364","loc":[-85.620542,41.950585]},"n4365":{"id":"n4365","loc":[-85.62068,41.950505]},"n4366":{"id":"n4366","loc":[-85.620681,41.950552]},"n4367":{"id":"n4367","loc":[-85.620589,41.950553]},"n4368":{"id":"n4368","loc":[-85.620588,41.950506]},"n4369":{"id":"n4369","loc":[-85.620539,41.950407]},"n437":{"id":"n437","loc":[-85.634499,41.943461]},"n4370":{"id":"n4370","loc":[-85.62054,41.950504]},"n4371":{"id":"n4371","loc":[-85.620416,41.950504]},"n4372":{"id":"n4372","loc":[-85.620416,41.950408]},"n4373":{"id":"n4373","loc":[-85.620742,41.95038]},"n4374":{"id":"n4374","loc":[-85.620527,41.95038]},"n4375":{"id":"n4375","loc":[-85.620528,41.950408]},"n4376":{"id":"n4376","loc":[-85.622449,41.950373]},"n4377":{"id":"n4377","loc":[-85.622452,41.950397]},"n4378":{"id":"n4378","loc":[-85.622336,41.950404]},"n4379":{"id":"n4379","loc":[-85.622333,41.950379]},"n438":{"id":"n438","loc":[-85.634514,41.943486]},"n4380":{"id":"n4380","loc":[-85.622263,41.950324]},"n4381":{"id":"n4381","loc":[-85.622261,41.950256]},"n4382":{"id":"n4382","loc":[-85.62236,41.950254]},"n4383":{"id":"n4383","loc":[-85.62236,41.95027]},"n4384":{"id":"n4384","loc":[-85.622402,41.950281]},"n4385":{"id":"n4385","loc":[-85.622403,41.9503]},"n4386":{"id":"n4386","loc":[-85.622439,41.950299]},"n4387":{"id":"n4387","loc":[-85.62244,41.950334]},"n4388":{"id":"n4388","loc":[-85.622414,41.950335]},"n4389":{"id":"n4389","loc":[-85.622414,41.95036]},"n439":{"id":"n439","loc":[-85.63452,41.943511]},"n4390":{"id":"n4390","loc":[-85.62231,41.950362]},"n4391":{"id":"n4391","loc":[-85.622309,41.950323]},"n4392":{"id":"n4392","loc":[-85.622015,41.950539]},"n4393":{"id":"n4393","loc":[-85.621909,41.95054]},"n4394":{"id":"n4394","loc":[-85.621909,41.950472]},"n4395":{"id":"n4395","loc":[-85.622015,41.950471]},"n4396":{"id":"n4396","loc":[-85.62199,41.950439]},"n4397":{"id":"n4397","loc":[-85.621956,41.95044]},"n4398":{"id":"n4398","loc":[-85.621955,41.950405]},"n4399":{"id":"n4399","loc":[-85.621988,41.950404]},"n44":{"id":"n44","loc":[-85.636799,41.943055]},"n440":{"id":"n440","loc":[-85.63451,41.943534]},"n4400":{"id":"n4400","loc":[-85.621668,41.950418]},"n4401":{"id":"n4401","loc":[-85.621667,41.950343]},"n4402":{"id":"n4402","loc":[-85.621745,41.950342]},"n4403":{"id":"n4403","loc":[-85.621744,41.950306]},"n4404":{"id":"n4404","loc":[-85.621764,41.950306]},"n4405":{"id":"n4405","loc":[-85.621763,41.950254]},"n4406":{"id":"n4406","loc":[-85.621861,41.950253]},"n4407":{"id":"n4407","loc":[-85.621861,41.950274]},"n4408":{"id":"n4408","loc":[-85.621896,41.950273]},"n4409":{"id":"n4409","loc":[-85.621898,41.950389]},"n441":{"id":"n441","loc":[-85.634483,41.943556]},"n4410":{"id":"n4410","loc":[-85.621843,41.95039]},"n4411":{"id":"n4411","loc":[-85.621843,41.950425]},"n4412":{"id":"n4412","loc":[-85.621789,41.950425]},"n4413":{"id":"n4413","loc":[-85.621789,41.950386]},"n4414":{"id":"n4414","loc":[-85.621752,41.950387]},"n4415":{"id":"n4415","loc":[-85.621753,41.950417]},"n4416":{"id":"n4416","loc":[-85.621556,41.950562]},"n4417":{"id":"n4417","loc":[-85.621552,41.950217]},"n4418":{"id":"n4418","loc":[-85.621788,41.950562]},"n4419":{"id":"n4419","loc":[-85.621155,41.950562]},"n442":{"id":"n442","loc":[-85.63419,41.943713]},"n4420":{"id":"n4420","loc":[-85.622473,41.950551]},"n4421":{"id":"n4421","loc":[-85.622043,41.950551]},"n4422":{"id":"n4422","loc":[-85.62142,41.950454]},"n4423":{"id":"n4423","loc":[-85.621315,41.950455]},"n4424":{"id":"n4424","loc":[-85.621313,41.950311]},"n4425":{"id":"n4425","loc":[-85.621388,41.950311]},"n4426":{"id":"n4426","loc":[-85.621387,41.950261]},"n4427":{"id":"n4427","loc":[-85.621468,41.95026]},"n4428":{"id":"n4428","loc":[-85.621468,41.950271]},"n4429":{"id":"n4429","loc":[-85.621503,41.95027]},"n443":{"id":"n443","loc":[-85.634462,41.943294]},"n4430":{"id":"n4430","loc":[-85.621505,41.950353]},"n4431":{"id":"n4431","loc":[-85.621483,41.950354]},"n4432":{"id":"n4432","loc":[-85.621483,41.950392]},"n4433":{"id":"n4433","loc":[-85.621419,41.950393]},"n4434":{"id":"n4434","loc":[-85.621213,41.95039]},"n4435":{"id":"n4435","loc":[-85.621127,41.950391]},"n4436":{"id":"n4436","loc":[-85.621126,41.950357]},"n4437":{"id":"n4437","loc":[-85.621094,41.950357]},"n4438":{"id":"n4438","loc":[-85.621094,41.950391]},"n4439":{"id":"n4439","loc":[-85.620977,41.950392]},"n444":{"id":"n444","loc":[-85.634298,41.943389]},"n4440":{"id":"n4440","loc":[-85.620975,41.950278]},"n4441":{"id":"n4441","loc":[-85.621087,41.950277]},"n4442":{"id":"n4442","loc":[-85.621088,41.950331]},"n4443":{"id":"n4443","loc":[-85.621211,41.950312]},"n4444":{"id":"n4444","loc":[-85.621104,41.950313]},"n4445":{"id":"n4445","loc":[-85.621105,41.950331]},"n4446":{"id":"n4446","loc":[-85.620706,41.950328]},"n4447":{"id":"n4447","loc":[-85.620606,41.950327]},"n4448":{"id":"n4448","loc":[-85.620607,41.950261]},"n4449":{"id":"n4449","loc":[-85.620707,41.950262]},"n445":{"id":"n445","loc":[-85.634527,41.943623]},"n4450":{"id":"n4450","loc":[-85.620599,41.950336]},"n4451":{"id":"n4451","loc":[-85.620559,41.950336]},"n4452":{"id":"n4452","loc":[-85.620559,41.950299]},"n4453":{"id":"n4453","loc":[-85.620599,41.950299]},"n4454":{"id":"n4454","loc":[-85.620545,41.950357]},"n4455":{"id":"n4455","loc":[-85.620418,41.950357]},"n4456":{"id":"n4456","loc":[-85.620417,41.950257]},"n4457":{"id":"n4457","loc":[-85.620544,41.950256]},"n4458":{"id":"n4458","loc":[-85.620246,41.950131],"tags":{"highway":"crossing"}},"n4459":{"id":"n4459","loc":[-85.620252,41.950956]},"n446":{"id":"n446","loc":[-85.634608,41.943577]},"n4460":{"id":"n4460","loc":[-85.620245,41.950179]},"n4461":{"id":"n4461","loc":[-85.620246,41.950088]},"n4462":{"id":"n4462","loc":[-85.620251,41.950885]},"n4463":{"id":"n4463","loc":[-85.620103,41.950884],"tags":{"crossing":"zebra","highway":"crossing"}},"n4464":{"id":"n4464","loc":[-85.619992,41.950884]},"n4465":{"id":"n4465","loc":[-85.619704,41.951008]},"n4466":{"id":"n4466","loc":[-85.619599,41.951122]},"n4467":{"id":"n4467","loc":[-85.619264,41.951486]},"n4468":{"id":"n4468","loc":[-85.619179,41.951573],"tags":{"highway":"crossing"}},"n4469":{"id":"n4469","loc":[-85.620251,41.950999],"tags":{"highway":"crossing"}},"n447":{"id":"n447","loc":[-85.634555,41.943531]},"n4470":{"id":"n4470","loc":[-85.620249,41.951066]},"n4471":{"id":"n4471","loc":[-85.620256,41.951374]},"n4472":{"id":"n4472","loc":[-85.620249,41.951389]},"n4473":{"id":"n4473","loc":[-85.620249,41.951407]},"n4474":{"id":"n4474","loc":[-85.620255,41.951423]},"n4475":{"id":"n4475","loc":[-85.62026,41.951853]},"n4476":{"id":"n4476","loc":[-85.620262,41.951894],"tags":{"highway":"crossing"}},"n4477":{"id":"n4477","loc":[-85.620265,41.951957]},"n4478":{"id":"n4478","loc":[-85.620262,41.952135]},"n4479":{"id":"n4479","loc":[-85.620241,41.952424]},"n448":{"id":"n448","loc":[-85.634555,41.943482]},"n4480":{"id":"n4480","loc":[-85.620213,41.952583]},"n4481":{"id":"n4481","loc":[-85.620158,41.952754]},"n4482":{"id":"n4482","loc":[-85.620065,41.952942]},"n4483":{"id":"n4483","loc":[-85.619753,41.953439]},"n4484":{"id":"n4484","loc":[-85.619605,41.953626]},"n4485":{"id":"n4485","loc":[-85.619381,41.953834]},"n4486":{"id":"n4486","loc":[-85.619069,41.954066]},"n4487":{"id":"n4487","loc":[-85.618674,41.95429]},"n4488":{"id":"n4488","loc":[-85.621816,41.952389]},"n4489":{"id":"n4489","loc":[-85.6217,41.952386]},"n449":{"id":"n449","loc":[-85.634509,41.943427]},"n4490":{"id":"n4490","loc":[-85.621705,41.952306]},"n4491":{"id":"n4491","loc":[-85.621821,41.95231]},"n4492":{"id":"n4492","loc":[-85.621819,41.952272]},"n4493":{"id":"n4493","loc":[-85.621778,41.952272]},"n4494":{"id":"n4494","loc":[-85.621778,41.952199]},"n4495":{"id":"n4495","loc":[-85.621818,41.952199]},"n4496":{"id":"n4496","loc":[-85.621754,41.952281]},"n4497":{"id":"n4497","loc":[-85.621701,41.95228]},"n4498":{"id":"n4498","loc":[-85.621702,41.952197]},"n4499":{"id":"n4499","loc":[-85.621755,41.952197]},"n45":{"id":"n45","loc":[-85.636791,41.942792]},"n450":{"id":"n450","loc":[-85.63453,41.943365]},"n4500":{"id":"n4500","loc":[-85.628201,41.954694],"tags":{"highway":"stop","stop":"all"}},"n4501":{"id":"n4501","loc":[-85.627921,41.954783],"tags":{"highway":"stop","stop":"all"}},"n4502":{"id":"n4502","loc":[-85.62775,41.954696],"tags":{"highway":"stop","stop":"all"}},"n4503":{"id":"n4503","loc":[-85.628046,41.954591],"tags":{"highway":"stop","stop":"all"}},"n4504":{"id":"n4504","loc":[-85.631074,41.957428],"tags":{"highway":"stop"}},"n4505":{"id":"n4505","loc":[-85.630768,41.957429],"tags":{"highway":"stop"}},"n4506":{"id":"n4506","loc":[-85.629888,41.957432],"tags":{"highway":"stop"}},"n4507":{"id":"n4507","loc":[-85.629565,41.957433],"tags":{"highway":"stop"}},"n4508":{"id":"n4508","loc":[-85.629559,41.957343]},"n4509":{"id":"n4509","loc":[-85.628723,41.95735]},"n451":{"id":"n451","loc":[-85.634356,41.943468]},"n4510":{"id":"n4510","loc":[-85.62842,41.957515]},"n4511":{"id":"n4511","loc":[-85.627561,41.957525]},"n4512":{"id":"n4512","loc":[-85.630323,41.957508]},"n4513":{"id":"n4513","loc":[-85.630811,41.957506]},"n4514":{"id":"n4514","loc":[-85.630839,41.960874]},"n4515":{"id":"n4515","loc":[-85.631035,41.957506]},"n4516":{"id":"n4516","loc":[-85.632027,41.9575]},"n4517":{"id":"n4517","loc":[-85.631038,41.958066]},"n4518":{"id":"n4518","loc":[-85.630787,41.954769]},"n4519":{"id":"n4519","loc":[-85.630806,41.957342]},"n452":{"id":"n452","loc":[-85.634123,41.943596]},"n4520":{"id":"n4520","loc":[-85.630809,41.957428],"tags":{"highway":"crossing"}},"n4521":{"id":"n4521","loc":[-85.630912,41.957506],"tags":{"highway":"crossing"}},"n4522":{"id":"n4522","loc":[-85.631033,41.957428],"tags":{"highway":"crossing"}},"n4523":{"id":"n4523","loc":[-85.631032,41.957341]},"n4524":{"id":"n4524","loc":[-85.63091,41.957341],"tags":{"highway":"crossing"}},"n4525":{"id":"n4525","loc":[-85.631027,41.95597]},"n4526":{"id":"n4526","loc":[-85.631027,41.955913],"tags":{"highway":"crossing"}},"n4527":{"id":"n4527","loc":[-85.631025,41.955873]},"n4528":{"id":"n4528","loc":[-85.631073,41.955913],"tags":{"highway":"stop"}},"n4529":{"id":"n4529","loc":[-85.631007,41.954766]},"n453":{"id":"n453","loc":[-85.634709,41.943926]},"n4530":{"id":"n4530","loc":[-85.630881,41.954768],"tags":{"highway":"crossing"}},"n4531":{"id":"n4531","loc":[-85.628022,41.954776]},"n4532":{"id":"n4532","loc":[-85.627385,41.95584]},"n4533":{"id":"n4533","loc":[-85.627329,41.955937]},"n4534":{"id":"n4534","loc":[-85.626583,41.957153]},"n4535":{"id":"n4535","loc":[-85.629675,41.954564],"tags":{"highway":"stop"}},"n4536":{"id":"n4536","loc":[-85.630881,41.954806],"tags":{"highway":"stop"}},"n4537":{"id":"n4537","loc":[-85.630879,41.954564],"tags":{"highway":"stop"}},"n4538":{"id":"n4538","loc":[-85.630784,41.954682],"tags":{"highway":"crossing"}},"n4539":{"id":"n4539","loc":[-85.63078,41.954595]},"n454":{"id":"n454","loc":[-85.63525,41.943855]},"n4540":{"id":"n4540","loc":[-85.630879,41.954595],"tags":{"highway":"crossing"}},"n4541":{"id":"n4541","loc":[-85.631004,41.954594]},"n4542":{"id":"n4542","loc":[-85.631006,41.954681],"tags":{"highway":"crossing"}},"n4543":{"id":"n4543","loc":[-85.631045,41.959036],"tags":{"highway":"stop"}},"n4544":{"id":"n4544","loc":[-85.632071,41.959029],"tags":{"highway":"stop"}},"n4545":{"id":"n4545","loc":[-85.632257,41.959027],"tags":{"highway":"stop"}},"n4546":{"id":"n4546","loc":[-85.631966,41.957427],"tags":{"highway":"stop"}},"n4547":{"id":"n4547","loc":[-85.632297,41.957426],"tags":{"highway":"stop"}},"n4548":{"id":"n4548","loc":[-85.631976,41.955911],"tags":{"highway":"give_way"}},"n4549":{"id":"n4549","loc":[-85.632272,41.955911],"tags":{"highway":"give_way"}},"n455":{"id":"n455","loc":[-85.635224,41.943869]},"n4550":{"id":"n4550","loc":[-85.632097,41.954805],"tags":{"highway":"stop"}},"n4551":{"id":"n4551","loc":[-85.632094,41.954566],"tags":{"highway":"stop"}},"n4552":{"id":"n4552","loc":[-85.626519,41.957256]},"n4553":{"id":"n4553","loc":[-85.625334,41.959165]},"n4554":{"id":"n4554","loc":[-85.626483,41.95806]},"n4555":{"id":"n4555","loc":[-85.626481,41.958175]},"n4556":{"id":"n4556","loc":[-85.626412,41.958174]},"n4557":{"id":"n4557","loc":[-85.626412,41.958202]},"n4558":{"id":"n4558","loc":[-85.62628,41.958201]},"n4559":{"id":"n4559","loc":[-85.626283,41.958057]},"n456":{"id":"n456","loc":[-85.638854,41.943104]},"n4560":{"id":"n4560","loc":[-85.622763,41.95109],"tags":{"highway":"stop"}},"n4561":{"id":"n4561","loc":[-85.622858,41.950876],"tags":{"emergency":"fire_hydrant"}},"n4562":{"id":"n4562","loc":[-85.624073,41.950393]},"n4563":{"id":"n4563","loc":[-85.624077,41.950924]},"n4564":{"id":"n4564","loc":[-85.624599,41.950984],"tags":{"highway":"stop"}},"n4565":{"id":"n4565","loc":[-85.624831,41.95119],"tags":{"emergency":"fire_hydrant"}},"n4566":{"id":"n4566","loc":[-85.624437,41.952568],"tags":{"emergency":"fire_hydrant"}},"n4567":{"id":"n4567","loc":[-85.624077,41.954606],"tags":{"emergency":"fire_hydrant"}},"n4568":{"id":"n4568","loc":[-85.624263,41.954888]},"n4569":{"id":"n4569","loc":[-85.624206,41.954919]},"n457":{"id":"n457","loc":[-85.635186,41.943901]},"n4570":{"id":"n4570","loc":[-85.624154,41.954865]},"n4571":{"id":"n4571","loc":[-85.624212,41.954835]},"n4572":{"id":"n4572","loc":[-85.622442,41.954401],"tags":{"emergency":"fire_hydrant"}},"n4573":{"id":"n4573","loc":[-85.619751,41.954658],"tags":{"emergency":"fire_hydrant"}},"n4574":{"id":"n4574","loc":[-85.617785,41.954534]},"n4575":{"id":"n4575","loc":[-85.617416,41.954721]},"n4576":{"id":"n4576","loc":[-85.617662,41.95474]},"n4577":{"id":"n4577","loc":[-85.618014,41.954717]},"n4578":{"id":"n4578","loc":[-85.617886,41.954671]},"n4579":{"id":"n4579","loc":[-85.617831,41.954612]},"n458":{"id":"n458","loc":[-85.635162,41.943917]},"n4580":{"id":"n4580","loc":[-85.617968,41.954752]},"n4581":{"id":"n4581","loc":[-85.617815,41.954752]},"n4582":{"id":"n4582","loc":[-85.617938,41.954695]},"n4583":{"id":"n4583","loc":[-85.617856,41.954642],"tags":{"highway":"stop"}},"n4584":{"id":"n4584","loc":[-85.619116,41.954164],"tags":{"man_made":"flagpole"}},"n4585":{"id":"n4585","loc":[-85.619569,41.953255],"tags":{"emergency":"fire_hydrant"}},"n4586":{"id":"n4586","loc":[-85.620352,41.951894],"tags":{"highway":"stop"}},"n4587":{"id":"n4587","loc":[-85.620485,41.951948],"tags":{"emergency":"fire_hydrant"}},"n4588":{"id":"n4588","loc":[-85.620316,41.950999],"tags":{"highway":"stop"}},"n4589":{"id":"n4589","loc":[-85.620311,41.950131],"tags":{"highway":"stop"}},"n459":{"id":"n459","loc":[-85.634856,41.943905]},"n4590":{"id":"n4590","loc":[-85.620374,41.95018],"tags":{"emergency":"fire_hydrant"}},"n4591":{"id":"n4591","loc":[-85.620301,41.949239],"tags":{"highway":"stop"}},"n4592":{"id":"n4592","loc":[-85.620278,41.947443],"tags":{"highway":"stop"}},"n4593":{"id":"n4593","loc":[-85.619844,41.947444],"tags":{"highway":"stop"}},"n4594":{"id":"n4594","loc":[-85.620191,41.947352],"tags":{"emergency":"fire_hydrant"}},"n4595":{"id":"n4595","loc":[-85.622819,41.947493],"tags":{"emergency":"fire_hydrant"}},"n4596":{"id":"n4596","loc":[-85.622744,41.947541],"tags":{"highway":"stop"}},"n4597":{"id":"n4597","loc":[-85.622739,41.947316],"tags":{"highway":"stop"}},"n4598":{"id":"n4598","loc":[-85.622909,41.948333],"tags":{"highway":"give_way"}},"n4599":{"id":"n4599","loc":[-85.622593,41.948333],"tags":{"highway":"give_way"}},"n46":{"id":"n46","loc":[-85.637131,41.94307]},"n460":{"id":"n460","loc":[-85.634811,41.944007]},"n4600":{"id":"n4600","loc":[-85.622835,41.948387],"tags":{"emergency":"fire_hydrant"}},"n4601":{"id":"n4601","loc":[-85.622768,41.949125],"tags":{"highway":"stop"}},"n4602":{"id":"n4602","loc":[-85.622769,41.949325],"tags":{"highway":"stop"}},"n4603":{"id":"n4603","loc":[-85.622837,41.949329],"tags":{"emergency":"fire_hydrant"}},"n4604":{"id":"n4604","loc":[-85.622614,41.950113],"tags":{"highway":"give_way"}},"n4605":{"id":"n4605","loc":[-85.624777,41.949219],"tags":{"highway":"stop"}},"n4606":{"id":"n4606","loc":[-85.624849,41.949106],"tags":{"emergency":"fire_hydrant"}},"n4607":{"id":"n4607","loc":[-85.624858,41.950119],"tags":{"emergency":"fire_hydrant"}},"n4608":{"id":"n4608","loc":[-85.624752,41.948334],"tags":{"highway":"give_way"}},"n4609":{"id":"n4609","loc":[-85.624845,41.948422],"tags":{"emergency":"fire_hydrant"}},"n461":{"id":"n461","loc":[-85.634987,41.943112]},"n4610":{"id":"n4610","loc":[-85.62484,41.947539],"tags":{"emergency":"fire_hydrant"}},"n4611":{"id":"n4611","loc":[-85.62476,41.947428],"tags":{"highway":"stop"}},"n4612":{"id":"n4612","loc":[-85.620286,41.950926]},"n4613":{"id":"n4613","loc":[-85.618237,41.950963]},"n4614":{"id":"n4614","loc":[-85.618107,41.950876]},"n4615":{"id":"n4615","loc":[-85.618131,41.950393]},"n4616":{"id":"n4616","loc":[-85.61823,41.9499]},"n4617":{"id":"n4617","loc":[-85.619138,41.950212]},"n4618":{"id":"n4618","loc":[-85.619299,41.950388]},"n4619":{"id":"n4619","loc":[-85.619306,41.950897]},"n462":{"id":"n462","loc":[-85.634698,41.943194]},"n4620":{"id":"n4620","loc":[-85.619155,41.950958]},"n4621":{"id":"n4621","loc":[-85.620079,41.947715]},"n4622":{"id":"n4622","loc":[-85.619674,41.947728]},"n4623":{"id":"n4623","loc":[-85.619634,41.947735]},"n4624":{"id":"n4624","loc":[-85.619587,41.947756],"tags":{"barrier":"gate"}},"n4625":{"id":"n4625","loc":[-85.61953,41.947796]},"n4626":{"id":"n4626","loc":[-85.619475,41.947847]},"n4627":{"id":"n4627","loc":[-85.619433,41.947903]},"n4628":{"id":"n4628","loc":[-85.619402,41.947982]},"n4629":{"id":"n4629","loc":[-85.619394,41.948043]},"n463":{"id":"n463","loc":[-85.634632,41.943219]},"n4630":{"id":"n4630","loc":[-85.619395,41.948476]},"n4631":{"id":"n4631","loc":[-85.618367,41.947452]},"n4632":{"id":"n4632","loc":[-85.618371,41.947567],"tags":{"barrier":"gate"}},"n4633":{"id":"n4633","loc":[-85.618341,41.947622]},"n4634":{"id":"n4634","loc":[-85.618138,41.94773]},"n4635":{"id":"n4635","loc":[-85.618078,41.947814]},"n4636":{"id":"n4636","loc":[-85.618072,41.948009]},"n4637":{"id":"n4637","loc":[-85.618269,41.947666]},"n4638":{"id":"n4638","loc":[-85.618099,41.947765]},"n4639":{"id":"n4639","loc":[-85.618378,41.954453]},"n464":{"id":"n464","loc":[-85.63459,41.943239]},"n4640":{"id":"n4640","loc":[-85.618198,41.95453]},"n4641":{"id":"n4641","loc":[-85.618212,41.954623]},"n4642":{"id":"n4642","loc":[-85.635211,41.943103],"tags":{"leisure":"picnic_table"}},"n4643":{"id":"n4643","loc":[-85.635345,41.943448],"tags":{"leisure":"picnic_table"}},"n4644":{"id":"n4644","loc":[-85.635901,41.943353],"tags":{"amenity":"bench"}},"n4645":{"id":"n4645","loc":[-85.635815,41.942638],"tags":{"highway":"stop"}},"n4646":{"id":"n4646","loc":[-85.635355,41.942044],"tags":{"leisure":"picnic_table"}},"n4647":{"id":"n4647","loc":[-85.635206,41.942045],"tags":{"leisure":"picnic_table"}},"n4648":{"id":"n4648","loc":[-85.63504,41.941992],"tags":{"leisure":"picnic_table"}},"n4649":{"id":"n4649","loc":[-85.635185,41.942001]},"n465":{"id":"n465","loc":[-85.634555,41.943263]},"n4650":{"id":"n4650","loc":[-85.635176,41.942021]},"n4651":{"id":"n4651","loc":[-85.635127,41.942008]},"n4652":{"id":"n4652","loc":[-85.635136,41.941988]},"n4653":{"id":"n4653","loc":[-85.635,41.941709],"tags":{"emergency":"fire_hydrant"}},"n4654":{"id":"n4654","loc":[-85.634893,41.941801]},"n4655":{"id":"n4655","loc":[-85.634937,41.941843]},"n4656":{"id":"n4656","loc":[-85.634963,41.941859]},"n4657":{"id":"n4657","loc":[-85.635027,41.941904]},"n4658":{"id":"n4658","loc":[-85.63494,41.94187]},"n4659":{"id":"n4659","loc":[-85.634951,41.941871]},"n466":{"id":"n466","loc":[-85.634526,41.943289]},"n4660":{"id":"n4660","loc":[-85.634753,41.941701],"tags":{"amenity":"drinking_water"}},"n4661":{"id":"n4661","loc":[-85.634717,41.941804],"tags":{"amenity":"bench"}},"n4662":{"id":"n4662","loc":[-85.634554,41.941883],"tags":{"amenity":"bench"}},"n4663":{"id":"n4663","loc":[-85.635002,41.941579],"tags":{"amenity":"fountain"}},"n4664":{"id":"n4664","loc":[-85.635258,41.94188],"tags":{"amenity":"waste_basket"}},"n4665":{"id":"n4665","loc":[-85.635262,41.941581],"tags":{"amenity":"bench"}},"n4666":{"id":"n4666","loc":[-85.635319,41.941744],"tags":{"amenity":"bench"}},"n4667":{"id":"n4667","loc":[-85.634702,41.941473],"tags":{"amenity":"waste_basket"}},"n4668":{"id":"n4668","loc":[-85.633981,41.941966],"tags":{"amenity":"bench"}},"n4669":{"id":"n4669","loc":[-85.63388,41.941743]},"n467":{"id":"n467","loc":[-85.635163,41.944985]},"n4670":{"id":"n4670","loc":[-85.633746,41.941741]},"n4671":{"id":"n4671","loc":[-85.633749,41.941664]},"n4672":{"id":"n4672","loc":[-85.633883,41.941667]},"n4673":{"id":"n4673","loc":[-85.634283,41.941183],"tags":{"leisure":"picnic_table"}},"n4674":{"id":"n4674","loc":[-85.634046,41.941102],"tags":{"amenity":"bbq"}},"n4675":{"id":"n4675","loc":[-85.63401,41.941093],"tags":{"amenity":"bbq"}},"n4676":{"id":"n4676","loc":[-85.633408,41.940862],"tags":{"amenity":"bench"}},"n4677":{"id":"n4677","loc":[-85.633359,41.940651],"tags":{"amenity":"bench"}},"n4678":{"id":"n4678","loc":[-85.634109,41.940831]},"n4679":{"id":"n4679","loc":[-85.63396,41.940867]},"n468":{"id":"n468","loc":[-85.635095,41.945035]},"n4680":{"id":"n4680","loc":[-85.633816,41.940913]},"n4681":{"id":"n4681","loc":[-85.633237,41.940455]},"n4682":{"id":"n4682","loc":[-85.634453,41.940025],"tags":{"emergency":"fire_hydrant"}},"n4683":{"id":"n4683","loc":[-85.635692,41.940218],"tags":{"emergency":"fire_hydrant"}},"n4684":{"id":"n4684","loc":[-85.635566,41.940102],"tags":{"highway":"stop"}},"n4685":{"id":"n4685","loc":[-85.635961,41.940125],"tags":{"highway":"stop"}},"n4686":{"id":"n4686","loc":[-85.635883,41.94012],"tags":{"crossing":"zebra","highway":"crossing"}},"n4687":{"id":"n4687","loc":[-85.635883,41.94006]},"n4688":{"id":"n4688","loc":[-85.635768,41.940051],"tags":{"crossing":"zebra","highway":"crossing"}},"n4689":{"id":"n4689","loc":[-85.635669,41.940043]},"n469":{"id":"n469","loc":[-85.634269,41.944431]},"n4690":{"id":"n4690","loc":[-85.635661,41.940107],"tags":{"crossing":"zebra","highway":"crossing"}},"n4691":{"id":"n4691","loc":[-85.635424,41.941005],"tags":{"amenity":"fountain"}},"n4692":{"id":"n4692","loc":[-85.635542,41.941371],"tags":{"amenity":"bench"}},"n4693":{"id":"n4693","loc":[-85.635709,41.941341],"tags":{"emergency":"fire_hydrant"}},"n4694":{"id":"n4694","loc":[-85.637038,41.942513],"tags":{"highway":"stop"}},"n4695":{"id":"n4695","loc":[-85.637174,41.941354],"tags":{"highway":"stop"}},"n4696":{"id":"n4696","loc":[-85.637091,41.941273],"tags":{"emergency":"fire_hydrant"}},"n4697":{"id":"n4697","loc":[-85.638058,41.941346],"tags":{"highway":"give_way"}},"n4698":{"id":"n4698","loc":[-85.638359,41.941344],"tags":{"highway":"give_way"}},"n4699":{"id":"n4699","loc":[-85.638288,41.941236],"tags":{"emergency":"fire_hydrant"}},"n47":{"id":"n47","loc":[-85.636693,41.943073]},"n470":{"id":"n470","loc":[-85.634352,41.944376]},"n4700":{"id":"n4700","loc":[-85.63935,41.94128],"tags":{"emergency":"fire_hydrant"}},"n4701":{"id":"n4701","loc":[-85.639277,41.941337],"tags":{"highway":"give_way"}},"n4702":{"id":"n4702","loc":[-85.639548,41.941334],"tags":{"highway":"give_way"}},"n4703":{"id":"n4703","loc":[-85.642191,41.940039]},"n4704":{"id":"n4704","loc":[-85.640585,41.941263],"tags":{"emergency":"fire_hydrant"}},"n4705":{"id":"n4705","loc":[-85.64049,41.941327],"tags":{"highway":"stop"}},"n4706":{"id":"n4706","loc":[-85.640803,41.941324],"tags":{"highway":"stop"}},"n4707":{"id":"n4707","loc":[-85.641717,41.941317],"tags":{"highway":"stop"}},"n4708":{"id":"n4708","loc":[-85.641846,41.941415],"tags":{"highway":"stop"}},"n4709":{"id":"n4709","loc":[-85.641756,41.941392],"tags":{"emergency":"fire_hydrant"}},"n471":{"id":"n471","loc":[-85.634747,41.944561],"tags":{"railway":"crossing"}},"n4710":{"id":"n4710","loc":[-85.642014,41.941313],"tags":{"highway":"stop"}},"n4711":{"id":"n4711","loc":[-85.641854,41.942455],"tags":{"highway":"stop"}},"n4712":{"id":"n4712","loc":[-85.641859,41.942739],"tags":{"highway":"stop"}},"n4713":{"id":"n4713","loc":[-85.640754,41.942707],"tags":{"emergency":"fire_hydrant"}},"n4714":{"id":"n4714","loc":[-85.640669,41.942716],"tags":{"highway":"stop"}},"n4715":{"id":"n4715","loc":[-85.640664,41.942478],"tags":{"highway":"stop"}},"n4716":{"id":"n4716","loc":[-85.63964,41.94274],"tags":{"man_made":"flagpole"}},"n4717":{"id":"n4717","loc":[-85.639455,41.942731],"tags":{"highway":"stop"}},"n4718":{"id":"n4718","loc":[-85.63945,41.942492],"tags":{"highway":"stop"}},"n4719":{"id":"n4719","loc":[-85.639527,41.942505],"tags":{"emergency":"fire_hydrant"}},"n472":{"id":"n472","loc":[-85.634667,41.944613]},"n4720":{"id":"n4720","loc":[-85.638238,41.942745],"tags":{"highway":"stop"}},"n4721":{"id":"n4721","loc":[-85.638233,41.942511],"tags":{"highway":"stop"}},"n4722":{"id":"n4722","loc":[-85.638018,41.94299],"tags":{"amenity":"waste_disposal"}},"n4723":{"id":"n4723","loc":[-85.637918,41.944152],"tags":{"amenity":"waste_basket"}},"n4724":{"id":"n4724","loc":[-85.635902,41.943291],"tags":{"leisure":"picnic_table"}},"n4725":{"id":"n4725","loc":[-85.63704,41.942741],"tags":{"highway":"stop"}},"n4726":{"id":"n4726","loc":[-85.633467,41.943818],"tags":{"highway":"stop"}},"n4727":{"id":"n4727","loc":[-85.633987,41.943531],"tags":{"highway":"stop"}},"n4728":{"id":"n4728","loc":[-85.632154,41.943539],"tags":{"emergency":"fire_hydrant"}},"n4729":{"id":"n4729","loc":[-85.633567,41.944641],"tags":{"amenity":"bench"}},"n473":{"id":"n473","loc":[-85.634161,41.944371]},"n4730":{"id":"n4730","loc":[-85.633127,41.944574],"tags":{"amenity":"bench"}},"n4731":{"id":"n4731","loc":[-85.633439,41.944871],"tags":{"amenity":"bench"}},"n4732":{"id":"n4732","loc":[-85.633676,41.944799],"tags":{"amenity":"waste_basket"}},"n4733":{"id":"n4733","loc":[-85.633466,41.944862],"tags":{"amenity":"waste_basket"}},"n4734":{"id":"n4734","loc":[-85.633451,41.944847],"tags":{"emergency":"fire_hydrant"}},"n4735":{"id":"n4735","loc":[-85.634202,41.945543],"tags":{"amenity":"waste_basket"}},"n4736":{"id":"n4736","loc":[-85.634652,41.945472],"tags":{"leisure":"picnic_table"}},"n4737":{"id":"n4737","loc":[-85.6347,41.945445],"tags":{"leisure":"picnic_table"}},"n4738":{"id":"n4738","loc":[-85.634646,41.945662],"tags":{"emergency":"fire_hydrant"}},"n4739":{"id":"n4739","loc":[-85.634673,41.945687],"tags":{"amenity":"waste_basket"}},"n474":{"id":"n474","loc":[-85.633861,41.944117]},"n4740":{"id":"n4740","loc":[-85.63449,41.945827],"tags":{"amenity":"clock","display":"analog"}},"n4741":{"id":"n4741","loc":[-85.63481,41.946056],"tags":{"highway":"stop"}},"n4742":{"id":"n4742","loc":[-85.634814,41.946176],"tags":{"amenity":"post_box"}},"n4743":{"id":"n4743","loc":[-85.638744,41.945328]},"n4744":{"id":"n4744","loc":[-85.63867,41.945228],"tags":{"amenity":"bench"}},"n4745":{"id":"n4745","loc":[-85.639487,41.945042],"tags":{"highway":"stop"}},"n4746":{"id":"n4746","loc":[-85.639635,41.94387],"tags":{"highway":"stop"}},"n4747":{"id":"n4747","loc":[-85.639549,41.943756],"tags":{"emergency":"fire_hydrant"}},"n4748":{"id":"n4748","loc":[-85.64055,41.943862],"tags":{"highway":"stop"}},"n4749":{"id":"n4749","loc":[-85.640864,41.943859],"tags":{"highway":"stop"}},"n475":{"id":"n475","loc":[-85.633906,41.943535]},"n4750":{"id":"n4750","loc":[-85.640718,41.945022],"tags":{"highway":"stop"}},"n4751":{"id":"n4751","loc":[-85.640664,41.945076],"tags":{"emergency":"fire_hydrant"}},"n4752":{"id":"n4752","loc":[-85.641913,41.94502],"tags":{"highway":"stop"}},"n4753":{"id":"n4753","loc":[-85.641838,41.945076],"tags":{"emergency":"fire_hydrant"}},"n4754":{"id":"n4754","loc":[-85.642045,41.94385],"tags":{"highway":"give_way"}},"n4755":{"id":"n4755","loc":[-85.641738,41.943852],"tags":{"highway":"give_way"}},"n4756":{"id":"n4756","loc":[-85.642928,41.943843],"tags":{"highway":"stop"}},"n4757":{"id":"n4757","loc":[-85.64305,41.943902],"tags":{"emergency":"fire_hydrant"}},"n4758":{"id":"n4758","loc":[-85.642986,41.945105],"tags":{"highway":"stop"}},"n4759":{"id":"n4759","loc":[-85.643136,41.94502],"tags":{"highway":"stop"}},"n476":{"id":"n476","loc":[-85.63423,41.943692]},"n4760":{"id":"n4760","loc":[-85.63169,41.947812]},"n4761":{"id":"n4761","loc":[-85.631307,41.947655]},"n4762":{"id":"n4762","loc":[-85.631407,41.947413]},"n4763":{"id":"n4763","loc":[-85.631173,41.947306]},"n4764":{"id":"n4764","loc":[-85.631316,41.947145]},"n4765":{"id":"n4765","loc":[-85.631476,41.947087]},"n4766":{"id":"n4766","loc":[-85.631793,41.946871]},"n4767":{"id":"n4767","loc":[-85.631884,41.946723]},"n4768":{"id":"n4768","loc":[-85.631814,41.946397]},"n4769":{"id":"n4769","loc":[-85.631382,41.947685]},"n477":{"id":"n477","loc":[-85.635096,41.942814]},"n4770":{"id":"n4770","loc":[-85.63109,41.947819]},"n4771":{"id":"n4771","loc":[-85.630921,41.947961]},"n4772":{"id":"n4772","loc":[-85.630249,41.947709]},"n4773":{"id":"n4773","loc":[-85.630149,41.947451]},"n4774":{"id":"n4774","loc":[-85.629733,41.947339]},"n4775":{"id":"n4775","loc":[-85.629755,41.946948]},"n4776":{"id":"n4776","loc":[-85.630457,41.947103]},"n4777":{"id":"n4777","loc":[-85.630934,41.946939]},"n4778":{"id":"n4778","loc":[-85.631277,41.946852]},"n4779":{"id":"n4779","loc":[-85.63142,41.946781]},"n478":{"id":"n478","loc":[-85.635058,41.942795]},"n4780":{"id":"n4780","loc":[-85.631116,41.946474]},"n4781":{"id":"n4781","loc":[-85.63073,41.945965]},"n4782":{"id":"n4782","loc":[-85.631337,41.94571]},"n4783":{"id":"n4783","loc":[-85.631589,41.945487]},"n4784":{"id":"n4784","loc":[-85.632278,41.945784]},"n4785":{"id":"n4785","loc":[-85.632105,41.946034]},"n4786":{"id":"n4786","loc":[-85.632532,41.946198]},"n4787":{"id":"n4787","loc":[-85.632566,41.946151]},"n4788":{"id":"n4788","loc":[-85.632684,41.946196]},"n4789":{"id":"n4789","loc":[-85.628676,41.947106]},"n479":{"id":"n479","loc":[-85.635002,41.94279]},"n4790":{"id":"n4790","loc":[-85.628973,41.946476]},"n4791":{"id":"n4791","loc":[-85.629094,41.946079]},"n4792":{"id":"n4792","loc":[-85.629226,41.94578]},"n4793":{"id":"n4793","loc":[-85.629479,41.945682]},"n4794":{"id":"n4794","loc":[-85.630606,41.94569]},"n4795":{"id":"n4795","loc":[-85.631255,41.945588]},"n4796":{"id":"n4796","loc":[-85.631546,41.945281]},"n4797":{"id":"n4797","loc":[-85.631629,41.944823]},"n4798":{"id":"n4798","loc":[-85.631766,41.944958]},"n4799":{"id":"n4799","loc":[-85.631689,41.945318]},"n48":{"id":"n48","loc":[-85.636689,41.94276]},"n480":{"id":"n480","loc":[-85.634908,41.94279]},"n4800":{"id":"n4800","loc":[-85.615069,41.945527]},"n4801":{"id":"n4801","loc":[-85.615058,41.946677]},"n4802":{"id":"n4802","loc":[-85.613692,41.946689]},"n4803":{"id":"n4803","loc":[-85.613475,41.946531]},"n4804":{"id":"n4804","loc":[-85.611717,41.946252]},"n4805":{"id":"n4805","loc":[-85.611353,41.946385]},"n4806":{"id":"n4806","loc":[-85.611304,41.947397]},"n4807":{"id":"n4807","loc":[-85.610564,41.947401]},"n4808":{"id":"n4808","loc":[-85.610553,41.947122]},"n4809":{"id":"n4809","loc":[-85.610194,41.946992]},"n481":{"id":"n481","loc":[-85.634478,41.942342]},"n4810":{"id":"n4810","loc":[-85.609976,41.946628]},"n4811":{"id":"n4811","loc":[-85.609769,41.946523]},"n4812":{"id":"n4812","loc":[-85.609307,41.946523]},"n4813":{"id":"n4813","loc":[-85.609035,41.946462]},"n4814":{"id":"n4814","loc":[-85.609018,41.943277]},"n4815":{"id":"n4815","loc":[-85.609617,41.943423]},"n4816":{"id":"n4816","loc":[-85.610471,41.943447]},"n4817":{"id":"n4817","loc":[-85.621491,41.949168]},"n4818":{"id":"n4818","loc":[-85.620266,41.94917]},"n4819":{"id":"n4819","loc":[-85.620262,41.947557]},"n482":{"id":"n482","loc":[-85.634521,41.942254]},"n4820":{"id":"n4820","loc":[-85.620825,41.947556]},"n4821":{"id":"n4821","loc":[-85.620827,41.948371]},"n4822":{"id":"n4822","loc":[-85.621489,41.94837]},"n4823":{"id":"n4823","loc":[-85.622865,41.950928]},"n4824":{"id":"n4824","loc":[-85.622858,41.949744]},"n4825":{"id":"n4825","loc":[-85.623696,41.949714]},"n4826":{"id":"n4826","loc":[-85.623696,41.949647]},"n4827":{"id":"n4827","loc":[-85.624019,41.949647]},"n4828":{"id":"n4828","loc":[-85.624024,41.950093]},"n4829":{"id":"n4829","loc":[-85.622885,41.949711]},"n483":{"id":"n483","loc":[-85.63425,41.941819]},"n4830":{"id":"n4830","loc":[-85.624584,41.951049]},"n4831":{"id":"n4831","loc":[-85.624669,41.9511]},"n4832":{"id":"n4832","loc":[-85.624316,41.952218]},"n4833":{"id":"n4833","loc":[-85.623819,41.952094]},"n4834":{"id":"n4834","loc":[-85.623385,41.952101]},"n4835":{"id":"n4835","loc":[-85.623456,41.951238]},"n4836":{"id":"n4836","loc":[-85.623535,41.951051]},"n4837":{"id":"n4837","loc":[-85.624693,41.950921]},"n4838":{"id":"n4838","loc":[-85.624727,41.950897]},"n4839":{"id":"n4839","loc":[-85.624869,41.950341]},"n484":{"id":"n484","loc":[-85.634324,41.942131]},"n4840":{"id":"n4840","loc":[-85.624859,41.949284]},"n4841":{"id":"n4841","loc":[-85.624788,41.949262]},"n4842":{"id":"n4842","loc":[-85.62402,41.949265]},"n4843":{"id":"n4843","loc":[-85.610382,41.954663]},"n4844":{"id":"n4844","loc":[-85.605675,41.954667]},"n4845":{"id":"n4845","loc":[-85.605669,41.949407]},"n4846":{"id":"n4846","loc":[-85.610376,41.949404]},"n4847":{"id":"n4847","loc":[-85.605552,41.958536]},"n4848":{"id":"n4848","loc":[-85.595755,41.958588]},"n4849":{"id":"n4849","loc":[-85.595732,41.956419]},"n485":{"id":"n485","loc":[-85.634211,41.941374]},"n4850":{"id":"n4850","loc":[-85.596908,41.955605]},"n4851":{"id":"n4851","loc":[-85.597723,41.955596]},"n4852":{"id":"n4852","loc":[-85.597715,41.954967]},"n4853":{"id":"n4853","loc":[-85.5874,41.955018]},"n4854":{"id":"n4854","loc":[-85.586615,41.955124]},"n4855":{"id":"n4855","loc":[-85.58613,41.955293]},"n4856":{"id":"n4856","loc":[-85.586166,41.962122]},"n4857":{"id":"n4857","loc":[-85.587008,41.955052]},"n4858":{"id":"n4858","loc":[-85.591685,41.95499]},"n4859":{"id":"n4859","loc":[-85.591718,41.956649]},"n486":{"id":"n486","loc":[-85.634085,41.940704]},"n4860":{"id":"n4860","loc":[-85.591133,41.956649]},"n4861":{"id":"n4861","loc":[-85.591061,41.95582]},"n4862":{"id":"n4862","loc":[-85.590677,41.95613]},"n4863":{"id":"n4863","loc":[-85.590826,41.956369]},"n4864":{"id":"n4864","loc":[-85.591016,41.954991]},"n4865":{"id":"n4865","loc":[-85.587656,41.954855]},"n4866":{"id":"n4866","loc":[-85.5964,41.955274]},"n4867":{"id":"n4867","loc":[-85.58776,41.96178]},"n4868":{"id":"n4868","loc":[-85.601172,41.960448]},"n4869":{"id":"n4869","loc":[-85.589489,41.960478]},"n487":{"id":"n487","loc":[-85.635567,41.940944]},"n4870":{"id":"n4870","loc":[-85.586664,41.960493]},"n4871":{"id":"n4871","loc":[-85.591227,41.95676]},"n4872":{"id":"n4872","loc":[-85.589424,41.958093]},"n4873":{"id":"n4873","loc":[-85.588779,41.957611]},"n4874":{"id":"n4874","loc":[-85.590583,41.956278]},"n4875":{"id":"n4875","loc":[-85.590759,41.957106]},"n4876":{"id":"n4876","loc":[-85.592213,41.958218]},"n4877":{"id":"n4877","loc":[-85.592262,41.958279]},"n4878":{"id":"n4878","loc":[-85.592304,41.958358]},"n4879":{"id":"n4879","loc":[-85.592351,41.95849]},"n488":{"id":"n488","loc":[-85.635542,41.940919]},"n4880":{"id":"n4880","loc":[-85.592363,41.958605]},"n4881":{"id":"n4881","loc":[-85.592383,41.96047]},"n4882":{"id":"n4882","loc":[-85.592376,41.959808]},"n4883":{"id":"n4883","loc":[-85.600825,41.959779]},"n4884":{"id":"n4884","loc":[-85.601084,41.959844]},"n4885":{"id":"n4885","loc":[-85.601144,41.959908]},"n4886":{"id":"n4886","loc":[-85.601164,41.960008]},"n4887":{"id":"n4887","loc":[-85.601162,41.960125]},"n4888":{"id":"n4888","loc":[-85.601134,41.960221]},"n4889":{"id":"n4889","loc":[-85.600993,41.960353]},"n489":{"id":"n489","loc":[-85.635514,41.940906]},"n4890":{"id":"n4890","loc":[-85.600794,41.960449]},"n4891":{"id":"n4891","loc":[-85.60098,41.959792]},"n4892":{"id":"n4892","loc":[-85.601067,41.960294]},"n4893":{"id":"n4893","loc":[-85.596829,41.959793]},"n4894":{"id":"n4894","loc":[-85.596839,41.960459]},"n4895":{"id":"n4895","loc":[-85.589364,41.958048]},"n4896":{"id":"n4896","loc":[-85.587374,41.959511]},"n4897":{"id":"n4897","loc":[-85.587286,41.959564]},"n4898":{"id":"n4898","loc":[-85.587163,41.959632]},"n4899":{"id":"n4899","loc":[-85.586694,41.959865]},"n49":{"id":"n49","loc":[-85.637127,41.942757]},"n490":{"id":"n490","loc":[-85.635469,41.940896]},"n4900":{"id":"n4900","loc":[-85.586634,41.959921]},"n4901":{"id":"n4901","loc":[-85.586607,41.960001]},"n4902":{"id":"n4902","loc":[-85.586599,41.960099]},"n4903":{"id":"n4903","loc":[-85.586602,41.96034]},"n4904":{"id":"n4904","loc":[-85.586669,41.960439]},"n4905":{"id":"n4905","loc":[-85.586758,41.960493]},"n4906":{"id":"n4906","loc":[-85.586618,41.960391]},"n4907":{"id":"n4907","loc":[-85.591201,41.956352]},"n4908":{"id":"n4908","loc":[-85.59112,41.954843]},"n4909":{"id":"n4909","loc":[-85.591536,41.956349]},"n491":{"id":"n491","loc":[-85.635667,41.940826]},"n4910":{"id":"n4910","loc":[-85.590953,41.956354]},"n4911":{"id":"n4911","loc":[-85.591468,41.956406]},"n4912":{"id":"n4912","loc":[-85.591469,41.956478]},"n4913":{"id":"n4913","loc":[-85.591123,41.956481]},"n4914":{"id":"n4914","loc":[-85.591121,41.956409]},"n4915":{"id":"n4915","loc":[-85.590826,41.955954]},"n4916":{"id":"n4916","loc":[-85.590612,41.956115]},"n4917":{"id":"n4917","loc":[-85.590402,41.955962]},"n4918":{"id":"n4918","loc":[-85.590622,41.955804]},"n4919":{"id":"n4919","loc":[-85.59011,41.956502]},"n492":{"id":"n492","loc":[-85.636197,41.940599]},"n4920":{"id":"n4920","loc":[-85.589877,41.956668]},"n4921":{"id":"n4921","loc":[-85.589777,41.95659]},"n4922":{"id":"n4922","loc":[-85.59001,41.956424]},"n4923":{"id":"n4923","loc":[-85.589595,41.956427]},"n4924":{"id":"n4924","loc":[-85.589434,41.956549]},"n4925":{"id":"n4925","loc":[-85.589262,41.956424]},"n4926":{"id":"n4926","loc":[-85.589422,41.956302]},"n4927":{"id":"n4927","loc":[-85.589358,41.956286]},"n4928":{"id":"n4928","loc":[-85.5892,41.956408]},"n4929":{"id":"n4929","loc":[-85.589032,41.956288]},"n493":{"id":"n493","loc":[-85.6362,41.940686]},"n4930":{"id":"n4930","loc":[-85.58919,41.956166]},"n4931":{"id":"n4931","loc":[-85.589165,41.956132]},"n4932":{"id":"n4932","loc":[-85.589002,41.956253]},"n4933":{"id":"n4933","loc":[-85.588826,41.956122]},"n4934":{"id":"n4934","loc":[-85.588989,41.956001]},"n4935":{"id":"n4935","loc":[-85.588673,41.955757]},"n4936":{"id":"n4936","loc":[-85.588502,41.955882]},"n4937":{"id":"n4937","loc":[-85.588339,41.955759]},"n4938":{"id":"n4938","loc":[-85.58851,41.955633]},"n4939":{"id":"n4939","loc":[-85.590382,41.955892]},"n494":{"id":"n494","loc":[-85.635969,41.94069]},"n4940":{"id":"n4940","loc":[-85.589923,41.956231]},"n4941":{"id":"n4941","loc":[-85.58984,41.956168]},"n4942":{"id":"n4942","loc":[-85.5903,41.95583]},"n4943":{"id":"n4943","loc":[-85.589636,41.956038]},"n4944":{"id":"n4944","loc":[-85.589546,41.956105]},"n4945":{"id":"n4945","loc":[-85.589045,41.955729]},"n4946":{"id":"n4946","loc":[-85.589135,41.955662]},"n4947":{"id":"n4947","loc":[-85.590718,41.955293]},"n4948":{"id":"n4948","loc":[-85.590718,41.955374]},"n4949":{"id":"n4949","loc":[-85.589211,41.955369]},"n495":{"id":"n495","loc":[-85.635965,41.940561]},"n4950":{"id":"n4950","loc":[-85.589212,41.955287]},"n4951":{"id":"n4951","loc":[-85.589675,41.956817]},"n4952":{"id":"n4952","loc":[-85.58947,41.95697]},"n4953":{"id":"n4953","loc":[-85.589219,41.956784]},"n4954":{"id":"n4954","loc":[-85.589425,41.95663]},"n4955":{"id":"n4955","loc":[-85.589373,41.95702]},"n4956":{"id":"n4956","loc":[-85.589171,41.957172]},"n4957":{"id":"n4957","loc":[-85.588962,41.957019]},"n4958":{"id":"n4958","loc":[-85.589164,41.956867]},"n4959":{"id":"n4959","loc":[-85.588881,41.955006]},"n496":{"id":"n496","loc":[-85.636031,41.94056]},"n4960":{"id":"n4960","loc":[-85.588804,41.955006]},"n4961":{"id":"n4961","loc":[-85.604773,41.954521]},"n4962":{"id":"n4962","loc":[-85.601603,41.954527]},"n4963":{"id":"n4963","loc":[-85.600823,41.954169]},"n4964":{"id":"n4964","loc":[-85.600828,41.950191]},"n4965":{"id":"n4965","loc":[-85.601673,41.949457]},"n4966":{"id":"n4966","loc":[-85.604464,41.949488]},"n4967":{"id":"n4967","loc":[-85.60538,41.950212]},"n4968":{"id":"n4968","loc":[-85.605395,41.954108]},"n4969":{"id":"n4969","loc":[-85.604771,41.954109]},"n497":{"id":"n497","loc":[-85.636032,41.940602]},"n4970":{"id":"n4970","loc":[-85.600613,41.953916]},"n4971":{"id":"n4971","loc":[-85.599758,41.954649]},"n4972":{"id":"n4972","loc":[-85.591194,41.954663]},"n4973":{"id":"n4973","loc":[-85.591182,41.950465]},"n4974":{"id":"n4974","loc":[-85.591871,41.950464]},"n4975":{"id":"n4975","loc":[-85.591868,41.949209]},"n4976":{"id":"n4976","loc":[-85.592155,41.949209]},"n4977":{"id":"n4977","loc":[-85.592155,41.94848]},"n4978":{"id":"n4978","loc":[-85.600615,41.948482]},"n4979":{"id":"n4979","loc":[-85.605421,41.949378]},"n498":{"id":"n498","loc":[-85.635776,41.940583]},"n4980":{"id":"n4980","loc":[-85.600614,41.949373]},"n4981":{"id":"n4981","loc":[-85.601316,41.94849]},"n4982":{"id":"n4982","loc":[-85.601592,41.947641]},"n4983":{"id":"n4983","loc":[-85.60395,41.947618]},"n4984":{"id":"n4984","loc":[-85.603973,41.948114]},"n4985":{"id":"n4985","loc":[-85.605398,41.948103]},"n4986":{"id":"n4986","loc":[-85.614017,41.965566]},"n4987":{"id":"n4987","loc":[-85.605787,41.965619]},"n4988":{"id":"n4988","loc":[-85.60577,41.963821]},"n4989":{"id":"n4989","loc":[-85.612886,41.963808]},"n499":{"id":"n499","loc":[-85.63589,41.940578]},"n4990":{"id":"n4990","loc":[-85.613207,41.963705]},"n4991":{"id":"n4991","loc":[-85.613511,41.963525]},"n4992":{"id":"n4992","loc":[-85.613667,41.963305]},"n4993":{"id":"n4993","loc":[-85.613779,41.962983]},"n4994":{"id":"n4994","loc":[-85.613797,41.959709]},"n4995":{"id":"n4995","loc":[-85.613663,41.95936]},"n4996":{"id":"n4996","loc":[-85.61339,41.959064]},"n4997":{"id":"n4997","loc":[-85.610503,41.956898]},"n4998":{"id":"n4998","loc":[-85.610485,41.956595]},"n4999":{"id":"n4999","loc":[-85.613892,41.956621]},"n5":{"id":"n5","loc":[-85.622744,41.95268]},"n50":{"id":"n50","loc":[-85.636673,41.943143]},"n500":{"id":"n500","loc":[-85.636198,41.940578]},"n5000":{"id":"n5000","loc":[-85.613866,41.958574]},"n5001":{"id":"n5001","loc":[-85.615262,41.958561]},"n5002":{"id":"n5002","loc":[-85.615279,41.959541]},"n5003":{"id":"n5003","loc":[-85.615314,41.95597]},"n5004":{"id":"n5004","loc":[-85.613887,41.955988]},"n5005":{"id":"n5005","loc":[-85.613074,41.962244]},"n5006":{"id":"n5006","loc":[-85.611678,41.963354]},"n5007":{"id":"n5007","loc":[-85.611678,41.963487]},"n5008":{"id":"n5008","loc":[-85.606906,41.963502]},"n5009":{"id":"n5009","loc":[-85.605777,41.962657]},"n501":{"id":"n501","loc":[-85.636251,41.940584]},"n5010":{"id":"n5010","loc":[-85.605711,41.9599]},"n5011":{"id":"n5011","loc":[-85.608139,41.9585]},"n5012":{"id":"n5012","loc":[-85.60814,41.956306]},"n5013":{"id":"n5013","loc":[-85.608854,41.95581]},"n5014":{"id":"n5014","loc":[-85.610039,41.955883]},"n5015":{"id":"n5015","loc":[-85.610068,41.956754]},"n5016":{"id":"n5016","loc":[-85.613058,41.959411]},"n5017":{"id":"n5017","loc":[-85.610234,41.957068]},"n5018":{"id":"n5018","loc":[-85.609826,41.95581]},"n5019":{"id":"n5019","loc":[-85.606987,41.958505]},"n502":{"id":"n502","loc":[-85.636279,41.940605]},"n5020":{"id":"n5020","loc":[-85.606498,41.958846]},"n5021":{"id":"n5021","loc":[-85.606013,41.959342]},"n5022":{"id":"n5022","loc":[-85.614553,41.961581]},"n5023":{"id":"n5023","loc":[-85.61465,41.96214]},"n5024":{"id":"n5024","loc":[-85.615277,41.962442]},"n5025":{"id":"n5025","loc":[-85.615451,41.962972]},"n5026":{"id":"n5026","loc":[-85.614355,41.964826]},"n5027":{"id":"n5027","loc":[-85.615133,41.964589]},"n5028":{"id":"n5028","loc":[-85.615342,41.963818]},"n5029":{"id":"n5029","loc":[-85.615971,41.963792]},"n503":{"id":"n503","loc":[-85.636285,41.940633]},"n5030":{"id":"n5030","loc":[-85.615751,41.963122]},"n5031":{"id":"n5031","loc":[-85.616575,41.963123]},"n5032":{"id":"n5032","loc":[-85.612527,41.963846]},"n5033":{"id":"n5033","loc":[-85.630653,41.940709]},"n5034":{"id":"n5034","loc":[-85.629858,41.939568]},"n5035":{"id":"n5035","loc":[-85.629847,41.937926]},"n504":{"id":"n504","loc":[-85.636281,41.940662]},"n505":{"id":"n505","loc":[-85.636266,41.940688]},"n506":{"id":"n506","loc":[-85.636236,41.940701]},"n507":{"id":"n507","loc":[-85.63619,41.940706]},"n508":{"id":"n508","loc":[-85.635892,41.940707]},"n509":{"id":"n509","loc":[-85.635777,41.9407]},"n51":{"id":"n51","loc":[-85.636673,41.942864]},"n510":{"id":"n510","loc":[-85.636044,41.940578]},"n511":{"id":"n511","loc":[-85.635946,41.940578]},"n512":{"id":"n512","loc":[-85.636475,41.940732]},"n513":{"id":"n513","loc":[-85.636475,41.940777]},"n514":{"id":"n514","loc":[-85.636405,41.940777]},"n515":{"id":"n515","loc":[-85.636405,41.940732]},"n516":{"id":"n516","loc":[-85.636471,41.940916]},"n517":{"id":"n517","loc":[-85.636471,41.940961]},"n518":{"id":"n518","loc":[-85.636404,41.940961]},"n519":{"id":"n519","loc":[-85.636404,41.940916]},"n52":{"id":"n52","loc":[-85.636227,41.942864]},"n520":{"id":"n520","loc":[-85.636286,41.941127]},"n521":{"id":"n521","loc":[-85.636203,41.941126]},"n522":{"id":"n522","loc":[-85.636204,41.941083]},"n523":{"id":"n523","loc":[-85.636287,41.941083]},"n524":{"id":"n524","loc":[-85.636124,41.941064]},"n525":{"id":"n525","loc":[-85.636,41.941065]},"n526":{"id":"n526","loc":[-85.636,41.940964]},"n527":{"id":"n527","loc":[-85.636045,41.940964]},"n528":{"id":"n528","loc":[-85.636045,41.940928]},"n529":{"id":"n529","loc":[-85.636111,41.940928]},"n53":{"id":"n53","loc":[-85.636227,41.943143]},"n530":{"id":"n530","loc":[-85.636111,41.940961]},"n531":{"id":"n531","loc":[-85.636123,41.940961]},"n532":{"id":"n532","loc":[-85.636124,41.940997]},"n533":{"id":"n533","loc":[-85.636164,41.940997]},"n534":{"id":"n534","loc":[-85.636164,41.941044]},"n535":{"id":"n535","loc":[-85.636124,41.941044]},"n536":{"id":"n536","loc":[-85.636534,41.941256]},"n537":{"id":"n537","loc":[-85.63645,41.941246]},"n538":{"id":"n538","loc":[-85.636462,41.941189]},"n539":{"id":"n539","loc":[-85.636546,41.941199]},"n54":{"id":"n54","loc":[-85.636198,41.943119]},"n540":{"id":"n540","loc":[-85.636802,41.941226]},"n541":{"id":"n541","loc":[-85.636701,41.941215]},"n542":{"id":"n542","loc":[-85.636709,41.941174]},"n543":{"id":"n543","loc":[-85.636656,41.941168]},"n544":{"id":"n544","loc":[-85.636666,41.941122]},"n545":{"id":"n545","loc":[-85.636781,41.941136]},"n546":{"id":"n546","loc":[-85.636774,41.94117]},"n547":{"id":"n547","loc":[-85.636812,41.941175]},"n548":{"id":"n548","loc":[-85.636803,41.941047]},"n549":{"id":"n549","loc":[-85.636785,41.941047]},"n55":{"id":"n55","loc":[-85.635945,41.94312]},"n550":{"id":"n550","loc":[-85.636785,41.941058]},"n551":{"id":"n551","loc":[-85.636644,41.941059]},"n552":{"id":"n552","loc":[-85.636644,41.941038]},"n553":{"id":"n553","loc":[-85.636581,41.941039]},"n554":{"id":"n554","loc":[-85.636581,41.940995]},"n555":{"id":"n555","loc":[-85.636746,41.940995]},"n556":{"id":"n556","loc":[-85.636746,41.940978]},"n557":{"id":"n557","loc":[-85.636803,41.940978]},"n558":{"id":"n558","loc":[-85.636781,41.940768]},"n559":{"id":"n559","loc":[-85.636783,41.940828]},"n56":{"id":"n56","loc":[-85.635943,41.942909]},"n560":{"id":"n560","loc":[-85.636761,41.940828]},"n561":{"id":"n561","loc":[-85.636762,41.940857]},"n562":{"id":"n562","loc":[-85.636641,41.940859]},"n563":{"id":"n563","loc":[-85.63664,41.940805]},"n564":{"id":"n564","loc":[-85.636676,41.940804]},"n565":{"id":"n565","loc":[-85.636675,41.940769]},"n566":{"id":"n566","loc":[-85.636733,41.94033]},"n567":{"id":"n567","loc":[-85.636471,41.940334]},"n568":{"id":"n568","loc":[-85.636469,41.940262]},"n569":{"id":"n569","loc":[-85.636731,41.940257]},"n57":{"id":"n57","loc":[-85.636227,41.942909]},"n570":{"id":"n570","loc":[-85.636798,41.940419]},"n571":{"id":"n571","loc":[-85.6368,41.940524]},"n572":{"id":"n572","loc":[-85.63664,41.940526]},"n573":{"id":"n573","loc":[-85.636638,41.940421]},"n574":{"id":"n574","loc":[-85.636372,41.940551]},"n575":{"id":"n575","loc":[-85.636338,41.94055]},"n576":{"id":"n576","loc":[-85.636339,41.940524]},"n577":{"id":"n577","loc":[-85.636373,41.940525]},"n578":{"id":"n578","loc":[-85.636388,41.940435]},"n579":{"id":"n579","loc":[-85.636222,41.940436]},"n58":{"id":"n58","loc":[-85.63627,41.943175]},"n580":{"id":"n580","loc":[-85.636222,41.940366]},"n581":{"id":"n581","loc":[-85.636387,41.940365]},"n582":{"id":"n582","loc":[-85.636158,41.940482]},"n583":{"id":"n583","loc":[-85.635963,41.940484]},"n584":{"id":"n584","loc":[-85.635961,41.940399]},"n585":{"id":"n585","loc":[-85.636156,41.940397]},"n586":{"id":"n586","loc":[-85.635987,41.940314]},"n587":{"id":"n587","loc":[-85.635987,41.940268]},"n588":{"id":"n588","loc":[-85.635968,41.940268]},"n589":{"id":"n589","loc":[-85.635967,41.940212]},"n59":{"id":"n59","loc":[-85.635531,41.943176]},"n590":{"id":"n590","loc":[-85.636082,41.940211]},"n591":{"id":"n591","loc":[-85.636083,41.94027]},"n592":{"id":"n592","loc":[-85.636064,41.94027]},"n593":{"id":"n593","loc":[-85.636064,41.940313]},"n594":{"id":"n594","loc":[-85.638071,41.941562]},"n595":{"id":"n595","loc":[-85.637953,41.941562]},"n596":{"id":"n596","loc":[-85.637952,41.941522]},"n597":{"id":"n597","loc":[-85.637876,41.941523]},"n598":{"id":"n598","loc":[-85.637876,41.941471]},"n599":{"id":"n599","loc":[-85.638035,41.94147]},"n6":{"id":"n6","loc":[-85.624925,41.950604]},"n60":{"id":"n60","loc":[-85.63542,41.942883]},"n600":{"id":"n600","loc":[-85.638035,41.941513]},"n601":{"id":"n601","loc":[-85.638071,41.941512]},"n602":{"id":"n602","loc":[-85.637038,41.942543],"tags":{"crossing":"zebra","highway":"crossing"}},"n603":{"id":"n603","loc":[-85.637134,41.942542]},"n604":{"id":"n604","loc":[-85.638122,41.942532]},"n605":{"id":"n605","loc":[-85.638121,41.942478]},"n606":{"id":"n606","loc":[-85.638104,41.941424]},"n607":{"id":"n607","loc":[-85.637115,41.941438]},"n608":{"id":"n608","loc":[-85.637133,41.942453]},"n609":{"id":"n609","loc":[-85.637429,41.942004]},"n61":{"id":"n61","loc":[-85.635701,41.942802]},"n610":{"id":"n610","loc":[-85.637125,41.942004]},"n611":{"id":"n611","loc":[-85.637022,41.942004]},"n612":{"id":"n612","loc":[-85.635952,41.943579]},"n613":{"id":"n613","loc":[-85.635872,41.943594]},"n614":{"id":"n614","loc":[-85.635857,41.943551]},"n615":{"id":"n615","loc":[-85.635937,41.943535]},"n616":{"id":"n616","loc":[-85.63671,41.94344]},"n617":{"id":"n617","loc":[-85.636427,41.94334]},"n618":{"id":"n618","loc":[-85.635353,41.943279]},"n619":{"id":"n619","loc":[-85.635319,41.943257]},"n62":{"id":"n62","loc":[-85.6358,41.942997]},"n620":{"id":"n620","loc":[-85.638786,41.943105]},"n621":{"id":"n621","loc":[-85.634957,41.943146]},"n622":{"id":"n622","loc":[-85.635012,41.943119]},"n623":{"id":"n623","loc":[-85.632409,41.944222]},"n624":{"id":"n624","loc":[-85.631863,41.944749]},"n625":{"id":"n625","loc":[-85.631915,41.944722]},"n626":{"id":"n626","loc":[-85.631884,41.94464]},"n627":{"id":"n627","loc":[-85.631792,41.944359]},"n628":{"id":"n628","loc":[-85.631817,41.944703]},"n629":{"id":"n629","loc":[-85.633464,41.945787]},"n63":{"id":"n63","loc":[-85.635808,41.943176]},"n630":{"id":"n630","loc":[-85.633583,41.945919]},"n631":{"id":"n631","loc":[-85.63382,41.945698]},"n632":{"id":"n632","loc":[-85.633681,41.945571]},"n633":{"id":"n633","loc":[-85.634217,41.946824]},"n634":{"id":"n634","loc":[-85.634271,41.946836]},"n635":{"id":"n635","loc":[-85.634319,41.94573]},"n636":{"id":"n636","loc":[-85.634377,41.945672]},"n637":{"id":"n637","loc":[-85.634909,41.945354]},"n638":{"id":"n638","loc":[-85.634726,41.945493],"tags":{"artwork_type":"mural","tourism":"artwork"}},"n639":{"id":"n639","loc":[-85.63546,41.945612]},"n64":{"id":"n64","loc":[-85.63631,41.943253]},"n640":{"id":"n640","loc":[-85.635561,41.945493]},"n641":{"id":"n641","loc":[-85.635417,41.945565]},"n642":{"id":"n642","loc":[-85.635315,41.945583]},"n643":{"id":"n643","loc":[-85.63506,41.945383]},"n644":{"id":"n644","loc":[-85.635198,41.945199]},"n645":{"id":"n645","loc":[-85.635361,41.94558]},"n646":{"id":"n646","loc":[-85.635017,41.945066]},"n647":{"id":"n647","loc":[-85.634779,41.945206]},"n648":{"id":"n648","loc":[-85.63425,41.945655]},"n649":{"id":"n649","loc":[-85.634247,41.945631]},"n65":{"id":"n65","loc":[-85.635398,41.943259]},"n650":{"id":"n650","loc":[-85.634889,41.945921]},"n651":{"id":"n651","loc":[-85.634889,41.945939]},"n652":{"id":"n652","loc":[-85.634889,41.945761]},"n653":{"id":"n653","loc":[-85.634889,41.945778]},"n654":{"id":"n654","loc":[-85.635112,41.945715]},"n655":{"id":"n655","loc":[-85.635025,41.945714]},"n656":{"id":"n656","loc":[-85.635027,41.945761]},"n657":{"id":"n657","loc":[-85.635438,41.945665]},"n658":{"id":"n658","loc":[-85.635416,41.945676]},"n659":{"id":"n659","loc":[-85.635401,41.945709]},"n66":{"id":"n66","loc":[-85.635336,41.943036]},"n660":{"id":"n660","loc":[-85.635271,41.945566]},"n661":{"id":"n661","loc":[-85.636106,41.946268]},"n662":{"id":"n662","loc":[-85.635867,41.946747]},"n663":{"id":"n663","loc":[-85.636476,41.946797]},"n664":{"id":"n664","loc":[-85.63651,41.946796]},"n665":{"id":"n665","loc":[-85.635367,41.946389]},"n666":{"id":"n666","loc":[-85.635367,41.946437]},"n667":{"id":"n667","loc":[-85.634787,41.946441]},"n668":{"id":"n668","loc":[-85.6358,41.946243]},"n669":{"id":"n669","loc":[-85.635784,41.94622]},"n67":{"id":"n67","loc":[-85.635911,41.942899]},"n670":{"id":"n670","loc":[-85.635727,41.946195]},"n671":{"id":"n671","loc":[-85.635708,41.946588]},"n672":{"id":"n672","loc":[-85.635648,41.946561]},"n673":{"id":"n673","loc":[-85.635624,41.946555]},"n674":{"id":"n674","loc":[-85.635417,41.946559]},"n675":{"id":"n675","loc":[-85.634866,41.946561]},"n676":{"id":"n676","loc":[-85.634866,41.946543]},"n677":{"id":"n677","loc":[-85.635085,41.946546]},"n678":{"id":"n678","loc":[-85.635085,41.946554]},"n679":{"id":"n679","loc":[-85.634584,41.94488]},"n68":{"id":"n68","loc":[-85.635915,41.943156]},"n680":{"id":"n680","loc":[-85.634557,41.944882]},"n681":{"id":"n681","loc":[-85.634455,41.944943]},"n682":{"id":"n682","loc":[-85.634305,41.944968]},"n683":{"id":"n683","loc":[-85.634261,41.944927]},"n684":{"id":"n684","loc":[-85.634132,41.944741]},"n685":{"id":"n685","loc":[-85.633705,41.944759]},"n686":{"id":"n686","loc":[-85.633918,41.944616]},"n687":{"id":"n687","loc":[-85.633974,41.944663]},"n688":{"id":"n688","loc":[-85.6336,41.944665]},"n689":{"id":"n689","loc":[-85.633817,41.944528]},"n69":{"id":"n69","loc":[-85.63631,41.943157]},"n690":{"id":"n690","loc":[-85.633889,41.944485]},"n691":{"id":"n691","loc":[-85.633931,41.944525]},"n692":{"id":"n692","loc":[-85.633864,41.944563]},"n693":{"id":"n693","loc":[-85.633456,41.944524]},"n694":{"id":"n694","loc":[-85.633676,41.944399]},"n695":{"id":"n695","loc":[-85.633352,41.944415]},"n696":{"id":"n696","loc":[-85.633655,41.944234]},"n697":{"id":"n697","loc":[-85.633761,41.94435]},"n698":{"id":"n698","loc":[-85.633254,41.944318]},"n699":{"id":"n699","loc":[-85.633472,41.944188]},"n7":{"id":"n7","loc":[-85.638791,41.943231]},"n70":{"id":"n70","loc":[-85.63579,41.942967]},"n700":{"id":"n700","loc":[-85.633524,41.944237]},"n701":{"id":"n701","loc":[-85.633583,41.944202]},"n702":{"id":"n702","loc":[-85.633632,41.944247]},"n703":{"id":"n703","loc":[-85.633165,41.944228]},"n704":{"id":"n704","loc":[-85.633388,41.944105]},"n705":{"id":"n705","loc":[-85.633117,41.944175]},"n706":{"id":"n706","loc":[-85.633302,41.944077]},"n707":{"id":"n707","loc":[-85.633352,41.944126]},"n708":{"id":"n708","loc":[-85.633052,41.944107]},"n709":{"id":"n709","loc":[-85.633237,41.944009]},"n71":{"id":"n71","loc":[-85.637506,41.942824]},"n710":{"id":"n710","loc":[-85.633187,41.943955]},"n711":{"id":"n711","loc":[-85.633,41.944054]},"n712":{"id":"n712","loc":[-85.633155,41.944265]},"n713":{"id":"n713","loc":[-85.633669,41.944765]},"n714":{"id":"n714","loc":[-85.634468,41.945503]},"n715":{"id":"n715","loc":[-85.63455,41.945566]},"n716":{"id":"n716","loc":[-85.634737,41.945729]},"n717":{"id":"n717","loc":[-85.634753,41.945752]},"n718":{"id":"n718","loc":[-85.634756,41.945781]},"n719":{"id":"n719","loc":[-85.634758,41.945978]},"n72":{"id":"n72","loc":[-85.637511,41.943056]},"n720":{"id":"n720","loc":[-85.634363,41.945548],"tags":{"crossing":"zebra","highway":"crossing"}},"n721":{"id":"n721","loc":[-85.634245,41.945599]},"n722":{"id":"n722","loc":[-85.633474,41.944889]},"n723":{"id":"n723","loc":[-85.632997,41.944418]},"n724":{"id":"n724","loc":[-85.63278,41.944183]},"n725":{"id":"n725","loc":[-85.63331,41.944429]},"n726":{"id":"n726","loc":[-85.633568,41.944829],"tags":{"crossing":"zebra","highway":"crossing"}},"n727":{"id":"n727","loc":[-85.634669,41.94567]},"n728":{"id":"n728","loc":[-85.634462,41.945787]},"n729":{"id":"n729","loc":[-85.634272,41.945625]},"n73":{"id":"n73","loc":[-85.637361,41.943058]},"n730":{"id":"n730","loc":[-85.634344,41.945699],"tags":{"crossing":"zebra","highway":"crossing"}},"n731":{"id":"n731","loc":[-85.634426,41.945783]},"n732":{"id":"n732","loc":[-85.632425,41.944137]},"n733":{"id":"n733","loc":[-85.632302,41.944192]},"n734":{"id":"n734","loc":[-85.632762,41.944174]},"n735":{"id":"n735","loc":[-85.632713,41.944179]},"n736":{"id":"n736","loc":[-85.632411,41.944327]},"n737":{"id":"n737","loc":[-85.632362,41.944341]},"n738":{"id":"n738","loc":[-85.632236,41.944204]},"n739":{"id":"n739","loc":[-85.634939,41.942165]},"n74":{"id":"n74","loc":[-85.637356,41.942825]},"n740":{"id":"n740","loc":[-85.635079,41.941535]},"n741":{"id":"n741","loc":[-85.635112,41.941595]},"n742":{"id":"n742","loc":[-85.635113,41.941633]},"n743":{"id":"n743","loc":[-85.635067,41.941652]},"n744":{"id":"n744","loc":[-85.634989,41.941651]},"n745":{"id":"n745","loc":[-85.634921,41.941609]},"n746":{"id":"n746","loc":[-85.634881,41.941544]},"n747":{"id":"n747","loc":[-85.635537,41.940939]},"n748":{"id":"n748","loc":[-85.635573,41.941048]},"n749":{"id":"n749","loc":[-85.635453,41.94091]},"n75":{"id":"n75","loc":[-85.638097,41.942833]},"n750":{"id":"n750","loc":[-85.635319,41.940943]},"n751":{"id":"n751","loc":[-85.637057,41.943224]},"n752":{"id":"n752","loc":[-85.636989,41.943296]},"n753":{"id":"n753","loc":[-85.636851,41.943299]},"n754":{"id":"n754","loc":[-85.636848,41.94322]},"n755":{"id":"n755","loc":[-85.636986,41.943217]},"n756":{"id":"n756","loc":[-85.637569,41.943454]},"n757":{"id":"n757","loc":[-85.637437,41.943458]},"n758":{"id":"n758","loc":[-85.637432,41.943384]},"n759":{"id":"n759","loc":[-85.637564,41.94338]},"n76":{"id":"n76","loc":[-85.638098,41.942912]},"n760":{"id":"n760","loc":[-85.637213,41.943378]},"n761":{"id":"n761","loc":[-85.637217,41.943435]},"n762":{"id":"n762","loc":[-85.637235,41.943434]},"n763":{"id":"n763","loc":[-85.637237,41.943465]},"n764":{"id":"n764","loc":[-85.637424,41.943459]},"n765":{"id":"n765","loc":[-85.637418,41.943371]},"n766":{"id":"n766","loc":[-85.638094,41.943149]},"n767":{"id":"n767","loc":[-85.638096,41.943201]},"n768":{"id":"n768","loc":[-85.638041,41.943202]},"n769":{"id":"n769","loc":[-85.638042,41.943216]},"n77":{"id":"n77","loc":[-85.637705,41.942913]},"n770":{"id":"n770","loc":[-85.637927,41.943218]},"n771":{"id":"n771","loc":[-85.637926,41.943201]},"n772":{"id":"n772","loc":[-85.637897,41.943201]},"n773":{"id":"n773","loc":[-85.637896,41.943155]},"n774":{"id":"n774","loc":[-85.637962,41.943153]},"n775":{"id":"n775","loc":[-85.637962,41.943134]},"n776":{"id":"n776","loc":[-85.638017,41.943132]},"n777":{"id":"n777","loc":[-85.638018,41.943151]},"n778":{"id":"n778","loc":[-85.638045,41.943289]},"n779":{"id":"n779","loc":[-85.638048,41.943363]},"n78":{"id":"n78","loc":[-85.637705,41.942834]},"n780":{"id":"n780","loc":[-85.637842,41.943367]},"n781":{"id":"n781","loc":[-85.637839,41.943296]},"n782":{"id":"n782","loc":[-85.637896,41.943295]},"n783":{"id":"n783","loc":[-85.637897,41.943314]},"n784":{"id":"n784","loc":[-85.637957,41.943312]},"n785":{"id":"n785","loc":[-85.637957,41.943291]},"n786":{"id":"n786","loc":[-85.637816,41.943375]},"n787":{"id":"n787","loc":[-85.637815,41.943416]},"n788":{"id":"n788","loc":[-85.637715,41.943415]},"n789":{"id":"n789","loc":[-85.637716,41.943374]},"n79":{"id":"n79","loc":[-85.638071,41.942298]},"n790":{"id":"n790","loc":[-85.637912,41.943545]},"n791":{"id":"n791","loc":[-85.637909,41.943479]},"n792":{"id":"n792","loc":[-85.637967,41.943477]},"n793":{"id":"n793","loc":[-85.637967,41.94346]},"n794":{"id":"n794","loc":[-85.638077,41.943457]},"n795":{"id":"n795","loc":[-85.638078,41.943473]},"n796":{"id":"n796","loc":[-85.638124,41.943471]},"n797":{"id":"n797","loc":[-85.638126,41.943514]},"n798":{"id":"n798","loc":[-85.638079,41.943515]},"n799":{"id":"n799","loc":[-85.638079,41.943532]},"n8":{"id":"n8","loc":[-85.635241,41.941948]},"n80":{"id":"n80","loc":[-85.638074,41.942431]},"n800":{"id":"n800","loc":[-85.638028,41.943534]},"n801":{"id":"n801","loc":[-85.638028,41.943542]},"n802":{"id":"n802","loc":[-85.638845,41.942983]},"n803":{"id":"n803","loc":[-85.638846,41.94305]},"n804":{"id":"n804","loc":[-85.638661,41.943052]},"n805":{"id":"n805","loc":[-85.63866,41.942984]},"n806":{"id":"n806","loc":[-85.638579,41.942753]},"n807":{"id":"n807","loc":[-85.638445,41.942755]},"n808":{"id":"n808","loc":[-85.638452,41.942978]},"n809":{"id":"n809","loc":[-85.638545,41.942976]},"n81":{"id":"n81","loc":[-85.637836,41.942433]},"n810":{"id":"n810","loc":[-85.638543,41.942935]},"n811":{"id":"n811","loc":[-85.638571,41.942934]},"n812":{"id":"n812","loc":[-85.63857,41.942901]},"n813":{"id":"n813","loc":[-85.638611,41.9429]},"n814":{"id":"n814","loc":[-85.638607,41.942769]},"n815":{"id":"n815","loc":[-85.63858,41.94277]},"n816":{"id":"n816","loc":[-85.638597,41.942614]},"n817":{"id":"n817","loc":[-85.638601,41.94273]},"n818":{"id":"n818","loc":[-85.638686,41.942731]},"n819":{"id":"n819","loc":[-85.638689,41.942917]},"n82":{"id":"n82","loc":[-85.637835,41.94242]},"n820":{"id":"n820","loc":[-85.638558,41.943018]},"n821":{"id":"n821","loc":[-85.638243,41.943019]},"n822":{"id":"n822","loc":[-85.637536,41.943887]},"n823":{"id":"n823","loc":[-85.63749,41.943926]},"n824":{"id":"n824","loc":[-85.63743,41.943886]},"n825":{"id":"n825","loc":[-85.637476,41.943847]},"n826":{"id":"n826","loc":[-85.637527,41.943846]},"n827":{"id":"n827","loc":[-85.637141,41.943728]},"n828":{"id":"n828","loc":[-85.637201,41.943755]},"n829":{"id":"n829","loc":[-85.636987,41.943608]},"n83":{"id":"n83","loc":[-85.63776,41.942421]},"n830":{"id":"n830","loc":[-85.637441,41.943807]},"n831":{"id":"n831","loc":[-85.637673,41.94399]},"n832":{"id":"n832","loc":[-85.637783,41.944137]},"n833":{"id":"n833","loc":[-85.63845,41.944333]},"n834":{"id":"n834","loc":[-85.638159,41.944248]},"n835":{"id":"n835","loc":[-85.637859,41.94416]},"n836":{"id":"n836","loc":[-85.638685,41.944542]},"n837":{"id":"n837","loc":[-85.638714,41.944611]},"n838":{"id":"n838","loc":[-85.638711,41.944757]},"n839":{"id":"n839","loc":[-85.638774,41.945069]},"n84":{"id":"n84","loc":[-85.637758,41.942339]},"n840":{"id":"n840","loc":[-85.638742,41.945205]},"n841":{"id":"n841","loc":[-85.640267,41.942403]},"n842":{"id":"n842","loc":[-85.640154,41.942404]},"n843":{"id":"n843","loc":[-85.640152,41.942249]},"n844":{"id":"n844","loc":[-85.640266,41.942248]},"n845":{"id":"n845","loc":[-85.640366,41.942599]},"n846":{"id":"n846","loc":[-85.640362,41.942192]},"n847":{"id":"n847","loc":[-85.640146,41.942191]},"n848":{"id":"n848","loc":[-85.640122,41.942196]},"n849":{"id":"n849","loc":[-85.640108,41.942211]},"n85":{"id":"n85","loc":[-85.637836,41.942339]},"n850":{"id":"n850","loc":[-85.640101,41.942236]},"n851":{"id":"n851","loc":[-85.640103,41.94241]},"n852":{"id":"n852","loc":[-85.64011,41.942435]},"n853":{"id":"n853","loc":[-85.640126,41.942445]},"n854":{"id":"n854","loc":[-85.640153,41.942451]},"n855":{"id":"n855","loc":[-85.640183,41.942452]},"n856":{"id":"n856","loc":[-85.640364,41.942452]},"n857":{"id":"n857","loc":[-85.640007,41.942452]},"n858":{"id":"n858","loc":[-85.639449,41.942461]},"n859":{"id":"n859","loc":[-85.640049,41.942391]},"n86":{"id":"n86","loc":[-85.637835,41.942301]},"n860":{"id":"n860","loc":[-85.640052,41.942503]},"n861":{"id":"n861","loc":[-85.639575,41.94251]},"n862":{"id":"n862","loc":[-85.639572,41.942398]},"n863":{"id":"n863","loc":[-85.638782,41.942227]},"n864":{"id":"n864","loc":[-85.63843,41.942226]},"n865":{"id":"n865","loc":[-85.63823,41.942183]},"n866":{"id":"n866","loc":[-85.638363,41.942216],"tags":{"barrier":"gate"}},"n867":{"id":"n867","loc":[-85.6384,41.942223]},"n868":{"id":"n868","loc":[-85.636042,41.942797]},"n869":{"id":"n869","loc":[-85.636308,41.942752]},"n87":{"id":"n87","loc":[-85.637566,41.942367]},"n870":{"id":"n870","loc":[-85.636516,41.942729]},"n871":{"id":"n871","loc":[-85.636782,41.942712]},"n872":{"id":"n872","loc":[-85.636944,41.942706]},"n873":{"id":"n873","loc":[-85.63704,41.942706]},"n874":{"id":"n874","loc":[-85.637237,41.942703]},"n875":{"id":"n875","loc":[-85.637553,41.9427]},"n876":{"id":"n876","loc":[-85.638236,41.942697]},"n877":{"id":"n877","loc":[-85.636284,41.942781]},"n878":{"id":"n878","loc":[-85.636551,41.942641]},"n879":{"id":"n879","loc":[-85.633914,41.943693]},"n88":{"id":"n88","loc":[-85.637566,41.94241]},"n880":{"id":"n880","loc":[-85.63389,41.943708]},"n881":{"id":"n881","loc":[-85.633866,41.943686]},"n882":{"id":"n882","loc":[-85.63389,41.943671]},"n883":{"id":"n883","loc":[-85.633857,41.943609]},"n884":{"id":"n884","loc":[-85.634858,41.944474]},"n885":{"id":"n885","loc":[-85.633988,41.943234]},"n886":{"id":"n886","loc":[-85.633999,41.943485]},"n887":{"id":"n887","loc":[-85.634109,41.943449],"tags":{"emergency":"fire_hydrant"}},"n888":{"id":"n888","loc":[-85.635728,41.942655],"tags":{"emergency":"fire_hydrant"}},"n889":{"id":"n889","loc":[-85.636499,41.942845],"tags":{"man_made":"flagpole"}},"n89":{"id":"n89","loc":[-85.637455,41.94241]},"n890":{"id":"n890","loc":[-85.636197,41.943073]},"n891":{"id":"n891","loc":[-85.636227,41.943073]},"n892":{"id":"n892","loc":[-85.637433,41.942933],"tags":{"addr:city":"Three Rivers","addr:housenumber":"401","addr:postcode":"49093","addr:state":"MI","addr:street":"Michigan Avenue","amenity":"restaurant","cuisine":"pizza","name":"Pizza Hut"}},"n893":{"id":"n893","loc":[-85.637907,41.942879],"tags":{"amenity":"car_wash"}},"n894":{"id":"n894","loc":[-85.637661,41.943018]},"n895":{"id":"n895","loc":[-85.636933,41.942733],"tags":{"emergency":"fire_hydrant"}},"n896":{"id":"n896","loc":[-85.637661,41.94304]},"n897":{"id":"n897","loc":[-85.637562,41.943041]},"n898":{"id":"n898","loc":[-85.637556,41.942725]},"n899":{"id":"n899","loc":[-85.637656,41.942724]},"n9":{"id":"n9","loc":[-85.635159,41.941926]},"n90":{"id":"n90","loc":[-85.637454,41.942367]},"n900":{"id":"n900","loc":[-85.637657,41.942779]},"n901":{"id":"n901","loc":[-85.637983,41.942777]},"n902":{"id":"n902","loc":[-85.637982,41.942616]},"n903":{"id":"n903","loc":[-85.637777,41.942778]},"n904":{"id":"n904","loc":[-85.637775,41.942699]},"n905":{"id":"n905","loc":[-85.637772,41.942618]},"n906":{"id":"n906","loc":[-85.637982,41.942698]},"n907":{"id":"n907","loc":[-85.637941,41.942378],"tags":{"addr:city":"Three Rivers","addr:housenumber":"416","addr:postcode":"49093","addr:state":"MI","addr:street":"Michigan Avenue","name":"Gem Pawnbroker","shop":"pawnbroker"}},"n908":{"id":"n908","loc":[-85.637515,41.942394],"tags":{"second_hand":"only","shop":"car"}},"n909":{"id":"n909","loc":[-85.638743,41.942374],"tags":{"addr:city":"Three Rivers","addr:housenumber":"500","addr:postcode":"49093","addr:state":"MI","addr:street":"Michigan Avenue","name":"William Towing","service:vehicle:towing":"yes","service:vehicle:tyres":"yes","shop":"car_repair"}},"n91":{"id":"n91","loc":[-85.637565,41.942341]},"n910":{"id":"n910","loc":[-85.638594,41.942357]},"n911":{"id":"n911","loc":[-85.634312,41.943562],"tags":{"addr:city":"Three Rivers","addr:housenumber":"145","addr:postcode":"49093","addr:state":"MI","addr:street":"Michigan Avenue","amenity":"cafe","cuisine":"coffee_shop","name":"L.A.'s Coffee Cafe","outdoor_seating":"yes"}},"n912":{"id":"n912","loc":[-85.634404,41.943512]},"n913":{"id":"n913","loc":[-85.634391,41.943519],"tags":{"entrance":"yes"}},"n914":{"id":"n914","loc":[-85.634259,41.943538],"tags":{"entrance":"yes"}},"n915":{"id":"n915","loc":[-85.634247,41.943528]},"n916":{"id":"n916","loc":[-85.633747,41.943322],"tags":{"addr:city":"Three Rivers","addr:housenumber":"132","addr:postcode":"49093","addr:state":"MI","addr:street":"Michigan Avenue","name":"Preferred Insurance Services","office":"insurance"}},"n917":{"id":"n917","loc":[-85.63299,41.943686],"tags":{"addr:city":"Three Rivers","addr:housenumber":"101","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","name":"Lynn's Garage","service:vehicle:tyres":"yes","shop":"car_repair"}},"n918":{"id":"n918","loc":[-85.633438,41.944883]},"n919":{"id":"n919","loc":[-85.633265,41.944983]},"n92":{"id":"n92","loc":[-85.637481,41.942341]},"n920":{"id":"n920","loc":[-85.633315,41.945027]},"n921":{"id":"n921","loc":[-85.633376,41.944827]},"n922":{"id":"n922","loc":[-85.633199,41.944922]},"n923":{"id":"n923","loc":[-85.633316,41.944772]},"n924":{"id":"n924","loc":[-85.633147,41.944867]},"n925":{"id":"n925","loc":[-85.633261,41.944719]},"n926":{"id":"n926","loc":[-85.633096,41.944812]},"n927":{"id":"n927","loc":[-85.633191,41.944645]},"n928":{"id":"n928","loc":[-85.632981,41.94476]},"n929":{"id":"n929","loc":[-85.633062,41.94483]},"n93":{"id":"n93","loc":[-85.637481,41.94226]},"n930":{"id":"n930","loc":[-85.633146,41.944602]},"n931":{"id":"n931","loc":[-85.632969,41.944703]},"n932":{"id":"n932","loc":[-85.633008,41.944745]},"n933":{"id":"n933","loc":[-85.633088,41.944545]},"n934":{"id":"n934","loc":[-85.632868,41.944655]},"n935":{"id":"n935","loc":[-85.632941,41.944718]},"n936":{"id":"n936","loc":[-85.633028,41.944483]},"n937":{"id":"n937","loc":[-85.632817,41.944605]},"n938":{"id":"n938","loc":[-85.632923,41.944373]},"n939":{"id":"n939","loc":[-85.632692,41.944485]},"n94":{"id":"n94","loc":[-85.637565,41.94226]},"n940":{"id":"n940","loc":[-85.632871,41.944316]},"n941":{"id":"n941","loc":[-85.632655,41.944421]},"n942":{"id":"n942","loc":[-85.632711,41.944478]},"n943":{"id":"n943","loc":[-85.632825,41.94426]},"n944":{"id":"n944","loc":[-85.632606,41.944363]},"n945":{"id":"n945","loc":[-85.63275,41.94418]},"n946":{"id":"n946","loc":[-85.632588,41.944256]},"n947":{"id":"n947","loc":[-85.632611,41.944279]},"n948":{"id":"n948","loc":[-85.632548,41.944306]},"n949":{"id":"n949","loc":[-85.632512,41.944406]},"n95":{"id":"n95","loc":[-85.637188,41.942217]},"n950":{"id":"n950","loc":[-85.632565,41.944463]},"n951":{"id":"n951","loc":[-85.632579,41.944456]},"n952":{"id":"n952","loc":[-85.632634,41.944518]},"n953":{"id":"n953","loc":[-85.632686,41.944569]},"n954":{"id":"n954","loc":[-85.632745,41.944537]},"n955":{"id":"n955","loc":[-85.632659,41.944587]},"n956":{"id":"n956","loc":[-85.632778,41.944705]},"n957":{"id":"n957","loc":[-85.632815,41.944301],"tags":{"addr:city":"Three Rivers","addr:housenumber":"5","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","name":"Access Point Employment","office":"employment_agency"}},"n958":{"id":"n958","loc":[-85.6332,41.944174],"tags":{"addr:city":"Three Rivers","addr:housenumber":"6","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","name":"Paisley Emporium","shop":"second_hand"}},"n959":{"id":"n959","loc":[-85.633578,41.944568],"tags":{"addr:city":"Three Rivers","addr:housenumber":"22","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","name":"Lowry's Books","shop":"books"}},"n96":{"id":"n96","loc":[-85.637189,41.942303]},"n960":{"id":"n960","loc":[-85.63344,41.944443],"tags":{"addr:city":"Three Rivers","addr:housenumber":"16","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","amenity":"restaurant","cuisine":"pizza","name":"Paisano's Bar and Grill"}},"n961":{"id":"n961","loc":[-85.633009,41.944542],"tags":{"addr:city":"Three Rivers","addr:housenumber":"13","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","amenity":"cafe","cuisine":"american","internet_access":"yes","name":"Main Street Cafe"}},"n962":{"id":"n962","loc":[-85.633674,41.944682],"tags":{"addr:city":"Three Rivers","addr:housenumber":"28","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","leisure":"fitness_centre","name":"Main Street Fitness"}},"n963":{"id":"n963","loc":[-85.633376,41.944868],"tags":{"addr:city":"Three Rivers","addr:housenumber":"27","addr:postcode":"49093","addr:state":"MI","addr:street":"Main Street","leisure":"fitness_centre","name":"Main Street Barbell"}},"n964":{"id":"n964","loc":[-85.633366,41.944783]},"n965":{"id":"n965","loc":[-85.633296,41.94482]},"n966":{"id":"n966","loc":[-85.633214,41.94487]},"n967":{"id":"n967","loc":[-85.633005,41.944988]},"n968":{"id":"n968","loc":[-85.633269,41.944816]},"n969":{"id":"n969","loc":[-85.633215,41.944842]},"n97":{"id":"n97","loc":[-85.637299,41.942302]},"n970":{"id":"n970","loc":[-85.633245,41.944871]},"n971":{"id":"n971","loc":[-85.633296,41.944845]},"n972":{"id":"n972","loc":[-85.633254,41.944845],"tags":{"natural":"tree"}},"n973":{"id":"n973","loc":[-85.633557,41.945515]},"n974":{"id":"n974","loc":[-85.633279,41.945246]},"n975":{"id":"n975","loc":[-85.63324,41.945226]},"n976":{"id":"n976","loc":[-85.6332,41.945213]},"n977":{"id":"n977","loc":[-85.633133,41.945164]},"n978":{"id":"n978","loc":[-85.63312,41.945132]},"n979":{"id":"n979","loc":[-85.633095,41.945081]},"n98":{"id":"n98","loc":[-85.637299,41.942314]},"n980":{"id":"n980","loc":[-85.633064,41.945047]},"n981":{"id":"n981","loc":[-85.632739,41.944742]},"n982":{"id":"n982","loc":[-85.633281,41.945026]},"n983":{"id":"n983","loc":[-85.633155,41.944903]},"n984":{"id":"n984","loc":[-85.633079,41.944829]},"n985":{"id":"n985","loc":[-85.63304,41.944853]},"n986":{"id":"n986","loc":[-85.632949,41.944776]},"n987":{"id":"n987","loc":[-85.632921,41.944725]},"n988":{"id":"n988","loc":[-85.632859,41.944673]},"n989":{"id":"n989","loc":[-85.632895,41.94505]},"n99":{"id":"n99","loc":[-85.637396,41.942313]},"n990":{"id":"n990","loc":[-85.633336,41.945138]},"n991":{"id":"n991","loc":[-85.633466,41.945265]},"n992":{"id":"n992","loc":[-85.633367,41.945327]},"n993":{"id":"n993","loc":[-85.633163,41.945189]},"n994":{"id":"n994","loc":[-85.633678,41.945309]},"n995":{"id":"n995","loc":[-85.633619,41.945261]},"n996":{"id":"n996","loc":[-85.63355,41.945301]},"n997":{"id":"n997","loc":[-85.633607,41.945352]},"n998":{"id":"n998","loc":[-85.633579,41.945327],"tags":{"entrance":"yes"}},"n999":{"id":"n999","loc":[-85.633445,41.945404]},"r2":{"id":"r2","members":[{"id":"w225","role":"outer","type":"way"}],"tags":{"type":"multipolygon","waterway":"riverbank"}},"r5":{"id":"r5","members":[{"id":"w642","role":"outer","type":"way"}],"tags":{"admin_level":"8","border_type":"city","boundary":"administrative","name":"Three Rivers","place":"city","type":"boundary"}},"w1":{"id":"w1","nodes":["n5","n1797"],"tags":{"highway":"residential","name":"12th Avenue"}},"w10":{"id":"w10","nodes":["n54","n55","n56","n57","n891","n890","n54"],"tags":{"building":"yes"}},"w100":{"id":"w100","nodes":["n451","n915","n452"],"tags":{"highway":"footway"}},"w101":{"id":"w101","nodes":["n461","n462","n463","n464","n465","n466"],"tags":{"barrier":"fence"}},"w102":{"id":"w102","nodes":["n467","n468","n469","n470","n472","n467"],"tags":{"amenity":"parking"}},"w103":{"id":"w103","nodes":["n2597","n2444","n471","n472"],"tags":{"highway":"footway"}},"w104":{"id":"w104","nodes":["n473","n474","n325"],"tags":{"footway":"sidewalk","highway":"footway"}},"w105":{"id":"w105","nodes":["n475","n324","n325"],"tags":{"footway":"sidewalk","highway":"footway"}},"w106":{"id":"w106","nodes":["n886","n452","n476"],"tags":{"footway":"sidewalk","highway":"footway"}},"w107":{"id":"w107","nodes":["n485","n4678","n486","n18"],"tags":{"highway":"service"}},"w108":{"id":"w108","nodes":["n300","n487","n488","n489","n490"],"tags":{"highway":"footway"}},"w109":{"id":"w109","nodes":["n490","n491"],"tags":{"highway":"footway"}},"w11":{"id":"w11","nodes":["n58","n63","n59","n315","n60"],"tags":{"highway":"service"}},"w110":{"id":"w110","nodes":["n492","n493","n494","n495","n496","n497","n492"],"tags":{"building":"yes"}},"w111":{"id":"w111","nodes":["n498","n499","n511"],"tags":{"highway":"service"}},"w112":{"id":"w112","nodes":["n510","n500","n501","n502","n503","n504","n505","n506","n507","n508","n509"],"tags":{"highway":"service"}},"w113":{"id":"w113","nodes":["n511","n510"],"tags":{"covered":"yes","highway":"service"}},"w114":{"id":"w114","nodes":["n512","n513","n514","n515","n512"],"tags":{"building":"yes"}},"w115":{"id":"w115","nodes":["n516","n517","n518","n519","n516"],"tags":{"building":"yes"}},"w116":{"id":"w116","nodes":["n520","n521","n522","n523","n520"],"tags":{"building":"yes"}},"w117":{"id":"w117","nodes":["n524","n525","n526","n527","n528","n529","n530","n531","n532","n533","n534","n535","n524"],"tags":{"building":"yes"}},"w118":{"id":"w118","nodes":["n536","n537","n538","n539","n536"],"tags":{"building":"yes"}},"w119":{"id":"w119","nodes":["n540","n541","n542","n543","n544","n545","n546","n547","n540"],"tags":{"building":"yes"}},"w12":{"id":"w12","nodes":["n61","n314","n70","n62","n63"],"tags":{"highway":"service"}},"w120":{"id":"w120","nodes":["n548","n549","n550","n551","n552","n553","n554","n555","n556","n557","n548"],"tags":{"building":"yes"}},"w121":{"id":"w121","nodes":["n558","n559","n560","n561","n562","n563","n564","n565","n558"],"tags":{"building":"yes"}},"w122":{"id":"w122","nodes":["n566","n567","n568","n569","n566"],"tags":{"building":"yes"}},"w123":{"id":"w123","nodes":["n570","n571","n572","n573","n570"],"tags":{"building":"yes"}},"w124":{"id":"w124","nodes":["n574","n575","n576","n577","n574"],"tags":{"building":"yes"}},"w125":{"id":"w125","nodes":["n578","n579","n580","n581","n578"],"tags":{"building":"yes"}},"w126":{"id":"w126","nodes":["n582","n583","n584","n585","n582"],"tags":{"building":"yes"}},"w127":{"id":"w127","nodes":["n586","n587","n588","n589","n590","n591","n592","n593","n586"],"tags":{"building":"yes"}},"w128":{"id":"w128","nodes":["n594","n595","n596","n597","n598","n599","n600","n601","n594"],"tags":{"building":"yes"}},"w129":{"id":"w129","nodes":["n309","n602","n603"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w13":{"id":"w13","nodes":["n64","n65","n66","n67","n68","n69","n64"],"tags":{"amenity":"parking"}},"w130":{"id":"w130","nodes":["n603","n604"],"tags":{"footway":"sidewalk","highway":"footway"}},"w131":{"id":"w131","nodes":["n604","n605","n606"],"tags":{"footway":"sidewalk","highway":"footway"}},"w132":{"id":"w132","nodes":["n606","n607"],"tags":{"footway":"sidewalk","highway":"footway"}},"w133":{"id":"w133","nodes":["n607","n610","n608","n603"],"tags":{"footway":"sidewalk","highway":"footway"}},"w134":{"id":"w134","nodes":["n609","n610","n611"],"tags":{"highway":"service","service":"driveway","surface":"unpaved"}},"w135":{"id":"w135","nodes":["n244","n245","n246"],"tags":{"highway":"service"}},"w136":{"id":"w136","nodes":["n612","n613","n614","n615","n612"],"tags":{"amenity":"shelter"}},"w137":{"id":"w137","nodes":["n2779","n2788","n2776","n2778","n2775","n2787","n2440","n2437","n629","n2438","n630","n2439","n2407","n2408","n2409"],"tags":{"highway":"residential","name":"Foster Street"}},"w138":{"id":"w138","nodes":["n2779","n625","n626","n627"],"tags":{"highway":"residential","name":"Foster Street","oneway":"yes"}},"w139":{"id":"w139","nodes":["n630","n631","n632","n2437"],"tags":{"highway":"service"}},"w14":{"id":"w14","nodes":["n71","n72","n73","n74","n71"],"tags":{"building":"yes"}},"w140":{"id":"w140","nodes":["n643","n637","n715","n2410"],"tags":{"highway":"footway","name":"Mural Mall"}},"w141":{"id":"w141","nodes":["n639","n2516"],"tags":{"barrier":"wall"}},"w142":{"id":"w142","nodes":["n640","n641","n645","n642","n660","n643","n644"],"tags":{"highway":"service"}},"w143":{"id":"w143","nodes":["n646","n647"],"tags":{"highway":"service"}},"w144":{"id":"w144","nodes":["n654","n655","n656"],"tags":{"barrier":"wall"}},"w145":{"id":"w145","nodes":["n665","n666","n667"],"tags":{"barrier":"wall"}},"w146":{"id":"w146","nodes":["n2727","n662","n2719"],"tags":{"highway":"service","oneway":"yes","service":"parking_aisle"}},"w147":{"id":"w147","nodes":["n2725","n674"],"tags":{"highway":"service","oneway":"yes"}},"w148":{"id":"w148","nodes":["n2464","n2460","n2454","n684","n2455","n2464"],"tags":{"building":"yes"}},"w149":{"id":"w149","nodes":["n2456","n685","n686","n687","n2456"],"tags":{"building":"yes"}},"w15":{"id":"w15","nodes":["n75","n76","n77","n78","n75"],"tags":{"building":"yes"}},"w150":{"id":"w150","nodes":["n685","n688","n689","n690","n691","n692","n686","n685"],"tags":{"building":"yes"}},"w151":{"id":"w151","nodes":["n688","n693","n694","n689","n688"],"tags":{"building":"yes"}},"w152":{"id":"w152","nodes":["n693","n695","n702","n696","n697","n694","n693"],"tags":{"building":"yes"}},"w153":{"id":"w153","nodes":["n695","n698","n699","n700","n701","n702","n695"],"tags":{"building":"yes"}},"w154":{"id":"w154","nodes":["n698","n703","n707","n704","n699","n698"],"tags":{"building":"yes"}},"w155":{"id":"w155","nodes":["n703","n705","n706","n707","n703"],"tags":{"building":"yes"}},"w156":{"id":"w156","nodes":["n705","n708","n709","n706","n705"],"tags":{"building":"yes"}},"w157":{"id":"w157","nodes":["n709","n710","n711","n708","n709"],"tags":{"building":"yes"}},"w158":{"id":"w158","nodes":["n369","n712","n725","n713","n714","n715","n727","n716","n717","n718","n719"],"tags":{"footway":"sidewalk","highway":"footway"}},"w159":{"id":"w159","nodes":["n714","n720","n721"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w16":{"id":"w16","nodes":["n79","n80","n81","n82","n83","n84","n85","n86","n79"],"tags":{"building":"yes"}},"w160":{"id":"w160","nodes":["n729","n721","n722","n964","n723","n724"],"tags":{"footway":"sidewalk","highway":"footway"}},"w161":{"id":"w161","nodes":["n713","n726","n722"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w162":{"id":"w162","nodes":["n727","n2411","n728"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w163":{"id":"w163","nodes":["n729","n730","n731"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w164":{"id":"w164","nodes":["n365","n732","n733","n738"],"tags":{"footway":"sidewalk","highway":"footway"}},"w165":{"id":"w165","nodes":["n724","n734","n367","n735","n736","n737"],"tags":{"footway":"sidewalk","highway":"footway"}},"w166":{"id":"w166","nodes":["n739","n2037","n2038","n2039","n2040","n1623","n2032"],"tags":{"highway":"footway"}},"w167":{"id":"w167","nodes":["n150","n751"],"tags":{"highway":"service"}},"w168":{"id":"w168","nodes":["n752","n753","n754","n755","n752"],"tags":{"building":"yes"}},"w169":{"id":"w169","nodes":["n756","n757","n758","n759","n756"],"tags":{"building":"yes"}},"w17":{"id":"w17","nodes":["n87","n88","n89","n90","n87"],"tags":{"building":"yes"}},"w170":{"id":"w170","nodes":["n760","n761","n762","n763","n764","n765","n760"],"tags":{"building":"yes"}},"w171":{"id":"w171","nodes":["n766","n767","n768","n769","n770","n771","n772","n773","n774","n775","n776","n777","n766"],"tags":{"building":"yes"}},"w172":{"id":"w172","nodes":["n778","n779","n780","n781","n782","n783","n784","n785","n778"],"tags":{"building":"yes"}},"w173":{"id":"w173","nodes":["n786","n787","n788","n789","n786"],"tags":{"building":"yes"}},"w174":{"id":"w174","nodes":["n790","n791","n792","n793","n794","n795","n796","n797","n798","n799","n800","n801","n790"],"tags":{"building":"yes"}},"w175":{"id":"w175","nodes":["n802","n803","n804","n805","n802"],"tags":{"building":"yes"}},"w176":{"id":"w176","nodes":["n806","n807","n808","n809","n810","n811","n812","n813","n814","n815","n806"],"tags":{"building":"yes"}},"w177":{"id":"w177","nodes":["n816","n1140","n817","n818","n819","n820","n821"],"tags":{"highway":"service"}},"w178":{"id":"w178","nodes":["n822","n823","n824","n825","n822"],"tags":{"building":"yes"}},"w179":{"id":"w179","nodes":["n841","n842","n843","n844","n841"],"tags":{"building":"yes"}},"w18":{"id":"w18","nodes":["n91","n92","n93","n94","n91"],"tags":{"building":"yes"}},"w180":{"id":"w180","nodes":["n845","n856","n846"],"tags":{"highway":"service"}},"w181":{"id":"w181","nodes":["n846","n847","n848","n849","n850","n851","n852","n853","n854","n855","n856"],"tags":{"highway":"service","oneway":"yes","service":"drive-through"}},"w182":{"id":"w182","nodes":["n857","n858"],"tags":{"highway":"service"}},"w183":{"id":"w183","nodes":["n859","n860","n861","n862","n859"],"tags":{"amenity":"parking"}},"w184":{"id":"w184","nodes":["n863","n864","n867","n866","n865"],"tags":{"highway":"service"}},"w185":{"id":"w185","nodes":["n883","n884"],"tags":{"barrier":"fence"}},"w186":{"id":"w186","nodes":["n1954","n622","n1955"],"tags":{"highway":"path","name":"Riverwalk Trail"}},"w187":{"id":"w187","nodes":["n621","n1954"],"tags":{"highway":"steps","incline":"up","name":"Riverwalk Trail","surface":"wood"}},"w188":{"id":"w188","nodes":["n2274","n2275","n2276","n2277","n2278","n2279","n1953","n621"],"tags":{"highway":"path","name":"Riverwalk Trail","surface":"wood"}},"w189":{"id":"w189","nodes":["n2273","n2274"],"tags":{"highway":"steps","incline":"down","name":"Riverwalk Trail","surface":"wood"}},"w19":{"id":"w19","nodes":["n95","n96","n97","n98","n99","n100","n101","n102","n95"],"tags":{"building":"yes"}},"w190":{"id":"w190","nodes":["n821","n894","n900","n903","n901"],"tags":{"highway":"service"}},"w191":{"id":"w191","nodes":["n896","n897","n898","n899","n900","n894","n896"],"tags":{"amenity":"parking"}},"w192":{"id":"w192","nodes":["n903","n904","n905"],"tags":{"highway":"service"}},"w193":{"id":"w193","nodes":["n901","n906","n902"],"tags":{"highway":"service"}},"w194":{"id":"w194","nodes":["n912","n913"],"tags":{"highway":"footway"}},"w195":{"id":"w195","nodes":["n914","n915"],"tags":{"highway":"footway"}},"w196":{"id":"w196","nodes":["n2466","n918","n919","n920","n2466"],"tags":{"building":"yes"}},"w197":{"id":"w197","nodes":["n918","n921","n922","n919","n918"],"tags":{"building":"yes"}},"w198":{"id":"w198","nodes":["n923","n925","n926","n924","n923"],"tags":{"building":"yes"}},"w199":{"id":"w199","nodes":["n925","n927","n932","n928","n929","n926","n925"],"tags":{"building":"yes"}},"w2":{"id":"w2","nodes":["n3523","n2182","n2160"],"tags":{"highway":"service"}},"w20":{"id":"w20","nodes":["n103","n104","n105","n106","n107","n108","n109","n110","n111","n112","n113","n114","n103"],"tags":{"building":"yes"}},"w200":{"id":"w200","nodes":["n927","n930","n931","n932","n927"],"tags":{"building":"yes"}},"w201":{"id":"w201","nodes":["n930","n933","n934","n935","n931","n930"],"tags":{"building":"yes"}},"w202":{"id":"w202","nodes":["n933","n936","n937","n934","n933"],"tags":{"building":"yes"}},"w203":{"id":"w203","nodes":["n936","n938","n942","n939","n954","n937","n936"],"tags":{"building":"yes"}},"w204":{"id":"w204","nodes":["n938","n940","n941","n942","n938"],"tags":{"building":"yes"}},"w205":{"id":"w205","nodes":["n940","n943","n944","n941","n940"],"tags":{"building":"yes"}},"w206":{"id":"w206","nodes":["n943","n945","n946","n947","n948","n944","n943"],"tags":{"building":"yes"}},"w207":{"id":"w207","nodes":["n944","n949","n950","n951","n941","n944"],"tags":{"building":"yes"}},"w208":{"id":"w208","nodes":["n941","n951","n952","n939","n942","n941"],"tags":{"building":"yes"}},"w209":{"id":"w209","nodes":["n952","n953","n954","n939","n952"],"tags":{"building":"yes"}},"w21":{"id":"w21","nodes":["n115","n116","n117","n118","n115"],"tags":{"building":"yes"}},"w210":{"id":"w210","nodes":["n953","n955","n956","n934","n937","n954","n953"],"tags":{"building":"yes"}},"w211":{"id":"w211","nodes":["n964","n965"],"tags":{"highway":"footway"}},"w212":{"id":"w212","nodes":["n966","n983","n967","n989"],"tags":{"highway":"footway"}},"w213":{"id":"w213","nodes":["n965","n968","n969","n966","n970","n971","n965"],"tags":{"highway":"footway"}},"w214":{"id":"w214","nodes":["n973","n999","n992","n974","n975","n976","n993","n977","n978","n979","n980","n967","n981","n1000","n1001","n1002","n1003","n1004","n1005","n1006","n1007","n1008","n1009"],"tags":{"footway":"sidewalk","highway":"footway"}},"w215":{"id":"w215","nodes":["n978","n982","n983","n984","n985","n986","n987","n988","n981"],"tags":{"highway":"footway"}},"w216":{"id":"w216","nodes":["n976","n990","n991","n992"],"tags":{"highway":"footway"}},"w217":{"id":"w217","nodes":["n998","n999"],"tags":{"highway":"footway"}},"w218":{"id":"w218","nodes":["n1019","n1020","n1021","n1022","n731","n728","n1023","n1025","n1024","n1019"],"tags":{"footway":"sidewalk","highway":"footway"}},"w219":{"id":"w219","nodes":["n719","n1026","n1027"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w22":{"id":"w22","nodes":["n119","n120","n121","n122","n119"],"tags":{"building":"yes"}},"w220":{"id":"w220","nodes":["n1027","n1028","n1019"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w221":{"id":"w221","nodes":["n2080","n1828","n1863","n1829"],"tags":{"highway":"tertiary","name":"Constantine Street"}},"w222":{"id":"w222","nodes":["n1029","n1030","n1031"],"tags":{"highway":"service"}},"w223":{"id":"w223","nodes":["n2213","n2171","n2183","n2180","n2205","n2177","n2179","n2218","n2200","n2188","n2169","n2196","n2162","n2170","n2211","n2216","n2204","n2220","n2164","n2210","n2217","n2189","n460","n453","n2282"],"tags":{"name":"Rocky River","waterway":"river"}},"w224":{"id":"w224","nodes":["n3750","n3751","n3752"],"tags":{"highway":"service","service":"alley","surface":"unpaved"}},"w225":{"id":"w225","nodes":["n2134","n2127","n2313","n2109","n2112","n2129","n2156","n2146","n2126","n2153","n2288","n2283","n2284","n2131","n2286","n2287","n2285","n2132","n2140","n2289","n2122","n2114","n2149","n2119","n2106","n2111","n2145","n2113","n2117","n2159","n2143","n2123","n2142","n2116","n2154","n2139","n2150","n2157","n2120","n2138","n2130","n2136","n2155","n2107","n2141","n2124","n3754","n2121","n2105","n2108","n3755","n2128","n2110","n2152","n2125","n2135","n2186","n2115","n2144","n2137","n2133","n2148","n2118","n1871","n1875","n1872","n2041","n1873","n2042","n1874","n1884","n1870","n2151","n2147","n2158","n2104","n2134"]},"w226":{"id":"w226","nodes":["n2243","n2280","n2244","n2245","n2246","n2247","n1931","n1932","n1933","n1934","n1935","n1936","n1937","n1938","n4681","n1939","n1940","n1941","n1942","n1943","n1944","n1945","n1946","n1947"],"tags":{"highway":"path","name":"Riverwalk Trail","surface":"asphalt","width":"3"}},"w227":{"id":"w227","nodes":["n2994","n3012","n3011","n2958"],"tags":{"highway":"secondary","name":"Main Street"}},"w228":{"id":"w228","nodes":["n2747","n2762","n2757","n2746","n2761","n2758","n2760","n2755","n2749","n2691","n1028","n2432","n2414","n2413","n2412","n2411","n2410","n720","n726","n370","n368","n2748"],"tags":{"highway":"primary","name":"Main Street"}},"w229":{"id":"w229","nodes":["n2083","n2103","n2102","n2084","n2085","n2086","n2087","n2242","n471","n324","n2101","n332","n1868"],"tags":{"name":"Conrail Railroad","railway":"rail"}},"w23":{"id":"w23","nodes":["n123","n124","n125","n126","n123"],"tags":{"building":"yes"}},"w230":{"id":"w230","nodes":["n2232","n2236","n2231","n2230","n2226","n2241","n2237","n2227","n1182","n2233","n2228","n2229","n1183","n2234","n19","n1891","n20","n2223","n2224","n2238","n2235","n2240","n2225","n2239"],"tags":{"name":"Saint Joseph River","waterway":"river"}},"w231":{"id":"w231","nodes":["n456","n1036","n1037","n1038"],"tags":{"barrier":"wall"}},"w232":{"id":"w232","nodes":["n1034","n1039","n1040"],"tags":{"barrier":"wall"}},"w233":{"id":"w233","nodes":["n1041","n1042","n1043","n1044","n1045","n1046","n1041"],"tags":{"access":"private","leisure":"swimming_pool"}},"w234":{"id":"w234","nodes":["n1047","n1048"],"tags":{"barrier":"hedge"}},"w235":{"id":"w235","nodes":["n1049","n1050","n1051","n1052","n1049"],"tags":{"building":"yes"}},"w236":{"id":"w236","nodes":["n1053","n1054","n1055","n1056","n1057","n1058","n1059","n1060","n1053"],"tags":{"building":"yes"}},"w237":{"id":"w237","nodes":["n1061","n1062","n1063","n1064","n1065","n1061"],"tags":{"building":"yes"}},"w238":{"id":"w238","nodes":["n1066","n1067","n1068","n1069","n1070","n1071","n1066"],"tags":{"building":"yes"}},"w239":{"id":"w239","nodes":["n1072","n1073","n1074","n1075","n1072"],"tags":{"building":"yes"}},"w24":{"id":"w24","nodes":["n127","n128","n129","n130","n127"],"tags":{"building":"yes"}},"w240":{"id":"w240","nodes":["n1076","n1077","n1078","n1079","n1080","n1081","n1076"],"tags":{"building":"yes"}},"w241":{"id":"w241","nodes":["n1082","n1083","n1084","n1085","n1082"],"tags":{"building":"yes"}},"w242":{"id":"w242","nodes":["n1086","n1087","n1088","n1089","n1086"],"tags":{"building":"yes"}},"w243":{"id":"w243","nodes":["n1090","n1091","n1092","n1093","n1094","n1095","n1096","n1097","n1090"],"tags":{"building":"yes"}},"w244":{"id":"w244","nodes":["n1098","n1099","n1100","n1101"],"tags":{"barrier":"fence"}},"w245":{"id":"w245","nodes":["n1102","n835","n30","n2590","n35","n29","n2591","n34","n28","n2592","n2312","n32","n2593","n31","n33","n2594","n2595","n1102"],"tags":{"highway":"service"}},"w246":{"id":"w246","nodes":["n1103","n1139","n1104"],"tags":{"barrier":"fence"}},"w247":{"id":"w247","nodes":["n1105","n1106","n1107","n1108","n1109","n1110","n1111","n1112","n1113","n1114","n1105"],"tags":{"building":"yes"}},"w248":{"id":"w248","nodes":["n1115","n1116","n1117","n1118","n1119","n1120","n1115"],"tags":{"building":"yes"}},"w249":{"id":"w249","nodes":["n1121","n1122","n1123","n1124","n1121"],"tags":{"building":"yes"}},"w25":{"id":"w25","nodes":["n131","n132","n133","n134","n135","n136","n137","n138","n139","n140","n141","n142","n131"],"tags":{"building":"yes"}},"w250":{"id":"w250","nodes":["n1125","n1126","n1127","n1128","n1129","n1130","n1131","n1132","n1133","n1134","n1135","n1136","n1125"],"tags":{"building":"yes"}},"w251":{"id":"w251","nodes":["n1137","n1138","n1139"],"tags":{"barrier":"fence"}},"w252":{"id":"w252","nodes":["n876","n1140","n1141"],"tags":{"footway":"sidewalk","highway":"footway"}},"w253":{"id":"w253","nodes":["n1141","n1142","n1143","n1144","n1145","n1146"],"tags":{"footway":"sidewalk","highway":"footway"}},"w254":{"id":"w254","nodes":["n1146","n4743","n1147","n1148"],"tags":{"footway":"sidewalk","highway":"footway"}},"w255":{"id":"w255","nodes":["n1148","n1149","n1150","n1151"],"tags":{"bridge":"yes","footway":"sidewalk","highway":"footway","layer":"1"}},"w256":{"id":"w256","nodes":["n1151","n1153","n1154","n1155"],"tags":{"footway":"sidewalk","highway":"footway"}},"w257":{"id":"w257","nodes":["n1155","n1156"],"tags":{"bridge":"yes","footway":"sidewalk","highway":"footway","layer":"1"}},"w258":{"id":"w258","nodes":["n1157","n1158"],"tags":{"barrier":"retaining_wall"}},"w259":{"id":"w259","nodes":["n1156","n1161","n1159","n1160","n719"],"tags":{"footway":"sidewalk","highway":"footway"}},"w26":{"id":"w26","nodes":["n143","n608","n144"],"tags":{"highway":"service"}},"w260":{"id":"w260","nodes":["n1162","n1163","n1164","n1165","n1166","n1167","n1168","n1169","n1170","n2528"],"tags":{"highway":"footway"}},"w261":{"id":"w261","nodes":["n1171","n1172","n1173"],"tags":{"barrier":"wall"}},"w262":{"id":"w262","nodes":["n1175","n1176","n1177","n1178","n1179","n1180","n1181","n1175"],"tags":{"natural":"wood"}},"w263":{"id":"w263","nodes":["n1947","n1184","n1948","n1185","n1949","n1957","n1950","n480","n1951","n479","n478","n477","n1952","n1851","n1956","n2248","n619","n618","n2249","n2250","n2251","n617","n2252","n616","n2253","n829","n2254","n827","n828","n2255","n830","n2256","n826","n2257","n831","n2258","n832","n835","n834","n2312","n2267","n2259","n833","n2268","n2260","n836","n2261","n837","n2262","n838","n2263","n2264","n839","n2265","n840","n2266"],"tags":{"highway":"path","name":"Riverwalk Trail","surface":"asphalt","width":"3"}},"w264":{"id":"w264","nodes":["n1186","n1187","n1188","n1189","n1186"],"tags":{"building":"yes"}},"w265":{"id":"w265","nodes":["n1190","n1191","n1192","n1193","n1190"],"tags":{"building":"yes"}},"w266":{"id":"w266","nodes":["n1194","n1195","n1196","n1197","n1198","n1199","n1200","n1201","n1194"],"tags":{"building":"yes"}},"w267":{"id":"w267","nodes":["n1205","n1206","n1207","n1208","n1209","n1210","n1205"],"tags":{"building":"house"}},"w268":{"id":"w268","nodes":["n1211","n1212","n1213","n1214","n1215","n1216","n1217","n1218","n1219","n1220","n1211"],"tags":{"building":"house"}},"w269":{"id":"w269","nodes":["n1221","n1225","n1222","n1223","n1224","n1221"],"tags":{"building":"house"}},"w27":{"id":"w27","nodes":["n145","n147","n146"],"tags":{"highway":"footway"}},"w270":{"id":"w270","nodes":["n1225","n1226","n1227","n1229","n1228"],"tags":{"barrier":"fence"}},"w271":{"id":"w271","nodes":["n1229","n1230"],"tags":{"barrier":"fence"}},"w272":{"id":"w272","nodes":["n1231","n1232","n1233","n1234","n1235","n1236","n1237","n1238","n1231"],"tags":{"building":"house"}},"w273":{"id":"w273","nodes":["n1239","n1240","n1241","n1242","n1243","n1244","n1245","n1246","n1239"],"tags":{"building":"house"}},"w274":{"id":"w274","nodes":["n1247","n1248","n1249","n1250","n1247"],"tags":{"building":"house"}},"w275":{"id":"w275","nodes":["n1251","n1252","n1253","n1254","n1255","n1256","n1251"],"tags":{"building":"house"}},"w276":{"id":"w276","nodes":["n1257","n1258","n1259","n1260","n1257"],"tags":{"building":"shed"}},"w277":{"id":"w277","nodes":["n1261","n1262","n1263","n1264","n1265","n1266","n1267","n1268","n1261"],"tags":{"building":"house"}},"w278":{"id":"w278","nodes":["n1269","n1270","n1271","n1272","n1273","n1274","n1284","n1269"],"tags":{"building":"house"}},"w279":{"id":"w279","nodes":["n1275","n1276","n1277","n1278","n1279","n1280","n1275"],"tags":{"building":"house"}},"w28":{"id":"w28","nodes":["n147","n148"],"tags":{"highway":"footway"}},"w280":{"id":"w280","nodes":["n1281","n1282","n1283","n1284"],"tags":{"barrier":"fence"}},"w281":{"id":"w281","nodes":["n1285","n1286","n1287","n1288","n1285"],"tags":{"building":"house"}},"w282":{"id":"w282","nodes":["n1289","n1290","n1291","n1292","n1293","n1294","n1295","n1296","n1289"],"tags":{"building":"house"}},"w283":{"id":"w283","nodes":["n1297","n1298","n1299","n1300","n1301","n1302","n1297"],"tags":{"access":"private","leisure":"swimming_pool"}},"w284":{"id":"w284","nodes":["n1303","n1304","n1305","n1306","n1307","n1308","n1309","n1310","n1311","n1312","n1303"],"tags":{"building":"house"}},"w285":{"id":"w285","nodes":["n1313","n1314","n1315","n1316","n1313"],"tags":{"building":"house"}},"w286":{"id":"w286","nodes":["n1317","n1318","n1319","n1320","n1321","n1322","n1323","n1324","n1325","n1326","n1327","n1328","n1329","n1330","n1317"],"tags":{"building":"house"}},"w287":{"id":"w287","nodes":["n1331","n1332","n1333","n1334","n1465","n1335","n1336","n1331"],"tags":{"building":"yes"}},"w288":{"id":"w288","nodes":["n1349","n1350","n1351","n1352","n1353","n1354","n1355","n1337","n1338","n1341","n1342","n1343","n1344","n1345","n1346","n1347","n1348","n1339","n1340","n1349"],"tags":{"access":"private","leisure":"swimming_pool"}},"w289":{"id":"w289","nodes":["n1356","n1331"],"tags":{"barrier":"fence"}},"w29":{"id":"w29","nodes":["n149","n874","n150","n151","n897","n898","n875","n152"],"tags":{"highway":"service","oneway":"yes"}},"w290":{"id":"w290","nodes":["n1357","n1358","n1359","n1360","n1357"],"tags":{"building":"shed"}},"w291":{"id":"w291","nodes":["n1358","n1361","n1362"],"tags":{"barrier":"fence"}},"w292":{"id":"w292","nodes":["n1363","n1364","n1365","n1366","n1367","n1368","n1363"],"tags":{"building":"house"}},"w293":{"id":"w293","nodes":["n1369","n1370","n1371","n1372","n1373","n1374","n1369"],"tags":{"leisure":"swimming_pool"}},"w294":{"id":"w294","nodes":["n1367","n1375","n1376","n1377"],"tags":{"barrier":"fence"}},"w295":{"id":"w295","nodes":["n1378","n1379","n1380","n1381","n1378"],"tags":{"building":"house"}},"w296":{"id":"w296","nodes":["n1382","n1383","n1384","n1385","n1386","n1387","n1382"],"tags":{"building":"house"}},"w297":{"id":"w297","nodes":["n1388","n1389","n1390","n1391","n1392","n1393","n1388"],"tags":{"building":"house"}},"w298":{"id":"w298","nodes":["n1394","n1395","n1396","n1397","n1394"],"tags":{"building":"house"}},"w299":{"id":"w299","nodes":["n1398","n1399","n1400","n1401","n1398"],"tags":{"access":"private3","leisure":"swimming_pool"}},"w3":{"id":"w3","nodes":["n1","n2"],"tags":{"highway":"track","name":"Water Street"}},"w30":{"id":"w30","nodes":["n153","n154","n155","n156","n153"],"tags":{"amenity":"parking"}},"w300":{"id":"w300","nodes":["n1402","n1403","n1404","n1405","n1406","n1407","n1408","n1409","n1410","n1411","n1412","n1413","n1402"],"tags":{"building":"house"}},"w301":{"id":"w301","nodes":["n1414","n1415","n1416","n1417","n1414"],"tags":{"building":"garage"}},"w302":{"id":"w302","nodes":["n1406","n1418","n1419","n1403"],"tags":{"barrier":"fence"}},"w303":{"id":"w303","nodes":["n1423","n1424","n1425","n1426","n1427","n1428","n1429","n1430","n1431","n1432","n1423"],"tags":{"building":"house"}},"w304":{"id":"w304","nodes":["n1433","n1434","n1435","n1446","n1436","n1437","n1438","n1439","n1444","n1440","n1441","n1445","n1442","n1443","n1433"],"tags":{"access":"private","leisure":"swimming_pool"}},"w305":{"id":"w305","nodes":["n1447","n1448","n1452","n1453","n1454","n1451","n1449","n1450","n1447"],"tags":{"building":"house"}},"w306":{"id":"w306","nodes":["n1455","n1456","n1457","n1458","n1455"],"tags":{"building":"shed"}},"w307":{"id":"w307","nodes":["n1459","n1460","n1461","n1462","n1459"],"tags":{"building":"shed"}},"w308":{"id":"w308","nodes":["n1463","n1464"],"tags":{"barrier":"fence"}},"w309":{"id":"w309","nodes":["n1465","n1466","n1467","n1468"],"tags":{"barrier":"fence"}},"w31":{"id":"w31","nodes":["n157","n605","n158"],"tags":{"highway":"service"}},"w310":{"id":"w310","nodes":["n1469","n1481","n1463"],"tags":{"barrier":"hedge"}},"w311":{"id":"w311","nodes":["n1470","n1471","n1472","n1473","n1474","n1475","n1480","n1476","n1477","n1478","n1479","n1470"],"tags":{"building":"house"}},"w312":{"id":"w312","nodes":["n1480","n1481"],"tags":{"barrier":"wall"}},"w313":{"id":"w313","nodes":["n1482","n1483","n1484","n1485","n1486","n1487","n1488","n1489","n1490","n1491","n1482"],"tags":{"access":"private","leisure":"swimming_pool"}},"w314":{"id":"w314","nodes":["n1492","n1493","n1494","n1495","n1496","n1497","n1498","n1499","n1500","n1501","n1502","n1503","n1504","n1505","n1492"],"tags":{"building":"house"}},"w315":{"id":"w315","nodes":["n1506","n1507","n1508","n1509","n1510","n1511","n1512","n1513","n1514","n1515","n1506"],"tags":{"building":"house"}},"w316":{"id":"w316","nodes":["n1516","n1517","n1518","n1519","n1520","n1521","n1522","n1523","n1516"],"tags":{"building":"house"}},"w317":{"id":"w317","nodes":["n1524","n1525","n1526","n1527","n1528","n1529","n1530","n1531","n1524"],"tags":{"building":"house"}},"w318":{"id":"w318","nodes":["n1532","n1533"],"tags":{"barrier":"fence"}},"w319":{"id":"w319","nodes":["n1534","n1532","n1535"],"tags":{"barrier":"fence"}},"w32":{"id":"w32","nodes":["n159","n160","n161","n162","n159"],"tags":{"amenity":"parking"}},"w320":{"id":"w320","nodes":["n1536","n1537","n1538","n1539","n1536"],"tags":{"building":"shed"}},"w321":{"id":"w321","nodes":["n1540","n1541","n1542","n1543","n1540"],"tags":{"building":"shed"}},"w322":{"id":"w322","nodes":["n1544","n1545","n1546","n1547","n1544"],"tags":{"building":"shed"}},"w323":{"id":"w323","nodes":["n1548","n1549","n1550","n1551","n1548"],"tags":{"building":"house"}},"w324":{"id":"w324","nodes":["n1552","n1553","n1554","n1555","n1556","n1557","n1558","n1559","n1552"],"tags":{"building":"house"}},"w325":{"id":"w325","nodes":["n1560","n1561","n1562","n1563","n1564","n1565","n1566","n1567","n1560"],"tags":{"building":"house"}},"w326":{"id":"w326","nodes":["n1561","n1568","n1569","n1570"],"tags":{"barrier":"wall"}},"w327":{"id":"w327","nodes":["n1571","n1572"],"tags":{"barrier":"fence"}},"w328":{"id":"w328","nodes":["n1573","n1574","n1575","n1576","n1573"],"tags":{"building":"house"}},"w329":{"id":"w329","nodes":["n1577","n1578","n1579","n1580","n1581","n1582","n1583","n1584","n1585","n1586","n1577"],"tags":{"building":"house"}},"w33":{"id":"w33","nodes":["n157","n163"],"tags":{"highway":"service"}},"w330":{"id":"w330","nodes":["n1587","n1588","n1589","n1590","n1591","n1592","n1593","n1594","n1587"],"tags":{"building":"house"}},"w331":{"id":"w331","nodes":["n1595","n1596","n1597","n1598","n1599","n1600","n1601","n1595"],"tags":{"access":"private","leisure":"swimming_pool"}},"w332":{"id":"w332","nodes":["n1602","n1603","n1604","n1605","n1606","n1607","n1608","n1609","n1611","n1610","n1612","n1613","n1602"],"tags":{"building":"house"}},"w333":{"id":"w333","nodes":["n2018","n1626","n1627","n2017","n2018"],"tags":{"amenity":"shelter","shelter_type":"picnic_shelter"}},"w334":{"id":"w334","nodes":["n2","n3","n2764"],"tags":{"highway":"service","name":"Water Street"}},"w335":{"id":"w335","nodes":["n3","n1628","n1614"],"tags":{"highway":"service"}},"w336":{"id":"w336","nodes":["n3198","n4545","n2747"],"tags":{"highway":"residential","name":"Morris Avenue"}},"w337":{"id":"w337","nodes":["n1629","n3504"],"tags":{"highway":"service","service":"alley","surface":"unpaved"}},"w338":{"id":"w338","nodes":["n1813","n1635","n1814","n1634","n1815","n1632","n1816","n1817"],"tags":{"highway":"service","service":"parking_aisle"}},"w339":{"id":"w339","nodes":["n1827","n4684","n4690","n1842","n4686","n4685","n1826","n1828","n1846","n1645","n1637","n4703","n1641"],"tags":{"highway":"residential","name":"Millard Street"}},"w34":{"id":"w34","nodes":["n164","n165","n166","n171","n866","n172","n167","n168","n169","n910","n170","n164"],"tags":{"amenity":"parking"}},"w340":{"id":"w340","nodes":["n1824","n1825"],"tags":{"highway":"service","service":"parking_aisle"}},"w341":{"id":"w341","nodes":["n1701","n1702","n1703","n1704","n1705","n1706","n1701"],"tags":{"building":"yes"}},"w342":{"id":"w342","nodes":["n1855","n1860","n1856","n1775","n1804","n1776","n1855"],"tags":{"amenity":"parking","fee":"no"}},"w343":{"id":"w343","nodes":["n1757","n1758","n1759","n1760","n1757"],"tags":{"building":"yes"}},"w344":{"id":"w344","nodes":["n1659","n1660","n1661","n1662","n1663","n1664","n1665","n1666","n1659"],"tags":{"building":"school"}},"w345":{"id":"w345","nodes":["n1751","n1752","n1753","n1754","n1755","n1756","n1751"],"tags":{"building":"yes"}},"w346":{"id":"w346","nodes":["n1641","n1676","n1673","n1639","n1810","n1642","n1849","n4759","n1845"],"tags":{"highway":"residential","name":"Douglas Avenue"}},"w347":{"id":"w347","nodes":["n1642","n1643","n1031","n1630","n845","n1631","n816","n1831","n902","n905","n152","n149","n1832","n1850","n878","n1833","n1852","n42","n1834","n61","n60","n1851","n1835"],"tags":{"highway":"primary","name":"Michigan Avenue"}},"w348":{"id":"w348","nodes":["n1650","n1651","n1652","n1653","n1654","n1655","n1656","n1657","n1658","n1650"],"tags":{"leisure":"playground"}},"w349":{"id":"w349","nodes":["n1861","n1818","n1819","n1820","n1821","n1825","n1823","n1639"],"tags":{"highway":"service"}},"w35":{"id":"w35","nodes":["n168","n167","n172"],"tags":{"barrier":"fence","fence_type":"chain_link"}},"w350":{"id":"w350","nodes":["n1783","n1819","n1784","n1857","n1861","n1858","n1783"],"tags":{"amenity":"parking"}},"w351":{"id":"w351","nodes":["n1717","n1718","n1719","n1720","n1717"],"tags":{"building":"yes"}},"w352":{"id":"w352","nodes":["n1743","n1744","n1745","n1746","n1747","n1748","n1749","n1750","n1743"],"tags":{"building":"yes"}},"w353":{"id":"w353","nodes":["n1637","n1636","n1029","n4715","n1630"],"tags":{"highway":"residential","name":"Lincoln Avenue"}},"w354":{"id":"w354","nodes":["n1713","n1714","n1715","n1716","n1713"],"tags":{"building":"yes"}},"w355":{"id":"w355","nodes":["n1689","n1690","n1691","n1692","n1693","n1694","n1695","n1696","n1689"],"tags":{"building":"yes"}},"w356":{"id":"w356","nodes":["n1631","n4717","n1840","n4745","n1841"],"tags":{"highway":"residential","name":"Hook Avenue"}},"w357":{"id":"w357","nodes":["n1737","n1738","n1739","n1740","n1741","n1742","n1737"],"tags":{"building":"yes"}},"w358":{"id":"w358","nodes":["n1707","n1708","n1709","n1710","n1711","n1712","n1707"],"tags":{"building":"yes"}},"w359":{"id":"w359","nodes":["n1829","n4695","n4697","n1843","n4698","n4701","n1638","n4702","n4705","n1636","n4706","n4707","n1633"],"tags":{"highway":"residential","name":"South Street"}},"w36":{"id":"w36","nodes":["n910","n171","n866","n172"],"tags":{"barrier":"fence","fence_type":"chain_link"}},"w360":{"id":"w360","nodes":["n1767","n1768","n1769","n1770","n1771","n1772","n1773","n1774","n1767"],"tags":{"building":"yes"}},"w361":{"id":"w361","nodes":["n1859","n1860","n1804","n1640","n1805","n1817","n1806","n1644","n1811","n1807","n1808","n3419","n1812","n1790","n3418","n3744","n1809","n1813","n1810"],"tags":{"highway":"service"}},"w362":{"id":"w362","nodes":["n1639","n1683","n4710","n1633"],"tags":{"highway":"residential","name":"South Street","oneway":"yes"}},"w363":{"id":"w363","nodes":["n1646","n1647","n1648","n1649","n1646"],"tags":{"leisure":"pitch","pitch":"basketball"}},"w364":{"id":"w364","nodes":["n3820","n3821","n3822","n3823","n3824","n3825","n3826","n3827","n3828","n3829","n3830","n3838","n3839","n3820"],"tags":{"amenity":"school","name":"Three Rivers Middle School"}},"w365":{"id":"w365","nodes":["n1721","n1722","n1723","n1724","n1725","n1726","n1727","n1728","n1729","n1730","n1731","n1732","n1733","n1734","n1735","n1736","n1721"],"tags":{"building":"yes"}},"w366":{"id":"w366","nodes":["n1791","n1792","n1793","n1794","n1795","n1796","n1798","n1799","n1800","n1801","n1802","n1803","n1791"],"tags":{"amenity":"parking"}},"w367":{"id":"w367","nodes":["n1633","n4708","n4711","n1643","n4712","n1838","n4752","n1839"],"tags":{"highway":"residential","name":"Grant Avenue"}},"w368":{"id":"w368","nodes":["n1853","n1687","n1688","n1854","n1853"],"tags":{"amenity":"library","building":"yes","name":"Three Rivers Public Library"}},"w369":{"id":"w369","nodes":["n1777","n1778","n1779","n1780","n1781","n1782","n1777"],"tags":{"amenity":"parking"}},"w37":{"id":"w37","nodes":["n173","n174","n175","n176","n177","n178","n179","n180","n173"],"tags":{"building":"yes"}},"w370":{"id":"w370","nodes":["n1645","n1638","n858","n4718","n1631"],"tags":{"highway":"residential","name":"Hook Avenue"}},"w371":{"id":"w371","nodes":["n3836","n3835","n4624","n3831","n4632","n3834","n3832","n3833","n3830","n3838","n3839","n3837","n3836"],"tags":{"amenity":"school","name":"Three Rivers High School"}},"w372":{"id":"w372","nodes":["n1697","n1698","n1699","n1700","n1697"],"tags":{"building":"yes"}},"w373":{"id":"w373","nodes":["n2891","n1785","n1786","n3394","n1787","n1788","n1789","n1830","n1836","n1837","n1848","n3409","n2891"],"tags":{"amenity":"parking"}},"w374":{"id":"w374","nodes":["n1761","n1762","n1763","n1764","n1765","n1766","n1761"],"tags":{"building":"yes"}},"w375":{"id":"w375","nodes":["n1822","n1823"],"tags":{"highway":"service","service":"parking_aisle"}},"w376":{"id":"w376","nodes":["n1677","n1678","n1679","n1680","n1681","n1682","n1677"],"tags":{"amenity":"parking"}},"w377":{"id":"w377","nodes":["n1676","n1675","n1674","n1673"],"tags":{"highway":"service","oneway":"yes"}},"w378":{"id":"w378","nodes":["n1667","n1668","n1669","n1670","n1671","n1672","n1667"],"tags":{"amenity":"school","name":"Andrews Elementary School"}},"w379":{"id":"w379","nodes":["n1630","n4714","n1847","n4750","n1844"],"tags":{"highway":"residential","name":"Lincoln Avenue"}},"w38":{"id":"w38","nodes":["n181","n182","n183","n185","n184","n181"],"tags":{"building":"yes"}},"w380":{"id":"w380","nodes":["n1683","n3745","n1686","n1633"],"tags":{"highway":"service","oneway":"yes","service":"parking_aisle"}},"w381":{"id":"w381","nodes":["n2022","n2037"],"tags":{"highway":"footway"}},"w382":{"id":"w382","nodes":["n1826","n1863"],"tags":{"highway":"residential"}},"w383":{"id":"w383","nodes":["n2011","n2012","n739","n2013","n2014","n2029","n2011"],"tags":{"amenity":"shelter","building":"yes","shelter_type":"picnic_shelter"}},"w384":{"id":"w384","nodes":["n2064","n2065","n2066","n2067","n2068","n2069","n2070","n2071","n2072","n2073","n2074","n2075","n2076","n2077","n2078","n2079","n2064"],"tags":{"building":"yes"}},"w385":{"id":"w385","nodes":["n1923","n1924","n1925","n1926","n1927","n1928","n1930","n1929","n1923"],"tags":{"natural":"water"}},"w386":{"id":"w386","nodes":["n1827","n14","n1886","n15","n1887","n16","n1888","n18","n17","n1889","n12","n13","n1890","n485","n1864","n11","n10","n2058","n2036","n1865","n2020","n9","n8","n1866","n295","n1867"],"tags":{"highway":"service"}},"w387":{"id":"w387","nodes":["n1846","n1843","n865","n157","n4721","n1831"],"tags":{"highway":"residential","name":"Andrews Street"}},"w388":{"id":"w388","nodes":["n2019","n2020","n2021","n2022","n2023","n2024","n2025","n2026","n2027","n2028","n2029"],"tags":{"highway":"footway"}},"w389":{"id":"w389","nodes":["n2217","n2222","n2221","n2219","n1877","n1879","n1882","n1883","n484","n1885","n483","n1880","n1881","n1878","n1884","n2223"],"tags":{"name":"Rocky River","waterway":"river"}},"w39":{"id":"w39","nodes":["n185","n186","n187"],"tags":{"barrier":"fence"}},"w390":{"id":"w390","nodes":["n2050","n2051","n2052","n2053","n2050"],"tags":{"amenity":"shelter","shelter_type":"picnic_shelter"}},"w391":{"id":"w391","nodes":["n2089","n2090","n2091","n2092","n2093","n2094","n2311","n2095","n2096","n2097","n2098","n1174","n2099","n751","n43","n2062","n4725","n873","n1832"],"tags":{"highway":"residential","name":"Constantine Street"}},"w392":{"id":"w392","nodes":["n1869","n212","n436","n2281","n2081"],"tags":{"highway":"primary","name":"Michigan Avenue"}},"w393":{"id":"w393","nodes":["n1829","n611","n144","n4694","n602","n1832"],"tags":{"highway":"tertiary","name":"Constantine Street"}},"w394":{"id":"w394","nodes":["n1997","n1998","n2000","n1999"],"tags":{"highway":"service","service":"parking_aisle"}},"w395":{"id":"w395","nodes":["n1835","n1869"],"tags":{"bridge":"yes","highway":"primary","name":"Michigan Avenue"}},"w396":{"id":"w396","nodes":["n2000","n2001"],"tags":{"highway":"service","service":"parking_aisle"}},"w397":{"id":"w397","nodes":["n2082","n4688","n1842","n308","n498","n509","n246","n241","n1867","n4645","n293","n1834"],"tags":{"highway":"residential","name":"Spring Street"}},"w398":{"id":"w398","nodes":["n2015","n2016","n2017","n2018","n2015"],"tags":{"building":"yes"}},"w399":{"id":"w399","nodes":["n2062","n45","n2063","n877","n41","n1852"],"tags":{"highway":"service"}},"w4":{"id":"w4","nodes":["n7","n38","n378","n379","n7"],"tags":{"building":"yes"}},"w40":{"id":"w40","nodes":["n188","n189","n190","n191","n192","n193","n188"],"tags":{"building":"house"}},"w400":{"id":"w400","nodes":["n1968","n1969","n1970","n1971","n2007","n1972","n1973","n1978","n1974","n1977","n1976","n1975","n1968"],"tags":{"amenity":"parking"}},"w401":{"id":"w401","nodes":["n1963","n1964"],"tags":{"bridge":"yes","highway":"footway"}},"w402":{"id":"w402","nodes":["n1892","n1893","n1894","n1895","n1896","n1897","n1898","n1899","n1900","n1901","n1902","n1903","n1892"],"tags":{"addr:city":"Three Rivers","addr:housenumber":"112","addr:postcode":"49093","addr:state":"MI","addr:street":"Spring Street","barrier":"fence","name":"Scidmore Park Petting Zoo","tourism":"zoo","zoo":"petting_zoo"}},"w403":{"id":"w403","nodes":["n1957","n1958","n1959","n481","n1960","n482","n1949"],"tags":{"highway":"path"}},"w404":{"id":"w404","nodes":["n2281","n27","n330","n1987","n1988"],"tags":{"highway":"service"}},"w405":{"id":"w405","nodes":["n2249","n2269","n2270","n2271","n2272","n454","n455","n2273"],"tags":{"highway":"path","name":"Riverwalk Trail"}},"w406":{"id":"w406","nodes":["n1947","n1624","n1625","n2030","n2033","n4658","n4659","n2031","n2032","n2021"],"tags":{"highway":"footway"}},"w407":{"id":"w407","nodes":["n2034","n2036","n2009"],"tags":{"highway":"footway"}},"w408":{"id":"w408","nodes":["n1964","n1965","n2002","n1966","n21","n1967","n1969"],"tags":{"highway":"footway"}},"w409":{"id":"w409","nodes":["n1904","n1905","n1906","n1907","n1908","n1909","n748","n1910","n747","n1911","n749","n1912","n750","n1913","n1922","n1914","n1921","n1915","n746","n1916","n745","n1917","n744","n1918","n743","n742","n1919","n741","n1920","n740","n1904"],"tags":{"natural":"water"}},"w41":{"id":"w41","nodes":["n194","n195","n196","n197","n198","n199","n200","n201","n202","n203","n204","n205","n194"],"tags":{"building":"house"}},"w410":{"id":"w410","nodes":["n1868","n2088"],"tags":{"bridge":"yes","name":"Conrail Railroad","railway":"rail"}},"w411":{"id":"w411","nodes":["n2010","n2019","n2009","n2008","n2058","n2035","n1961","n1962","n1947","n1963"],"tags":{"highway":"footway"}},"w412":{"id":"w412","nodes":["n2290","n2043","n2044","n2045","n1872","n2041","n1873","n2042","n1874","n2046","n2047","n2048","n2049","n2290"],"tags":{"addr:city":"Three Rivers","addr:housenumber":"112","addr:postcode":"49093","addr:state":"MI","addr:street":"Spring Street","leisure":"park","name":"Scidmore Park"}},"w413":{"id":"w413","nodes":["n1831","n876","n4720","n821","n2089"],"tags":{"highway":"residential","name":"Andrews Street"}},"w414":{"id":"w414","nodes":["n2002","n2003","n2004","n2005","n2006","n2007"],"tags":{"highway":"footway"}},"w415":{"id":"w415","nodes":["n1979","n1980","n1981","n1982","n1979"],"tags":{"amenity":"parking"}},"w416":{"id":"w416","nodes":["n2054","n2055","n2056","n2057","n2054"],"tags":{"amenity":"shelter","shelter_type":"picnic_shelter"}},"w417":{"id":"w417","nodes":["n2291","n2292","n2293","n2294","n2295","n2296","n2297","n2298","n2299","n1098","n2300","n2301","n2302","n2303","n2304","n2059","n2060","n2305","n2307","n2306","n2310","n2308","n2309","n2291"],"tags":{"leisure":"park","name":"Memory Isle Park"}},"w418":{"id":"w418","nodes":["n2033","n2034","n2035"],"tags":{"highway":"footway"}},"w419":{"id":"w419","nodes":["n1983","n1984","n1985","n1986","n1983"],"tags":{"amenity":"parking"}},"w42":{"id":"w42","nodes":["n206","n207","n208","n209","n210","n211","n206"],"tags":{"building":"house"}},"w420":{"id":"w420","nodes":["n1840","n4746","n4748","n1847","n4749","n4755","n1838","n4754","n4756","n1849"],"tags":{"highway":"residential","name":"French Street"}},"w421":{"id":"w421","nodes":["n2337","n2268"],"tags":{"highway":"path"}},"w422":{"id":"w422","nodes":["n2338","n2339","n2320","n2317","n2319","n2318","n2340","n2341","n2342","n2343","n2344","n2345","n2346","n2347","n2348","n2338"],"tags":{"natural":"water"}},"w423":{"id":"w423","nodes":["n2180","n2349","n2350","n2351","n2352","n2404","n2353","n2354","n2355","n2356","n2357","n2358","n2359","n2360","n2361","n2362","n2363","n2364","n2365","n2366","n2370","n2371","n2372","n2373","n2374","n2375","n2377","n2378","n2380","n2381","n2382","n2383","n2386","n2389","n2390","n2391","n2392","n2393","n2396","n2397","n2401","n2402","n2321","n2322","n2323","n2403","n2180"],"tags":{"natural":"wetland"}},"w424":{"id":"w424","nodes":["n2324","n2316","n1841","n2315","n2314","n1844","n1839","n4758","n1845"],"tags":{"highway":"residential","name":"Pealer Street"}},"w425":{"id":"w425","nodes":["n2267","n2337","n2336","n2335","n2334","n2333","n2332","n2331","n2330","n37","n2329","n2328","n2327","n36","n2326","n2325","n2266"],"tags":{"highway":"path","name":"Riverwalk Trail"}},"w426":{"id":"w426","nodes":["n2478","n681","n680","n679","n2459","n2467","n2487","n2478"],"tags":{"building":"yes"}},"w427":{"id":"w427","nodes":["n2671","n2672","n2673","n2674","n2671"],"tags":{"building":"yes"}},"w428":{"id":"w428","nodes":["n2483","n2482","n2486","n2489","n2492","n2502","n2495","n2480","n2483"],"tags":{"building":"yes"}},"w429":{"id":"w429","nodes":["n2707","n2708","n2716","n2712","n2714","n2713","n2715","n2711","n2710","n2723","n2709","n2707"],"tags":{"amenity":"parking"}},"w43":{"id":"w43","nodes":["n1955","n1956"],"tags":{"footway":"sidewalk","highway":"footway","name":"Riverwalk Trail"}},"w430":{"id":"w430","nodes":["n2471","n2474","n2484","n2479","n2471"],"tags":{"building":"yes"}},"w431":{"id":"w431","nodes":["n2218","n2434","n2436","n2433","n2435","n2210"],"tags":{"name":"Rocky River","waterway":"river"}},"w432":{"id":"w432","nodes":["n2782","n2532","n2783","n2784","n2782"],"tags":{"amenity":"parking"}},"w433":{"id":"w433","nodes":["n2513","n649","n2520","n2514","n2507","n2513"],"tags":{"building":"yes"}},"w434":{"id":"w434","nodes":["n2470","n2468","n2461","n2465","n2470"],"tags":{"building":"yes"}},"w435":{"id":"w435","nodes":["n2598","n2599","n648","n649","n2520","n2598"],"tags":{"building":"yes"}},"w436":{"id":"w436","nodes":["n2639","n2640","n2641","n2642","n2643","n2644","n2645","n2646","n2647","n2648","n2639"],"tags":{"building":"yes"}},"w437":{"id":"w437","nodes":["n2503","n2512","n2508","n2499","n2503"],"tags":{"building":"yes"}},"w438":{"id":"w438","nodes":["n2440","n2800","n2774","n1"],"tags":{"highway":"residential","name":"Water Street"}},"w439":{"id":"w439","nodes":["n2675","n2676","n2677","n2678","n2675"],"tags":{"building":"yes"}},"w44":{"id":"w44","nodes":["n213","n214","n215","n216","n213"],"tags":{"building":"yes"}},"w440":{"id":"w440","nodes":["n2512","n2503","n2507","n2514","n2512"],"tags":{"building":"yes"}},"w441":{"id":"w441","nodes":["n2554","n2717","n674","n2720","n2798"],"tags":{"highway":"service","oneway":"yes"}},"w442":{"id":"w442","nodes":["n2583","n2596","n2584","n2585","n2595","n2586","n2587","n2588","n2589","n2583"],"tags":{"amenity":"parking"}},"w443":{"id":"w443","nodes":["n2629","n2627","n2628","n2616","n2630","n2629"],"tags":{"building":"yes"}},"w444":{"id":"w444","nodes":["n2717","n2724","n670","n2718","n669","n668","n2722","n2727"],"tags":{"highway":"service","oneway":"yes","service":"parking_aisle"}},"w445":{"id":"w445","nodes":["n2572","n2573"],"tags":{"bridge":"yes","highway":"path","name":"Riverwalk Trail"}},"w446":{"id":"w446","nodes":["n2603","n2604","n2601","n2605","n2606","n2607","n2603"],"tags":{"building":"yes"}},"w447":{"id":"w447","nodes":["n2780","n2777","n628","n624","n2779"],"tags":{"highway":"residential","name":"Foster Street","oneway":"yes"}},"w448":{"id":"w448","nodes":["n2733","n2734","n2735","n2736","n2737","n2738","n663","n664","n2739","n2733"],"tags":{"building":"yes"}},"w449":{"id":"w449","nodes":["n2564","n2565","n2566","n2567","n2568","n2794","n2795","n2564"],"tags":{"amenity":"parking"}},"w45":{"id":"w45","nodes":["n217","n218","n219","n220","n217"],"tags":{"amenity":"shelter","shelter_type":"picnic_shelter"}},"w450":{"id":"w450","nodes":["n2799","n2728","n2729","n2730","n2731","n2732","n2799"],"tags":{"building":"yes"}},"w451":{"id":"w451","nodes":["n2441","n1170","n2442","n2575","n2443","n2445","n2444","n2448","n2441"],"tags":{"amenity":"parking"}},"w452":{"id":"w452","nodes":["n2273","n457","n2569","n458","n2570"],"tags":{"highway":"path","name":"Riverwalk Trail"}},"w453":{"id":"w453","nodes":["n2447","n2242","n2448","n2527","n2530"],"tags":{"highway":"service"}},"w454":{"id":"w454","nodes":["n2560","n333","n2561"],"tags":{"highway":"service","service":"parking_aisle"}},"w455":{"id":"w455","nodes":["n2679","n2680","n2681","n2682","n2683","n2684","n2685","n2686","n2687","n2688","n2689","n2690","n2679"],"tags":{"building":"yes"}},"w456":{"id":"w456","nodes":["n2425","n2429","n2424"],"tags":{"bridge":"yes","highway":"residential","name":"Moore Street"}},"w457":{"id":"w457","nodes":["n2487","n2467","n2472","n2480","n2495","n2487"],"tags":{"building":"yes"}},"w458":{"id":"w458","nodes":["n2659","n2660","n2661","n2662","n678","n677","n2663","n2664","n2665","n2666","n675","n676","n2659"],"tags":{"building":"yes"}},"w459":{"id":"w459","nodes":["n2600","n2598","n2599","n2601","n2605","n2602","n2600"],"tags":{"building":"yes"}},"w46":{"id":"w46","nodes":["n221","n222","n223","n224","n221"],"tags":{"amenity":"shelter","shelter_type":"picnic_shelter"}},"w460":{"id":"w460","nodes":["n2468","n2464","n2455","n2457","n2461","n2468"],"tags":{"building":"yes"}},"w461":{"id":"w461","nodes":["n2478","n2473","n683","n682","n2463","n681","n2478"],"tags":{"building":"yes"}},"w462":{"id":"w462","nodes":["n2547","n473","n2548","n2549"],"tags":{"highway":"service","service":"parking_aisle"}},"w463":{"id":"w463","nodes":["n2573","n2574"],"tags":{"highway":"path","name":"Riverwalk Trail"}},"w464":{"id":"w464","nodes":["n2445","n2597","n2527","n2528","n2529","n2530","n2531","n2597"],"tags":{"highway":"service","service":"parking_aisle"}},"w465":{"id":"w465","nodes":["n2571","n459","n2572"],"tags":{"highway":"path","name":"Riverwalk Trail"}},"w466":{"id":"w466","nodes":["n2445","n2574","n2552","n442","n2551","n4727","n323","n2446"],"tags":{"highway":"service"}},"w467":{"id":"w467","nodes":["n2484","n2474","n2477","n2485","n2488","n2484"],"tags":{"building":"yes"}},"w468":{"id":"w468","nodes":["n2695","n2696","n2697","n2698","n2699","n2700","n2701","n2702","n2695"],"tags":{"building":"yes"}},"w469":{"id":"w469","nodes":["n2469","n2476","n2481","n2475","n920","n2466","n2469"],"tags":{"building":"yes"}},"w47":{"id":"w47","nodes":["n1988","n1997","n1989","n25","n24","n1990","n26","n1991","n21","n1992","n2006","n1993","n22","n1994","n23","n1995","n1999","n1996","n2001","n1988"],"tags":{"highway":"service"}},"w470":{"id":"w470","nodes":["n2473","n2470","n2465","n2458","n2462","n683","n2473"],"tags":{"building":"yes"}},"w471":{"id":"w471","nodes":["n2490","n2496","n994","n997","n998","n996","n995","n2485","n2477","n2490"],"tags":{"building":"yes"}},"w472":{"id":"w472","nodes":["n2424","n2426","n2427","n2428"],"tags":{"highway":"residential","name":"Moore Street"}},"w473":{"id":"w473","nodes":["n2432","n1026","n4741","n2554","n2425"],"tags":{"highway":"residential","name":"Moore Street"}},"w474":{"id":"w474","nodes":["n2577","n2576"],"tags":{"bridge":"yes","highway":"footway"}},"w475":{"id":"w475","nodes":["n2497","n2505","n2500","n2493","n2497"],"tags":{"building":"yes"}},"w476":{"id":"w476","nodes":["n2493","n2500","n2501","n2496","n2490","n2493"],"tags":{"building":"yes"}},"w477":{"id":"w477","nodes":["n2431","n360","n4726","n418","n397","n396","n2547","n646","n2447","n644","n2418","n424","n640","n2419","n2420","n2423"],"tags":{"highway":"residential","name":"Railroad Drive"}},"w478":{"id":"w478","nodes":["n2515","n2511","n2498","n2504","n2509","n2515"],"tags":{"building":"yes"}},"w479":{"id":"w479","nodes":["n2525","n651","n650","n2526","n2524","n653","n652","n656","n2523","n654","n2518","n2517","n2521","n2522","n2525"],"tags":{"building":"yes"}},"w48":{"id":"w48","nodes":["n225","n237","n226","n227","n228","n229","n230","n231","n232","n233","n234","n235","n236","n225"],"tags":{"building":"yes"}},"w480":{"id":"w480","nodes":["n2703","n2704","n2710","n2711","n2705","n2706","n2703"],"tags":{"amenity":"parking"}},"w481":{"id":"w481","nodes":["n2796","n2657","n2658","n2797","n2796"],"tags":{"building":"yes"}},"w482":{"id":"w482","nodes":["n2550","n2551","n442","n2552","n2553","n2550"],"tags":{"amenity":"parking"}},"w483":{"id":"w483","nodes":["n2790","n2542"],"tags":{"highway":"service","service":"parking_aisle"}},"w484":{"id":"w484","nodes":["n2311","n1102"],"tags":{"highway":"service"}},"w485":{"id":"w485","nodes":["n2515","n2509","n2516","n2519","n2515"],"tags":{"building":"yes"}},"w486":{"id":"w486","nodes":["n2506","n2502","n2492","n2491","n2494","n2506"],"tags":{"building":"yes"}},"w487":{"id":"w487","nodes":["n2667","n2668","n2669","n2670","n2667"],"tags":{"building":"yes"}},"w488":{"id":"w488","nodes":["n2616","n2608","n2617","n2618","n2619","n2620","n2621","n2622","n2623","n2624","n2625","n2626","n2627","n2628","n2616"],"tags":{"building":"yes"}},"w489":{"id":"w489","nodes":["n2081","n2430"],"tags":{"bridge":"yes","highway":"primary","name":"Michigan Avenue"}},"w49":{"id":"w49","nodes":["n237","n238"],"tags":{"highway":"footway"}},"w490":{"id":"w490","nodes":["n2410","n636","n730","n635","n2409","n2694","n2751","n2765","n2753","n2768","n2754","n2769","n2745","n2766","n4503","n2763","n4501","n2752","n2781"],"tags":{"highway":"residential","name":"Portage Avenue"}},"w491":{"id":"w491","nodes":["n2578","n2579","n2580","n2581","n2578"],"tags":{"amenity":"shelter","building":"yes","shelter_type":"picnic_shelter"}},"w492":{"id":"w492","nodes":["n2556","n2557","n2558","n2559","n2556"],"tags":{"amenity":"parking"}},"w493":{"id":"w493","nodes":["n2460","n2456","n687","n2453","n2454","n2460"],"tags":{"building":"yes"}},"w494":{"id":"w494","nodes":["n2471","n2479","n2476","n2469","n2471"],"tags":{"building":"yes"}},"w495":{"id":"w495","nodes":["n2724","n2725","n673","n672","n671","n2726","n2727"],"tags":{"highway":"service","oneway":"yes","service":"parking_aisle"}},"w496":{"id":"w496","nodes":["n2649","n2650","n2651","n2652","n2653","n2654","n2655","n2656","n2649"],"tags":{"building":"yes"}},"w497":{"id":"w497","nodes":["n2430","n2446","n343","n2101","n2560","n2431","n363","n2748"],"tags":{"highway":"primary","name":"Michigan Avenue"}},"w498":{"id":"w498","nodes":["n2691","n2692","n634","n633","n2693","n2694"],"tags":{"highway":"service"}},"w499":{"id":"w499","nodes":["n2423","n2415","n661","n2416","n2417","n2719","n2721","n2772","n2756","n2773","n2759","n2767"],"tags":{"highway":"residential","name":"West Street"}},"w5":{"id":"w5","nodes":["n380","n381","n382","n383","n429","n430","n380"],"tags":{"building":"yes"}},"w50":{"id":"w50","nodes":["n239","n499","n508","n245","n238","n242","n240"],"tags":{"footway":"sidewalk","highway":"footway"}},"w500":{"id":"w500","nodes":["n2428","n1152","n2421","n2324"],"tags":{"bridge":"yes","highway":"residential","name":"Moore Street"}},"w501":{"id":"w501","nodes":["n2608","n2609","n2610","n2611","n2612","n2613","n2614","n2615","n2617","n2608"],"tags":{"building":"yes"}},"w502":{"id":"w502","nodes":["n2570","n2571"],"tags":{"bridge":"yes","highway":"path","name":"Riverwalk Trail"}},"w503":{"id":"w503","nodes":["n2540","n2542","n2787"],"tags":{"highway":"service"}},"w504":{"id":"w504","nodes":["n2269","n2582","n2250"],"tags":{"highway":"path"}},"w505":{"id":"w505","nodes":["n2631","n2632","n2633","n2634","n2635","n2636","n2637","n2638","n2631"],"tags":{"building":"yes"}},"w506":{"id":"w506","nodes":["n2543","n2544","n2545","n395","n2546","n2543"],"tags":{"amenity":"parking"}},"w507":{"id":"w507","nodes":["n2449","n2450","n2451","n2452","n1162","n2449"],"tags":{"leisure":"pitch","sport":"tennis"}},"w508":{"id":"w508","nodes":["n2554","n1160","n2559","n2558","n659","n2555","n658","n657","n2419"],"tags":{"highway":"service"}},"w509":{"id":"w509","nodes":["n2499","n2508","n2510","n2505","n2497","n2499"],"tags":{"building":"yes"}},"w51":{"id":"w51","nodes":["n241","n242","n243","n244"],"tags":{"highway":"service","surface":"unpaved"}},"w510":{"id":"w510","nodes":["n2575","n2577"],"tags":{"highway":"footway"}},"w511":{"id":"w511","nodes":["n2533","n2534","n2535","n2536","n2537","n2538","n2539","n2785","n2786","n2533"],"tags":{"amenity":"parking"}},"w512":{"id":"w512","nodes":["n2801","n2740","n2741","n2742","n2743","n2744","n2801"],"tags":{"building":"yes"}},"w513":{"id":"w513","nodes":["n2720","n2721"],"tags":{"highway":"service","service":"parking_aisle"}},"w514":{"id":"w514","nodes":["n2788","n2790","n2789","n989","n2540","n2541"],"tags":{"highway":"service","service":"parking_aisle"}},"w515":{"id":"w515","nodes":["n2848","n2849","n2850","n2851","n2803","n2804","n2812"],"tags":{"highway":"residential","name":"Middle Street"}},"w516":{"id":"w516","nodes":["n2852","n2805"],"tags":{"access":"private","highway":"service","name":"Battle Street"}},"w517":{"id":"w517","nodes":["n2863","n2815","n2814","n2812","n2864","n2855","n2865","n2867","n2868"],"tags":{"highway":"secondary","name":"Michigan Avenue","name_1":"State Highway 60","ref":"M 60"}},"w518":{"id":"w518","nodes":["n2859","n2808"],"tags":{"highway":"residential","name":"2nd Avenue"}},"w519":{"id":"w519","nodes":["n2823","n2824","n2825","n2826","n2827","n2828","n2823"],"tags":{"building":"yes"}},"w52":{"id":"w52","nodes":["n247","n248","n249","n250","n247"],"tags":{"amenity":"parking"}},"w520":{"id":"w520","nodes":["n2806","n2807","n2803"],"tags":{"highway":"residential","name":"2nd Avenue"}},"w521":{"id":"w521","nodes":["n2829","n2830","n2831","n2832","n2833","n2834","n2835","n2836","n2837","n2838","n2829"],"tags":{"building":"yes"}},"w522":{"id":"w522","nodes":["n2815","n2813","n2811","n4597","n2846","n4596","n2857","n4601","n2853","n4602","n2861","n4","n2879","n4560","n3550","n5","n1685"],"tags":{"highway":"residential","name":"Washington Street"}},"w523":{"id":"w523","nodes":["n2878","n2811","n2810","n2860","n2880","n2881","n2882"],"tags":{"highway":"residential","name":"5th Avenue"}},"w524":{"id":"w524","nodes":["n2816","n2817","n2818","n2819","n2820","n2821","n2822","n2816"],"tags":{"building":"yes"}},"w525":{"id":"w525","nodes":["n2869","n2856","n2806","n2808","n2814","n2809","n2810","n2847","n2858","n2854","n2870","n2871","n6","n2872","n2839","n2862"],"tags":{"highway":"residential","name":"Wood Street"}},"w526":{"id":"w526","nodes":["n2877","n2809","n2813","n2844","n2843"],"tags":{"highway":"residential","name":"4th Avenue"}},"w527":{"id":"w527","nodes":["n4785","n4784","n2936","n4788","n4787","n4786","n4785"],"tags":{"amenity":"parking"}},"w528":{"id":"w528","nodes":["n2864","n2892","n2893","n2877","n2860","n3840"],"tags":{"highway":"residential","name":"Garden Street"}},"w529":{"id":"w529","nodes":["n2868","n2890"],"tags":{"bridge":"yes","highway":"secondary","name":"Michigan Avenue","name_1":"State Highway 60","ref":"M 60"}},"w53":{"id":"w53","nodes":["n251","n252","n253","n254","n255","n256","n257","n258","n259","n260","n261","n262","n251"],"tags":{"building":"yes"}},"w530":{"id":"w530","nodes":["n2914","n2915","n2916","n2917","n2918","n2919","n2920","n2921","n2922","n2923","n2924","n2925","n2926","n2927","n2928","n2929","n2930","n2931","n2932","n2933","n2914"],"tags":{"building":"yes"}},"w531":{"id":"w531","nodes":["n2958","n2896"],"tags":{"bridge":"yes","highway":"secondary","name":"Main Street"}},"w532":{"id":"w532","nodes":["n2896","n394","n364","n2748"],"tags":{"highway":"secondary","name":"Main Street"}},"w533":{"id":"w533","nodes":["n2800","n2943","n2940","n2941","n2942","n2943"],"tags":{"highway":"service","service":"parking_aisle"}},"w534":{"id":"w534","nodes":["n3836","n3837","n3839","n3838","n3834","n4632","n3831","n4624","n3835","n3836"],"tags":{"barrier":"fence"}},"w535":{"id":"w535","nodes":["n2894","n2944","n2774","n2765"],"tags":{"highway":"residential","name":"5th Avenue"}},"w536":{"id":"w536","nodes":["n2890","n2780","n627","n2889","n2887","n623","n2888","n366","n2748"],"tags":{"highway":"secondary","name":"Michigan Avenue","name_1":"State Highway 60","ref":"M 60"}},"w537":{"id":"w537","nodes":["n2895","n738","n2887","n737","n2913"],"tags":{"highway":"residential","name":"Water Street"}},"w538":{"id":"w538","nodes":["n2855","n3756","n2884","n2885","n2886","n2945","n2946","n2947","n2948","n2949","n2950","n2951","n2952","n2953","n2955","n2848","n2956","n2856"],"tags":{"highway":"residential","name":"River Drive"}},"w539":{"id":"w539","nodes":["n2882","n2894"],"tags":{"bridge":"yes","highway":"residential","name":"5th Avenue"}},"w54":{"id":"w54","nodes":["n263","n264","n265","n266","n267","n268","n269","n270","n271","n272","n273","n274","n275","n276","n263"],"tags":{"building":"yes"}},"w540":{"id":"w540","nodes":["n2987","n2964","n2981","n2983","n2966","n2982","n2962","n2960","n2967","n2965","n2984","n2977","n2968","n2976","n2986","n2988","n2963","n2970","n2969","n2979","n2974","n2980","n2959","n2973","n2985","n2961","n2975","n2971","n2972","n2978","n2898","n2907","n2912","n2909","n2911","n2901","n2903","n2904","n2906","n2902","n2900","n2910","n2908","n2899","n2897","n2905","n2186","n2233"],"tags":{"name":"Portage River","waterway":"river"}},"w541":{"id":"w541","nodes":["n2852","n2851","n3003"],"tags":{"highway":"residential","name":"1st Avenue"}},"w542":{"id":"w542","nodes":["n2991","n3004","n2994"],"tags":{"highway":"residential","name":"River Street"}},"w543":{"id":"w543","nodes":["n2993","n2989"],"tags":{"bridge":"yes","highway":"residential","name":"6th Street"}},"w544":{"id":"w544","nodes":["n2995","n2996","n2997","n2998","n2999","n3000","n3001","n3002","n2990","n2991","n2993"],"tags":{"highway":"residential","name":"6th Street"}},"w545":{"id":"w545","nodes":["n2989","n2992","n2848"],"tags":{"highway":"residential","name":"6th Street"}},"w546":{"id":"w546","nodes":["n2313","n3169","n3170","n3171","n3172","n3173","n3174","n3175","n3176","n3177","n3178","n3179","n3180","n3191","n3181","n3190","n3182","n3183","n3184","n3185","n3186","n3187","n3188","n3189","n3160","n3161","n3162","n2126","n2146","n2156","n2129","n2112","n2109","n2313"],"tags":{"natural":"wetland"}},"w547":{"id":"w547","nodes":["n2088","n3013","n3015","n3014","n3017","n3018"],"tags":{"name":"Conrail Railroad","railway":"rail"}},"w548":{"id":"w548","nodes":["n3083","n3084","n3085","n3086","n3083"],"tags":{"building":"yes"}},"w549":{"id":"w549","nodes":["n3020","n2288","n2283","n2284","n2131","n2286","n2287","n2285","n2132","n2140","n2289","n3020"],"tags":{"leisure":"park","name":"Conservation Park"}},"w55":{"id":"w55","nodes":["n277","n278","n279","n280","n281","n282","n283","n284","n277"],"tags":{"building":"yes"}},"w550":{"id":"w550","nodes":["n3056","n3042","n3041","n3040","n3039","n3038","n3037","n3036","n3044","n3035","n3034","n3043","n3016","n3056","n3019","n3015","n3012"],"tags":{"highway":"service"}},"w551":{"id":"w551","nodes":["n3044","n3045","n3046","n3047","n3048","n3049","n3050","n3051","n3052","n3053","n3054","n3055","n3016"],"tags":{"highway":"footway"}},"w552":{"id":"w552","nodes":["n3117","n3118","n3119","n3120","n3121","n3122","n3117"],"tags":{"building":"yes"}},"w553":{"id":"w553","nodes":["n3123","n3124","n3129","n3125","n3126","n3123"],"tags":{"building":"yes"}},"w554":{"id":"w554","nodes":["n3069","n3070","n3071","n3072","n3073","n3074","n3075","n3076","n3077","n3078","n3079","n3080","n3081","n3082","n3069"],"tags":{"building":"yes"}},"w555":{"id":"w555","nodes":["n3087","n3088","n3089","n3090","n3087"],"tags":{"building":"yes"}},"w556":{"id":"w556","nodes":["n3113","n3114","n3115","n3116","n3113"],"tags":{"building":"yes"}},"w557":{"id":"w557","nodes":["n3103","n3104","n3105","n3106","n3103"],"tags":{"building":"yes"}},"w558":{"id":"w558","nodes":["n3127","n3128","n3129","n3124","n3127"],"tags":{"building":"yes"}},"w559":{"id":"w559","nodes":["n3137","n3141","n3142","n3138","n3139","n3140","n3137"],"tags":{"building":"yes"}},"w56":{"id":"w56","nodes":["n285","n286","n287","n288","n285"],"tags":{"amenity":"parking"}},"w560":{"id":"w560","nodes":["n3091","n3092","n3093","n3094","n3091"],"tags":{"building":"yes"}},"w561":{"id":"w561","nodes":["n3155","n3157","n3158","n3159","n3156","n3155"],"tags":{"building":"yes"}},"w562":{"id":"w562","nodes":["n3057","n3058","n3059","n3060","n3057"],"tags":{"building":"yes"}},"w563":{"id":"w563","nodes":["n3107","n3108","n3109","n3110","n3111","n3112","n3107"],"tags":{"building":"yes"}},"w564":{"id":"w564","nodes":["n3134","n3135","n3136","n3131","n3134"],"tags":{"building":"yes"}},"w565":{"id":"w565","nodes":["n3143","n3144","n3145","n3146","n3143"],"tags":{"building":"yes"}},"w566":{"id":"w566","nodes":["n3095","n3096","n3097","n3098","n3095"],"tags":{"building":"yes"}},"w567":{"id":"w567","nodes":["n3130","n3131","n3136","n3132","n3133","n3130"],"tags":{"building":"yes"}},"w568":{"id":"w568","nodes":["n3025","n3026","n3027","n3028","n3029","n3030","n3031","n3033","n3032","n3025"],"tags":{"amenity":"parking"}},"w569":{"id":"w569","nodes":["n3061","n3062","n3063","n3064","n3061"],"tags":{"building":"yes"}},"w57":{"id":"w57","nodes":["n289","n290","n291","n292","n289"],"tags":{"amenity":"parking"}},"w570":{"id":"w570","nodes":["n3155","n3156","n3152","n3153","n3155"],"tags":{"building":"yes"}},"w571":{"id":"w571","nodes":["n3099","n3100","n3101","n3102","n3099"],"tags":{"building":"yes"}},"w572":{"id":"w572","nodes":["n3147","n3148","n3149","n3150","n3147"],"tags":{"building":"yes"}},"w573":{"id":"w573","nodes":["n3039","n2284"],"tags":{"highway":"service"}},"w574":{"id":"w574","nodes":["n3151","n3152","n3153","n3154","n3151"],"tags":{"building":"yes"}},"w575":{"id":"w575","nodes":["n3021","n3022","n3023","n3024","n3021"],"tags":{"amenity":"shelter","shelter_type":"picnic_shelter"}},"w576":{"id":"w576","nodes":["n3065","n3066","n3067","n3068","n3065"],"tags":{"building":"yes"}},"w577":{"id":"w577","nodes":["n2944","n3192","n3757","n3813","n3814","n3815","n3816","n3817","n3818","n3819"],"tags":{"highway":"service","name":"Willow Drive","service":"driveway","surface":"unpaved"}},"w578":{"id":"w578","nodes":["n2163","n2165","n2166","n2167","n2168","n2172","n2173","n2174","n2175","n2176","n2178","n2181","n2163"],"tags":{"building":"yes"}},"w579":{"id":"w579","nodes":["n2754","n3195","n3204","n3205","n4537","n4540","n3206","n4530","n4536","n3207","n4524","n3199","n4521","n3197","n1032"],"tags":{"highway":"residential","name":"Elm Street"}},"w58":{"id":"w58","nodes":["n240","n293","n294"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w580":{"id":"w580","nodes":["n2184","n2185","n2187","n2190","n2191","n2192","n2184"],"tags":{"building":"yes"}},"w581":{"id":"w581","nodes":["n2765","n3208","n3211","n2755","n3280","n2756","n3346"],"tags":{"highway":"residential","name":"Kelsey Street"}},"w582":{"id":"w582","nodes":["n2753","n3194","n3193","n3201","n3196","n4551","n3202","n4550","n3203","n3200","n3198","n1033"],"tags":{"highway":"residential","name":"Walnut Street"}},"w583":{"id":"w583","nodes":["n3272","n4469","n4588","n2879","n4564","n2872"],"tags":{"highway":"residential","name":"10th Avenue"}},"w584":{"id":"w584","nodes":["n3243","n3242","n3241","n3240","n3243"],"tags":{"building":"industrial"}},"w585":{"id":"w585","nodes":["n3273","n3274","n4631","n4593","n3275","n4592","n2846","n4611","n2847"],"tags":{"highway":"residential","name":"6th Avenue"}},"w586":{"id":"w586","nodes":["n3276","n4591","n2853","n4605","n2854"],"tags":{"highway":"residential","name":"8th Avenue"}},"w587":{"id":"w587","nodes":["n3269","n3268","n3267","n3266","n3265","n3264","n3263","n3262","n3269"],"tags":{"building":"industrial"}},"w588":{"id":"w588","nodes":["n3277","n4599","n2857","n4598","n4608","n2858"],"tags":{"highway":"residential","name":"7th Avenue"}},"w589":{"id":"w589","nodes":["n3239","n3238","n3271","n3270","n3237","n3236","n3235","n3234","n3239"],"tags":{"building":"yes"}},"w59":{"id":"w59","nodes":["n294","n295","n296","n297","n298","n299","n300","n301","n302","n303","n491","n304","n305","n306","n307"],"tags":{"footway":"sidewalk","highway":"footway"}},"w590":{"id":"w590","nodes":["n3278","n4458","n4589","n4604","n2861"],"tags":{"highway":"residential","name":"9th Avenue"}},"w591":{"id":"w591","nodes":["n3253","n3252","n3251","n3250","n3249","n3248","n3253"],"tags":{"building":"industrial"}},"w592":{"id":"w592","nodes":["n3229","n3228","n3227","n3226","n3225","n3224","n3223","n3222","n3221","n3220","n3219","n3218","n3217","n3216","n3215","n3214","n3213","n3212","n3229"],"tags":{"natural":"water","water":"pond"}},"w593":{"id":"w593","nodes":["n3261","n3260","n3259","n3258","n3257","n3256","n3255","n3254","n3261"],"tags":{"building":"industrial"}},"w594":{"id":"w594","nodes":["n3233","n3232","n3231","n3230","n3233"],"tags":{"building":"yes"}},"w595":{"id":"w595","nodes":["n3247","n3246","n3245","n3244","n3247"],"tags":{"building":"industrial"}},"w596":{"id":"w596","nodes":["n2769","n3195","n3193","n3209","n2758","n2759","n3279"],"tags":{"highway":"residential","name":"Armitage Street"}},"w597":{"id":"w597","nodes":["n2193","n2194","n2195","n2197","n2193"],"tags":{"building":"yes"}},"w598":{"id":"w598","nodes":["n3404","n3403","n3402","n3401","n3400","n3399","n3398","n3397","n3373","n3372","n3396","n3395","n3404"],"tags":{"building":"school"}},"w6":{"id":"w6","nodes":["n879","n880","n881","n882","n879"],"tags":{"building":"shed"}},"w60":{"id":"w60","nodes":["n239","n308","n307"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w600":{"id":"w600","nodes":["n3387","n3386","n3316","n3315","n3314","n3313","n3387"],"tags":{"building":"yes"}},"w601":{"id":"w601","nodes":["n3304","n3303","n3302","n3301","n3385","n3384","n3300","n3299","n3304"],"tags":{"building":"yes"}},"w602":{"id":"w602","nodes":["n3334","n3333","n3332","n3331","n3330","n3329","n3328","n3327","n3326","n3325","n3324","n3323","n3322","n3321","n3320","n3319","n3318","n3317","n3334"],"tags":{"building":"yes"}},"w603":{"id":"w603","nodes":["n3353","n3352","n3347","n3280","n2798"],"tags":{"highway":"service","service":"alley","surface":"unpaved"}},"w604":{"id":"w604","nodes":["n3753","n3211","n3383"],"tags":{"highway":"service","service":"alley"}},"w605":{"id":"w605","nodes":["n3290","n3289","n3288","n3287","n3286","n3285","n3284","n3283","n3282","n3281","n3290"],"tags":{"building":"yes"}},"w606":{"id":"w606","nodes":["n2198","n2199","n2201","n2202","n2203","n2206","n2198"],"tags":{"building":"yes"}},"w607":{"id":"w607","nodes":["n2198","n2207"],"tags":{"barrier":"wall"}},"w608":{"id":"w608","nodes":["n2751","n3208","n3210","n3209","n3415","n3410","n3414","n3413","n3412","n3416"],"tags":{"highway":"residential","name":"East Street"}},"w609":{"id":"w609","nodes":["n2772","n3346","n3746","n3748","n3747","n3345","n3378","n3279","n3411"],"tags":{"highway":"residential","name":"Maple Street"}},"w61":{"id":"w61","nodes":["n309","n310","n311","n312","n313","n240"],"tags":{"footway":"sidewalk","highway":"footway"}},"w610":{"id":"w610","nodes":["n3379","n3380","n3382","n3381","n3379"],"tags":{"leisure":"park","name":"LaFayette Park"}},"w611":{"id":"w611","nodes":["n2768","n3194","n3210","n3753","n2760","n3353","n2773","n3378"],"tags":{"highway":"residential","name":"Bennett Street"}},"w612":{"id":"w612","nodes":["n2751","n3383","n2749","n2798","n2772"],"tags":{"highway":"residential","name":"Market Street"}},"w613":{"id":"w613","nodes":["n3298","n3297","n3296","n3295","n3294","n3293","n3292","n3291","n3298"],"tags":{"building":"yes"}},"w614":{"id":"w614","nodes":["n3375","n3406","n3405","n3374","n3375"],"tags":{"leisure":"playground"}},"w615":{"id":"w615","nodes":["n3393","n3344","n3343","n3342","n3341","n3340","n3339","n3338","n3337","n3392","n3391","n3390","n3389","n3336","n3335","n3388","n3393"],"tags":{"building":"yes"}},"w616":{"id":"w616","nodes":["n3376","n3407","n3408","n3377","n3376"],"tags":{"amenity":"school","name":"Three Rivers Elementary School"}},"w617":{"id":"w617","nodes":["n3312","n3311","n3310","n3309","n3308","n3307","n3306","n3305","n3312"],"tags":{"building":"yes"}},"w619":{"id":"w619","nodes":["n2863","n3424","n3425","n3426","n3427","n3428","n3429","n3430","n3431","n3432","n3433","n2844"],"tags":{"highway":"secondary","name":"Michigan Avenue","ref":"M 60"}},"w62":{"id":"w62","nodes":["n876","n906","n904","n875","n874","n873","n872","n871","n870","n869","n41","n868","n146","n314","n315","n1956"],"tags":{"footway":"sidewalk","highway":"footway"}},"w620":{"id":"w620","nodes":["n2844","n3420","n3421","n3422","n3439","n2859","n3437","n3493","n3496","n3500","n3497"],"tags":{"highway":"residential"}},"w621":{"id":"w621","nodes":["n3468","n3469","n3470","n3471","n3468"],"tags":{"building":"yes"}},"w622":{"id":"w622","nodes":["n3417","n3436","n3438","n3491","n3488","n3492","n3495","n3494","n3498","n3487","n3499","n3490","n3489","n4800","n3417"],"tags":{"landuse":"cemetery","name":"Riverside Cemetery"}},"w623":{"id":"w623","nodes":["n3440","n3441","n3442","n3443","n3444","n3445","n3440"],"tags":{"building":"yes"}},"w624":{"id":"w624","nodes":["n3446","n3447","n3448","n3449","n3450","n3451","n3452","n3453","n3454","n3455","n3456","n3457","n3458","n3459","n3460","n3461","n3462","n3463","n3464","n3465","n3466","n3467","n3446"],"tags":{"building":"yes"}},"w625":{"id":"w625","nodes":["n2844","n3434","n3435","n2878","n3275","n4621","n3276","n3278","n4463","n3272","n3472","n3474","n3475","n3476","n3477","n3478","n1202","n3479","n3480","n3481","n1203","n3482","n3483","n3484","n3485","n4574","n3486","n3473"],"tags":{"highway":"secondary","name":"Jefferson Street","name_1":"State Highway 60","ref":"M 60"}},"w626":{"id":"w626","nodes":["n3439","n3423","n2863"],"tags":{"highway":"unclassified","name":"Michigan Avenue","name_1":"State Highway 60"}},"w627":{"id":"w627","nodes":["n3500","n3005"],"tags":{"highway":"service"}},"w628":{"id":"w628","nodes":["n3491","n3488","n3492","n3010","n3009","n3005","n3008","n3007","n3006","n3502","n3491"],"tags":{"leisure":"park","name":"Marina Park"}},"w629":{"id":"w629","nodes":["n2208","n2209","n2212","n2214","n2208"],"tags":{"building":"yes"}},"w63":{"id":"w63","nodes":["n1955","n316"],"tags":{"footway":"sidewalk","highway":"footway"}},"w630":{"id":"w630","nodes":["n2757","n3414","n3202","n4542","n3206","n4538","n3750","n3503","n1629","n4500","n2763","n4502","n2764","n3508"],"tags":{"highway":"residential","name":"Hoffman Street"}},"w631":{"id":"w631","nodes":["n2215","n2750","n2770","n2771","n2215"],"tags":{"building":"yes"}},"w632":{"id":"w632","nodes":["n2766","n3504","n3507","n3751","n3205","n3196","n3410","n2746"],"tags":{"highway":"residential","name":"Cushman Street"}},"w633":{"id":"w633","nodes":["n2745","n3749","n3507","n4535","n3503"],"tags":{"highway":"residential","name":"Pine Street"}},"w634":{"id":"w634","nodes":["n3510","n3511","n3512","n3509","n3510"],"tags":{"leisure":"park","name":"Bowman Park"}},"w636":{"id":"w636","nodes":["n2745","n3752","n3204","n3201","n3415","n2761","n2767","n3411"],"tags":{"highway":"residential","name":"Wheeler Street"}},"w637":{"id":"w637","nodes":["n3550","n4586","n4476","n3472"],"tags":{"highway":"residential","name":"11th Avenue"}},"w638":{"id":"w638","nodes":["n3508","n3518"],"tags":{"bridge":"yes","highway":"residential","name":"Hoffman Street"}},"w639":{"id":"w639","nodes":["n3518","n1204","n2862","n3519","n3520","n3521","n3522","n3523","n2161","n3524","n3549","n3552","n4239","n3551","n4577","n4582","n4578","n4583","n4579","n4574"],"tags":{"highway":"residential","name":"Hoffman Street"}},"w64":{"id":"w64","nodes":["n316","n317"],"tags":{"bridge":"yes","footway":"sidewalk","highway":"footway","layer":"1"}},"w640":{"id":"w640","nodes":["n3634","n3640","n3676","n3633","n3678","n3648","n3638","n3683","n3600","n3579","n3679","n3677","n2987","n3592","n3588","n3608","n3559","n3617","n3620","n3660","n3553","n3533","n3530","n3531","n3525","n3527","n3526","n3532","n3529","n3528","n3667","n3627","n3623","n3625","n3601","n3687","n3671","n3644","n3626","n3673","n3582","n3693","n3605","n3619","n3651","n3650","n3615","n3663","n3631","n3596","n3604","n3655","n3586","n3595","n3701","n3603","n3686","n3611","n3568","n3674","n3613","n3580","n3562","n3564","n3689","n3585","n3670","n3659","n3684","n3680","n3646","n3558","n3556","n3692","n3563","n3575","n3571","n3675","n3557","n3700","n3656","n3622","n3657","n3565","n3669","n3658","n3618","n3624","n3688","n3610","n3570","n3645","n3649","n3583","n3694","n3561","n3554","n3614","n3698","n3581","n3635","n3641","n3569","n3647","n3628","n3598","n3696","n3665","n3639","n3607","n3695","n3642","n3672","n3577","n3643","n3691","n3602","n3576","n3591","n3560","n3606","n3685","n3597","n3629","n3661","n3654","n3616","n3697","n3578","n3609","n3653","n3699","n3566","n3637","n3567","n3666","n3555","n3599","n3590","n3572","n3593","n3690","n3681","n3612","n3682","n3668","n3587","n3621","n3636","n3662","n3589","n3573","n3652","n3664","n3632","n3574","n3594","n3584","n3630","n3634"],"tags":{"landuse":"reservoir","name":"Hoffman Pond","natural":"water"}},"w641":{"id":"w641","nodes":["n2988","n3534","n3535","n3536","n3537","n3538","n3539","n3540","n3541","n3542","n3543","n3544","n3545","n3546","n3547","n3548","n2970"],"tags":{"waterway":"river"}},"w642":{"id":"w642","nodes":["n3702","n3703","n3704","n3705","n3706","n3707","n3708","n3709","n3710","n3711","n3712","n3713","n3714","n3715","n3716","n3717","n3718","n3719","n3720","n3721","n3722","n3723","n3724","n3725","n3726","n3727","n3728","n3729","n3730","n3731","n3732","n3733","n3734","n3735","n3736","n3737","n3738","n3739","n3740","n3741","n3742","n3743","n3702"],"tags":{"admin_level":"8","boundary":"administrative"}},"w643":{"id":"w643","nodes":["n2839","n2873"],"tags":{"highway":"service","service":"driveway"}},"w644":{"id":"w644","nodes":["n2873","n2840"],"tags":{"bridge":"yes","highway":"service","layer":"1","service":"driveway"}},"w645":{"id":"w645","nodes":["n2840","n2841","n2842","n2845","n2866"],"tags":{"highway":"service","service":"driveway","surface":"unpaved"}},"w646":{"id":"w646","nodes":["n2752","n3759","n1420","n1421","n1422","n3758","n4507","n4506","n4505","n4520","n3199","n4522","n4504","n4546","n3200","n4547","n3412"],"tags":{"highway":"residential","name":"Flower Street"}},"w647":{"id":"w647","nodes":["n2874","n2875","n2876","n2954","n2874"],"tags":{"building":"industrial"}},"w648":{"id":"w648","nodes":["n3778","n3779","n3780","n3781","n3782","n3783","n3778"],"tags":{"building":"yes"}},"w649":{"id":"w649","nodes":["n3197","n4543","n4544","n3198"],"tags":{"highway":"residential","name":"Morris Avenue","surface":"unpaved"}},"w65":{"id":"w65","nodes":["n317","n318","n319","n320","n321"],"tags":{"footway":"sidewalk","highway":"footway"}},"w650":{"id":"w650","nodes":["n3207","n4526","n4528","n4548","n3203","n4549","n3413","n2762"],"tags":{"highway":"residential","name":"Adams Street"}},"w651":{"id":"w651","nodes":["n3788","n3785","n3786","n3787","n3788"],"tags":{"power":"station"}},"w652":{"id":"w652","nodes":["n2957","n3163","n3241"],"tags":{"barrier":"wall"}},"w653":{"id":"w653","nodes":["n3549","n3802","n3803","n3800","n3801"],"tags":{"highway":"service","surface":"unpaved"}},"w654":{"id":"w654","nodes":["n3164","n3165","n3166","n3167","n3168","n3505","n3164"],"tags":{"building":"yes"}},"w655":{"id":"w655","nodes":["n3506","n3517","n3760","n3761","n3762","n3763","n3506"],"tags":{"building":"yes"}},"w656":{"id":"w656","nodes":["n3764","n3765","n3766","n3767","n3768","n3769","n3770","n3771","n3764"],"tags":{"building":"yes"}},"w657":{"id":"w657","nodes":["n3772","n3773","n3774","n3775","n3772"],"tags":{"building":"yes"}},"w658":{"id":"w658","nodes":["n3776","n3777","n3784","n3789","n3776"],"tags":{"building":"yes"}},"w659":{"id":"w659","nodes":["n3930","n3931","n3932","n3933","n3934","n3935","n3936","n3937","n3938","n3930"],"tags":{"leisure":"pitch","sport":"baseball"}},"w66":{"id":"w66","nodes":["n321","n322"],"tags":{"bridge":"yes","footway":"sidewalk","highway":"footway","layer":"1"}},"w660":{"id":"w660","nodes":["n3982","n3842","n3864","n3865","n3866","n3867","n3868","n3858","n3869","n3870","n3862"],"tags":{"highway":"service"}},"w661":{"id":"w661","nodes":["n3968","n3969"],"tags":{"highway":"footway"}},"w662":{"id":"w662","nodes":["n3875","n3876","n3877","n3878","n3879","n3880","n3881","n3882","n3875"],"tags":{"amenity":"parking"}},"w663":{"id":"w663","nodes":["n3964","n3965"],"tags":{"highway":"footway"}},"w664":{"id":"w664","nodes":["n3966","n3967"],"tags":{"highway":"footway"}},"w665":{"id":"w665","nodes":["n3857","n3890","n3884","n3894","n3889","n3899","n3885","n3886","n3896","n3887"],"tags":{"highway":"service","service":"parking_aisle"}},"w666":{"id":"w666","nodes":["n3895","n3896"],"tags":{"highway":"service","service":"parking_aisle"}},"w667":{"id":"w667","nodes":["n3274","n3977","n3984","n3983","n3981","n3844","n3978","n3982","n3861","n3862","n3873","n3874","n4468","n3863"],"tags":{"access":"private","highway":"service","name":"Collins Drive"}},"w668":{"id":"w668","nodes":["n3900","n3901","n3902","n3903","n3904","n3905","n3808","n3809","n3906","n3907","n3908","n3967","n3909","n3910","n3911","n3955","n3964","n3912","n3913","n3914","n3915","n3916","n3917","n3918","n3919","n3920","n3921","n3922","n3923","n3924","n3925","n3926","n3927","n3969","n3970","n3928","n3807","n3929","n3900"],"tags":{"building":"school"}},"w669":{"id":"w669","nodes":["n3272","n39","n40","n3974","n3863","n3857","n3892","n3883","n3891","n3889"],"tags":{"highway":"service"}},"w67":{"id":"w67","nodes":["n322","n886","n323","n475"],"tags":{"footway":"crossing","highway":"footway"}},"w670":{"id":"w670","nodes":["n3473","n3859","n3860","n3980","n4908","n4865"],"tags":{"highway":"secondary","name":"Hoffman Street","ref":"M 60"}},"w671":{"id":"w671","nodes":["n3970","n3806","n3971"],"tags":{"highway":"footway"}},"w672":{"id":"w672","nodes":["n3892","n3893","n3894"],"tags":{"highway":"service","service":"parking_aisle"}},"w673":{"id":"w673","nodes":["n3945","n3946","n3992","n3990","n3945"],"tags":{"leisure":"pitch","sport":"tennis"}},"w674":{"id":"w674","nodes":["n3890","n3893","n3891"],"tags":{"highway":"service","service":"parking_aisle"}},"w675":{"id":"w675","nodes":["n3947","n3948","n3994","n3993","n3947"],"tags":{"leisure":"pitch","sport":"tennis"}},"w676":{"id":"w676","nodes":["n3858","n3954","n3972","n3810","n3811","n3812","n3841","n3973","n3898","n3963","n3897","n3896"],"tags":{"highway":"service"}},"w677":{"id":"w677","nodes":["n3977","n3996","n3997","n4004","n3998","n3999","n4005","n4007","n4006","n3995","n4000","n3843","n4001","n4002","n4003","n3949","n3950","n3951","n3952","n3953","n3954","n3956","n3966","n3955"],"tags":{"highway":"footway"}},"w678":{"id":"w678","nodes":["n3887","n3888","n3895","n3899"],"tags":{"highway":"service","service":"parking_aisle"}},"w679":{"id":"w679","nodes":["n3946","n3947","n3993","n3992","n3946"],"tags":{"leisure":"pitch","sport":"tennis"}},"w68":{"id":"w68","nodes":["n294","n1952","n326"],"tags":{"footway":"sidewalk","highway":"footway"}},"w680":{"id":"w680","nodes":["n3939","n3940","n3941","n3985","n3986","n3987","n3988","n3989","n3942","n3943","n3939"],"tags":{"leisure":"pitch","sport":"baseball"}},"w681":{"id":"w681","nodes":["n3990","n3991","n3944","n3945","n3990"],"tags":{"leisure":"pitch","sport":"tennis"}},"w682":{"id":"w682","nodes":["n3871","n3872","n3873","n3874","n3871"],"tags":{"amenity":"parking"}},"w683":{"id":"w683","nodes":["n3956","n3965","n3957","n3958","n3959"],"tags":{"footway":"sidewalk","highway":"footway"}},"w684":{"id":"w684","nodes":["n3790","n3791","n3792","n3793","n3790"],"tags":{"building":"shed"}},"w685":{"id":"w685","nodes":["n3794","n3795","n3796","n3797","n3794"],"tags":{"building":"yes"}},"w686":{"id":"w686","nodes":["n3798","n3799","n3804","n3805","n3798"],"tags":{"building":"yes"}},"w687":{"id":"w687","nodes":["n3806","n3807"],"tags":{"highway":"footway"}},"w688":{"id":"w688","nodes":["n3845","n3846","n3847","n3848","n3845"],"tags":{"leisure":"pitch","sport":"american_football"}},"w689":{"id":"w689","nodes":["n3849","n4021","n3850","n3851","n3852","n3853","n3854","n3855","n3856","n3975","n3976","n3979","n4008","n4009","n4010","n4011","n4012","n4013","n4014","n4015","n4016","n4017","n4018","n4019","n4020","n4021"],"tags":{"leisure":"track","sport":"running"}},"w69":{"id":"w69","nodes":["n326","n327"],"tags":{"bridge":"yes","footway":"sidewalk","highway":"footway","layer":"1"}},"w690":{"id":"w690","nodes":["n4022","n4023","n4024","n4025","n4026","n4027","n4022"],"tags":{"building":"yes"}},"w691":{"id":"w691","nodes":["n4028","n4029","n4030","n4031","n4028"],"tags":{"building":"yes"}},"w692":{"id":"w692","nodes":["n4032","n4033","n4034","n4035","n4032"],"tags":{"building":"yes"}},"w693":{"id":"w693","nodes":["n4036","n4037","n4038","n4039","n4036"],"tags":{"building":"yes"}},"w694":{"id":"w694","nodes":["n4040","n4041","n4042","n4043","n4040"],"tags":{"building":"yes"}},"w695":{"id":"w695","nodes":["n4044","n4045","n4050","n4053","n4046","n4047","n4048","n4049","n4044"],"tags":{"building":"yes"}},"w696":{"id":"w696","nodes":["n4050","n4051","n4052","n4053","n4050"],"tags":{"building":"roof"}},"w697":{"id":"w697","nodes":["n4054","n4068","n4055","n4056","n4057","n4054"],"tags":{"building":"yes"}},"w698":{"id":"w698","nodes":["n4058","n4059","n4060","n4061","n4062","n4063","n4058"],"tags":{"building":"yes"}},"w699":{"id":"w699","nodes":["n4064","n4066","n4065"],"tags":{"barrier":"fence"}},"w7":{"id":"w7","nodes":["n43","n44","n45"],"tags":{"highway":"service"}},"w70":{"id":"w70","nodes":["n327","n328","n27","n329"],"tags":{"footway":"sidewalk","highway":"footway"}},"w700":{"id":"w700","nodes":["n4066","n4067","n4068"],"tags":{"barrier":"fence"}},"w701":{"id":"w701","nodes":["n4069","n4070","n4071","n4072","n4069"],"tags":{"building":"shed"}},"w702":{"id":"w702","nodes":["n4073","n4074","n4075","n4076","n4077","n4078","n4079","n4080","n4081","n4082","n4083","n4084","n4073"],"tags":{"building":"yes"}},"w703":{"id":"w703","nodes":["n4085","n4093","n4086","n4087","n4088","n4089","n4090","n4091","n4092","n4085"],"tags":{"building":"yes"}},"w704":{"id":"w704","nodes":["n4093","n4094","n4095","n4096"],"tags":{"barrier":"fence"}},"w705":{"id":"w705","nodes":["n4097","n4098","n4099","n4100","n4097"],"tags":{"building":"yes"}},"w706":{"id":"w706","nodes":["n4098","n4102","n4087"],"tags":{"barrier":"fence"}},"w707":{"id":"w707","nodes":["n4101","n4102","n4096","n4170","n4103"],"tags":{"barrier":"fence"}},"w708":{"id":"w708","nodes":["n4104","n4105","n4106","n4107","n4104"],"tags":{"access":"private","leisure":"swimming_pool"}},"w709":{"id":"w709","nodes":["n4108","n4109","n4110","n4111","n4108"],"tags":{"building":"yes"}},"w71":{"id":"w71","nodes":["n329","n331"],"tags":{"bridge":"yes","footway":"sidewalk","highway":"footway","layer":"1"}},"w710":{"id":"w710","nodes":["n4112","n4113","n4114","n4115","n4116","n4117","n4118","n4119","n4112"],"tags":{"building":"yes"}},"w711":{"id":"w711","nodes":["n4120","n4121","n4122","n4123","n4120"],"tags":{"building":"yes"}},"w712":{"id":"w712","nodes":["n4124","n4125","n4126","n4127","n4128","n4129","n4124"],"tags":{"building":"yes"}},"w713":{"id":"w713","nodes":["n4130","n4131","n4132","n4133","n4130"],"tags":{"building":"shed"}},"w714":{"id":"w714","nodes":["n4134","n4135","n4136","n4137","n4138","n4139","n4140","n4141","n4142","n4143","n4134"],"tags":{"building":"yes"}},"w715":{"id":"w715","nodes":["n4144","n4145","n4146","n4147","n4148","n4149","n4144"],"tags":{"building":"yes"}},"w716":{"id":"w716","nodes":["n4150","n4151","n4152","n4153","n4150"],"tags":{"building":"yes"}},"w717":{"id":"w717","nodes":["n4154","n4155","n4156","n4157","n4154"],"tags":{"building":"yes"}},"w718":{"id":"w718","nodes":["n4158","n4159","n4160","n4161","n4162","n4163","n4164","n4165","n4158"],"tags":{"building":"yes"}},"w719":{"id":"w719","nodes":["n4166","n4167","n4168","n4169","n4166"],"tags":{"building":"yes"}},"w72":{"id":"w72","nodes":["n331","n344","n332","n333","n334"],"tags":{"footway":"sidewalk","highway":"footway"}},"w720":{"id":"w720","nodes":["n4170","n4171"],"tags":{"barrier":"fence"}},"w721":{"id":"w721","nodes":["n4138","n4103"],"tags":{"barrier":"fence"}},"w722":{"id":"w722","nodes":["n4103","n4172"],"tags":{"barrier":"fence"}},"w723":{"id":"w723","nodes":["n4173","n4174"],"tags":{"barrier":"fence"}},"w724":{"id":"w724","nodes":["n4175","n4176","n4177","n4178","n4175"],"tags":{"building":"yes"}},"w725":{"id":"w725","nodes":["n4179","n4180","n4181","n4182","n4183","n4184","n4179"],"tags":{"building":"yes"}},"w726":{"id":"w726","nodes":["n4185","n4186","n4187","n4188","n4185"],"tags":{"building":"yes"}},"w727":{"id":"w727","nodes":["n4189","n4190","n4191","n4192","n4193","n4194","n4195","n4196","n4197","n4198","n4199","n4200","n4201","n4202","n4189"],"tags":{"building":"yes"}},"w728":{"id":"w728","nodes":["n4203","n4204","n4205","n4206","n4207","n4208","n4209","n4210","n4203"],"tags":{"building":"yes"}},"w729":{"id":"w729","nodes":["n4211","n4212","n4213","n4214","n4211"],"tags":{"building":"shed"}},"w73":{"id":"w73","nodes":["n335","n336","n337","n338","n339","n340","n341","n342","n335"],"tags":{"building":"yes"}},"w730":{"id":"w730","nodes":["n4215","n4216","n4217","n4218","n4215"],"tags":{"building":"yes"}},"w731":{"id":"w731","nodes":["n4219","n4220","n4221","n4222","n4223","n4224","n4225","n4226","n4227","n4228","n4229","n4230","n4219"],"tags":{"building":"yes"}},"w732":{"id":"w732","nodes":["n4231","n4232","n4233","n4234","n4235","n4236","n4237","n4238","n4231"],"tags":{"building":"yes"}},"w733":{"id":"w733","nodes":["n4239","n4240","n4241","n4242","n4243","n4244","n4245","n4246","n4247","n4248","n4241"],"tags":{"highway":"service"}},"w734":{"id":"w734","nodes":["n4240","n4249","n4248"],"tags":{"highway":"service","service":"parking_aisle"}},"w735":{"id":"w735","nodes":["n4250","n4251","n4252","n4253","n4254","n4255","n4256","n4257","n4258","n4250"],"tags":{"amenity":"parking"}},"w736":{"id":"w736","nodes":["n4259","n4260","n4261","n4262","n4259"],"tags":{"building":"yes"}},"w737":{"id":"w737","nodes":["n4263","n4264","n4265","n4266","n4267","n4268","n4269","n4270","n4271","n4272","n4273","n4274","n4275","n4276","n4263"],"tags":{"building":"yes"}},"w738":{"id":"w738","nodes":["n4277","n4278","n4279","n4280","n4281","n4282","n4277"],"tags":{"building":"yes"}},"w739":{"id":"w739","nodes":["n4283","n4284","n4285","n4286","n4287","n4288","n4289","n4290","n4291","n4292","n4293","n4294","n4283"],"tags":{"building":"yes"}},"w74":{"id":"w74","nodes":["n343","n344","n345"],"tags":{"highway":"service"}},"w740":{"id":"w740","nodes":["n4295","n4296","n4297","n4298","n4295"],"tags":{"building":"yes"}},"w741":{"id":"w741","nodes":["n4299","n4300","n4301","n4302","n4303","n4304","n4305","n4306","n4307","n4308","n4309","n4310","n4299"],"tags":{"building":"yes"}},"w742":{"id":"w742","nodes":["n4311","n4312","n4313","n4314","n4311"],"tags":{"building":"shed"}},"w743":{"id":"w743","nodes":["n4315","n4316","n4317","n4318","n4319","n4320","n4315"],"tags":{"building":"yes"}},"w744":{"id":"w744","nodes":["n4321","n4322","n4323","n4324","n4325","n4326","n4327","n4328","n4329","n4330","n4331","n4332","n4333","n4334","n4321"],"tags":{"building":"yes"}},"w745":{"id":"w745","nodes":["n4335","n4336","n4337","n4338","n4335"],"tags":{"building":"shed"}},"w746":{"id":"w746","nodes":["n4339","n4340","n4341","n4342","n4343","n4344","n4339"],"tags":{"building":"yes"}},"w747":{"id":"w747","nodes":["n4345","n4346","n4347","n4348","n4345"],"tags":{"building":"yes"}},"w748":{"id":"w748","nodes":["n4349","n4350","n4351","n4352","n4349"],"tags":{"building":"yes"}},"w749":{"id":"w749","nodes":["n4353","n4354","n4355","n4356","n4357","n4358","n4353"],"tags":{"building":"yes"}},"w75":{"id":"w75","nodes":["n346","n347","n348","n349","n350","n351","n346"],"tags":{"amenity":"parking"}},"w750":{"id":"w750","nodes":["n4612","n4359","n4360"],"tags":{"barrier":"fence"}},"w751":{"id":"w751","nodes":["n4361","n4362","n4363","n4364","n4361"],"tags":{"building":"yes"}},"w752":{"id":"w752","nodes":["n4365","n4366","n4367","n4368","n4365"],"tags":{"building":"yes"}},"w753":{"id":"w753","nodes":["n4369","n4370","n4371","n4372","n4375","n4369"],"tags":{"building":"yes"}},"w754":{"id":"w754","nodes":["n4373","n4374","n4375"],"tags":{"barrier":"fence"}},"w755":{"id":"w755","nodes":["n4376","n4377","n4378","n4379","n4376"],"tags":{"building":"shed"}},"w756":{"id":"w756","nodes":["n4380","n4381","n4382","n4383","n4384","n4385","n4386","n4387","n4388","n4389","n4390","n4391","n4380"],"tags":{"building":"yes"}},"w757":{"id":"w757","nodes":["n4392","n4393","n4394","n4395","n4392"],"tags":{"building":"yes"}},"w758":{"id":"w758","nodes":["n4396","n4397","n4398","n4399","n4396"],"tags":{"building":"shed"}},"w759":{"id":"w759","nodes":["n4400","n4401","n4402","n4403","n4404","n4405","n4406","n4407","n4408","n4409","n4410","n4411","n4412","n4413","n4414","n4415","n4400"],"tags":{"building":"yes"}},"w76":{"id":"w76","nodes":["n2561","n359","n2563","n2793","n357","n356","n2792","n355","n354","n2791","n2562","n353","n352","n358","n2561"],"tags":{"highway":"service","oneway":"yes","service":"parking_aisle"}},"w760":{"id":"w760","nodes":["n4416","n4417"],"tags":{"barrier":"fence"}},"w761":{"id":"w761","nodes":["n4418","n4416","n4419"],"tags":{"barrier":"fence"}},"w762":{"id":"w762","nodes":["n4420","n4421"],"tags":{"barrier":"fence"}},"w763":{"id":"w763","nodes":["n4422","n4423","n4424","n4425","n4426","n4427","n4428","n4429","n4430","n4431","n4432","n4433","n4422"],"tags":{"building":"yes"}},"w764":{"id":"w764","nodes":["n4434","n4435","n4436","n4437","n4438","n4439","n4440","n4441","n4442","n4445","n4444","n4443","n4434"],"tags":{"building":"yes"}},"w765":{"id":"w765","nodes":["n4446","n4447","n4448","n4449","n4446"],"tags":{"building":"yes"}},"w766":{"id":"w766","nodes":["n4450","n4451","n4452","n4453","n4450"],"tags":{"building":"yes"}},"w767":{"id":"w767","nodes":["n4454","n4455","n4456","n4457","n4454"],"tags":{"building":"yes"}},"w768":{"id":"w768","nodes":["n4461","n4458","n4460"],"tags":{"footway":"crossing","highway":"footway"}},"w769":{"id":"w769","nodes":["n4460","n4462","n4459"],"tags":{"footway":"sidewalk","highway":"footway"}},"w77":{"id":"w77","nodes":["n325","n360","n361"],"tags":{"footway":"crossing","highway":"footway"}},"w770":{"id":"w770","nodes":["n4462","n4463","n4464"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w771":{"id":"w771","nodes":["n4464","n4465","n4466","n4467"],"tags":{"footway":"sidewalk","highway":"footway"}},"w772":{"id":"w772","nodes":["n3959","n3968","n3971","n3960","n3961","n3962","n3963"],"tags":{"footway":"sidewalk","highway":"footway"}},"w773":{"id":"w773","nodes":["n4467","n4468","n3959"],"tags":{"footway":"crossing","highway":"footway"}},"w774":{"id":"w774","nodes":["n4459","n4469","n4470"],"tags":{"footway":"crossing","highway":"footway"}},"w775":{"id":"w775","nodes":["n4470","n4471","n4472","n4473","n4474","n4475"],"tags":{"footway":"sidewalk","highway":"footway"}},"w776":{"id":"w776","nodes":["n4475","n4476","n4477"],"tags":{"footway":"crossing","highway":"footway"}},"w777":{"id":"w777","nodes":["n4477","n4478","n4479","n4480","n4481","n4482","n4483","n4484","n4485","n4486","n4487"],"tags":{"footway":"sidewalk","highway":"footway"}},"w778":{"id":"w778","nodes":["n4488","n4489","n4490","n4491","n4488"],"tags":{"building":"yes"}},"w779":{"id":"w779","nodes":["n4492","n4493","n4494","n4495","n4492"],"tags":{"building":"yes"}},"w78":{"id":"w78","nodes":["n361","n362","n369"],"tags":{"footway":"sidewalk","highway":"footway"}},"w780":{"id":"w780","nodes":["n4496","n4497","n4498","n4499","n4496"],"tags":{"access":"private","leisure":"swimming_pool"}},"w781":{"id":"w781","nodes":["n4508","n4509"],"tags":{"footway":"sidewalk","highway":"footway"}},"w782":{"id":"w782","nodes":["n4510","n4511"],"tags":{"footway":"sidewalk","highway":"footway"}},"w783":{"id":"w783","nodes":["n4512","n4513"],"tags":{"footway":"sidewalk","highway":"footway"}},"w784":{"id":"w784","nodes":["n4513","n4514"],"tags":{"footway":"sidewalk","highway":"footway"}},"w785":{"id":"w785","nodes":["n4515","n4516"],"tags":{"footway":"sidewalk","highway":"footway"}},"w786":{"id":"w786","nodes":["n4517","n4515"],"tags":{"footway":"sidewalk","highway":"footway"}},"w787":{"id":"w787","nodes":["n4518","n4519"],"tags":{"footway":"sidewalk","highway":"footway"}},"w788":{"id":"w788","nodes":["n4519","n4520","n4513"],"tags":{"footway":"crossing","highway":"footway"}},"w789":{"id":"w789","nodes":["n4515","n4521","n4513"],"tags":{"footway":"crossing","highway":"footway"}},"w79":{"id":"w79","nodes":["n362","n363","n334"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w790":{"id":"w790","nodes":["n4515","n4522","n4523"],"tags":{"footway":"crossing","highway":"footway"}},"w791":{"id":"w791","nodes":["n4523","n4524","n4519"],"tags":{"footway":"crossing","highway":"footway"}},"w792":{"id":"w792","nodes":["n4523","n4525"],"tags":{"footway":"sidewalk","highway":"footway"}},"w793":{"id":"w793","nodes":["n4525","n4526","n4527"],"tags":{"footway":"crossing","highway":"footway"}},"w794":{"id":"w794","nodes":["n4527","n4529"],"tags":{"footway":"sidewalk","highway":"footway"}},"w795":{"id":"w795","nodes":["n4529","n4530","n4518"],"tags":{"footway":"crossing","highway":"footway"}},"w796":{"id":"w796","nodes":["n4518","n4531"],"tags":{"footway":"sidewalk","highway":"footway"}},"w797":{"id":"w797","nodes":["n4531","n4532"],"tags":{"footway":"sidewalk","highway":"footway"}},"w798":{"id":"w798","nodes":["n4533","n4534"],"tags":{"footway":"sidewalk","highway":"footway"}},"w799":{"id":"w799","nodes":["n4518","n4538","n4539"],"tags":{"footway":"crossing","highway":"footway"}},"w8":{"id":"w8","nodes":["n46","n47","n145","n48","n49","n46"],"tags":{"amenity":"parking"}},"w80":{"id":"w80","nodes":["n334","n364","n365"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w800":{"id":"w800","nodes":["n4539","n4540","n4541"],"tags":{"footway":"crossing","highway":"footway"}},"w801":{"id":"w801","nodes":["n4541","n4542","n4529"],"tags":{"footway":"crossing","highway":"footway"}},"w802":{"id":"w802","nodes":["n4552","n4553"],"tags":{"footway":"sidewalk","highway":"footway"}},"w803":{"id":"w803","nodes":["n4554","n4555","n4556","n4557","n4558","n4559","n4554"],"tags":{"building":"yes"}},"w804":{"id":"w804","nodes":["n4562","n4563"],"tags":{"barrier":"retaining_wall"}},"w805":{"id":"w805","nodes":["n4568","n4569","n4570","n4571","n4568"],"tags":{"building":"yes"}},"w806":{"id":"w806","nodes":["n3473","n4575","n4576","n4581","n4580","n3551"],"tags":{"highway":"residential","oneway":"yes"}},"w807":{"id":"w807","nodes":["n4613","n4614","n4615","n4616","n4617","n4618","n4619","n4620","n4613"],"tags":{"leisure":"pitch","sport":"baseball"}},"w808":{"id":"w808","nodes":["n4621","n4622","n4623","n4624","n4625","n4626","n4627","n4628","n4629","n4630"],"tags":{"highway":"service"}},"w809":{"id":"w809","nodes":["n4631","n4632","n4633","n4637","n4634","n4638","n4635","n4636"],"tags":{"highway":"service"}},"w81":{"id":"w81","nodes":["n365","n366","n367"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w810":{"id":"w810","nodes":["n4639","n4640","n4641"],"tags":{"barrier":"fence"}},"w811":{"id":"w811","nodes":["n4649","n4650","n4651","n4652","n4649"],"tags":{"building":"yes"}},"w812":{"id":"w812","nodes":["n4654","n4655"],"tags":{"barrier":"fence"}},"w813":{"id":"w813","nodes":["n4656","n4657"],"tags":{"barrier":"fence"}},"w814":{"id":"w814","nodes":["n4669","n4670","n4671","n4672","n4669"],"tags":{"amenity":"shelter","shelter_type":"picnic_shelters"}},"w815":{"id":"w815","nodes":["n4678","n4679","n4680","n1889"],"tags":{"highway":"service"}},"w816":{"id":"w816","nodes":["n239","n4686","n4687"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w817":{"id":"w817","nodes":["n4687","n4688","n4689"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w818":{"id":"w818","nodes":["n4689","n4690","n307"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w819":{"id":"w819","nodes":["n2266","n4743"],"tags":{"highway":"path"}},"w82":{"id":"w82","nodes":["n724","n368","n369"],"tags":{"crossing":"zebra","footway":"crossing","highway":"footway"}},"w820":{"id":"w820","nodes":["n4785","n4786","n4787","n4788","n1684","n4760","n4769","n4761","n4762","n4763","n4764","n4765","n4766","n4767","n4768","n4785"],"tags":{"natural":"wood"}},"w821":{"id":"w821","nodes":["n4769","n4770","n4771","n4772","n4773","n4774","n4775","n4776","n4777","n4778","n4779","n4780","n4781","n4782","n4783","n4784","n4785","n4768","n4767","n4766","n4765","n4764","n4763","n4762","n4761","n4769"],"tags":{"natural":"scrub"}},"w822":{"id":"w822","nodes":["n4772","n4789","n4790","n4791","n4792","n4793","n4794","n4795","n4796","n4797","n4798","n4799","n4783","n4782","n4781","n4780","n4779","n4778","n4777","n4776","n4775","n4774","n4773","n4772"],"tags":{"natural":"wood"}},"w823":{"id":"w823","nodes":["n4800","n4801","n4802","n4803","n4804","n4805","n4806","n4807","n4808","n4809","n4810","n4811","n4812","n4813","n4814","n4815","n4816","n3490","n3489","n4800"],"tags":{"natural":"wood"}},"w824":{"id":"w824","nodes":["n4817","n4818","n4819","n4820","n4821","n4822","n4817"],"tags":{"landuse":"recreation_ground"}},"w825":{"id":"w825","nodes":["n4563","n4823","n4824","n4829","n4825","n4826","n4827","n4828","n4562","n4563"],"tags":{"landuse":"recreation_ground"}},"w826":{"id":"w826","nodes":["n4830","n4831","n4832","n4833","n4834","n4835","n4836","n4830"],"tags":{"landuse":"industrial"}},"w827":{"id":"w827","nodes":["n4563","n4837","n4838","n4839","n4840","n4841","n4842","n4827","n4828","n4562","n4563"],"tags":{"landuse":"industrial"}},"w828":{"id":"w828","nodes":["n4843","n4844","n4845","n4846","n4843"],"tags":{"landuse":"farmland"}},"w829":{"id":"w829","nodes":["n3712","n4847","n4848","n4849","n4850","n4851","n4852","n4858","n4864","n4959","n4960","n4853","n4857","n4854","n4855","n4856","n3712"],"tags":{"aeroway":"aerodrome","name":"Three Rivers Municipal Airport"}},"w83":{"id":"w83","nodes":["n371","n372","n373","n374","n371"],"tags":{"building":"yes"}},"w830":{"id":"w830","nodes":["n4855","n4854","n4857","n4853","n4960"],"tags":{"barrier":"fence"}},"w831":{"id":"w831","nodes":["n4860","n4859","n4858","n4852","n4851"],"tags":{"barrier":"fence"}},"w832":{"id":"w832","nodes":["n4866","n4878","n4869","n4867"],"tags":{"aeroway":"runway","ref":"5/23"}},"w833":{"id":"w833","nodes":["n4868","n4890","n4894","n4881","n4869","n4905","n4870"],"tags":{"aeroway":"runway","ref":"9/27"}},"w834":{"id":"w834","nodes":["n4871","n4875","n4872","n4895","n4873","n4874","n4871"],"tags":{"aeroway":"apron"}},"w835":{"id":"w835","nodes":["n4875","n4876","n4877","n4878","n4879","n4880","n4882","n4881"],"tags":{"aeroway":"taxiway"}},"w836":{"id":"w836","nodes":["n4882","n4893","n4883","n4891","n4884","n4885","n4886","n4887","n4888","n4892","n4889","n4890"],"tags":{"aeroway":"taxiway"}},"w837":{"id":"w837","nodes":["n4893","n4894"],"tags":{"aeroway":"taxiway"}},"w838":{"id":"w838","nodes":["n4895","n4896","n4897","n4898","n4899","n4900","n4901","n4902","n4903","n4906","n4904","n4905"],"tags":{"aeroway":"taxiway"}},"w839":{"id":"w839","nodes":["n4907","n4908"],"tags":{"highway":"service"}},"w84":{"id":"w84","nodes":["n374","n375","n376","n377","n373","n374"],"tags":{"building":"yes"}},"w840":{"id":"w840","nodes":["n4909","n4907","n4910"],"tags":{"highway":"service"}},"w841":{"id":"w841","nodes":["n4911","n4912","n4913","n4914","n4911"],"tags":{"building":"yes"}},"w842":{"id":"w842","nodes":["n4915","n4916","n4917","n4918","n4915"],"tags":{"aeroway":"hangar","building":"yes"}},"w843":{"id":"w843","nodes":["n4919","n4920","n4921","n4922","n4919"],"tags":{"building":"yes"}},"w844":{"id":"w844","nodes":["n4923","n4924","n4925","n4926","n4923"],"tags":{"aeroway":"hangar","building":"yes"}},"w845":{"id":"w845","nodes":["n4927","n4928","n4929","n4930","n4927"],"tags":{"aeroway":"hangar","building":"yes"}},"w846":{"id":"w846","nodes":["n4931","n4932","n4933","n4934","n4931"],"tags":{"aeroway":"hangar","building":"yes"}},"w847":{"id":"w847","nodes":["n4935","n4936","n4937","n4938","n4935"],"tags":{"aeroway":"hangar","building":"yes"}},"w848":{"id":"w848","nodes":["n4939","n4940","n4941","n4942","n4939"],"tags":{"aeroway":"hangar","building":"yes"}},"w849":{"id":"w849","nodes":["n4943","n4944","n4945","n4946","n4943"],"tags":{"aeroway":"hangar","building":"yes"}},"w85":{"id":"w85","nodes":["n431","n432","n1038","n433","n434","n1040","n431"],"tags":{"building":"yes"}},"w850":{"id":"w850","nodes":["n4947","n4948","n4949","n4950","n4947"],"tags":{"aeroway":"hangar","building":"yes"}},"w851":{"id":"w851","nodes":["n4951","n4952","n4953","n4954","n4951"],"tags":{"aeroway":"hangar","building":"yes"}},"w852":{"id":"w852","nodes":["n4955","n4956","n4957","n4958","n4955"],"tags":{"aeroway":"hangar","building":"yes"}},"w853":{"id":"w853","nodes":["n4959","n4864","n4861","n4862","n4863"],"tags":{"barrier":"fence"}},"w854":{"id":"w854","nodes":["n4961","n4962","n4963","n4964","n4965","n4966","n4967","n4968","n4969","n4961"],"tags":{"landuse":"farmland"}},"w855":{"id":"w855","nodes":["n4970","n4971","n4972","n4973","n4974","n4975","n4976","n4977","n4978","n4980","n4970"],"tags":{"landuse":"farmland"}},"w856":{"id":"w856","nodes":["n4979","n4980","n4978","n4981","n4982","n4983","n4984","n4985","n4979"],"tags":{"natural":"scrub"}},"w857":{"id":"w857","nodes":["n4986","n4987","n4988","n5032","n4989","n4990","n4991","n4992","n4993","n4994","n4995","n4996","n4997","n4998","n4999","n5000","n5001","n5002","n5022","n5023","n5024","n5025","n5030","n5031","n5029","n5028","n5027","n5026","n4986"],"tags":{"landuse":"farmland"}},"w858":{"id":"w858","nodes":["n5001","n5003","n5004","n4999","n5000","n5001"],"tags":{"natural":"scrub"}},"w859":{"id":"w859","nodes":["n5005","n5006","n5007","n5008","n5009","n5010","n5021","n5020","n5019","n5011","n5012","n5013","n5018","n5014","n5015","n5017","n5016","n5005"],"tags":{"landuse":"farmland"}},"w86":{"id":"w86","nodes":["n384","n385","n386","n387","n384"],"tags":{"building":"yes"}},"w860":{"id":"w860","nodes":["n3020","n5033","n5034","n5035","n3179","n3180","n3191","n3181","n3190","n3182","n3183","n3184","n3185","n3186","n3187","n3188","n3189","n3160","n3161","n3162","n2126","n2153","n2288","n3020"],"tags":{"landuse":"industrial"}},"w87":{"id":"w87","nodes":["n387","n388","n389","n386","n387"],"tags":{"building":"yes"}},"w88":{"id":"w88","nodes":["n390","n391","n392","n393","n390"],"tags":{"building":"yes"}},"w89":{"id":"w89","nodes":["n394","n2895"],"tags":{"highway":"service"}},"w9":{"id":"w9","nodes":["n50","n51","n148","n52","n57","n891","n53","n50"],"tags":{"building":"yes"}},"w90":{"id":"w90","nodes":["n398","n399","n400","n401","n402","n403","n404","n405","n406","n407","n408","n409","n410","n411","n412","n413","n414","n415","n416","n417","n398"],"tags":{"building":"yes"}},"w91":{"id":"w91","nodes":["n418","n423","n419"],"tags":{"highway":"service"}},"w92":{"id":"w92","nodes":["n420","n421","n422","n423","n420"],"tags":{"amenity":"parking"}},"w93":{"id":"w93","nodes":["n2282","n1876"],"tags":{"name":"Rocky River","tunnel":"building_passage","waterway":"river"}},"w94":{"id":"w94","nodes":["n1876","n885","n1875","n2234"],"tags":{"name":"Rocky River","waterway":"river"}},"w95":{"id":"w95","nodes":["n425","n426","n427","n914","n428","n913","n425"],"tags":{"building":"yes"}},"w96":{"id":"w96","nodes":["n456","n620","n1034","n1035","n456"],"tags":{"building":"yes"}},"w97":{"id":"w97","nodes":["n435","n912","n451","n321"],"tags":{"highway":"footway"}},"w98":{"id":"w98","nodes":["n436","n319","n437","n438","n439","n440","n441","n476","n442"],"tags":{"highway":"service"}},"w99":{"id":"w99","nodes":["n443","n444","n445","n446","n447","n448","n449","n450","n443"],"tags":{"amenity":"parking"}}};
58443
58444 // toggles the visibility of ui elements, using a combination of the
58445 // hide class, which sets display=none, and a d3 transition for opacity.
58446 // this will cause blinking when called repeatedly, so check that the
58447 // value actually changes between calls.
58448 function uiToggle(show, callback) {
58449     return function(selection$$1) {
58450         selection$$1
58451             .style('opacity', show ? 0 : 1)
58452             .classed('hide', false)
58453             .transition()
58454             .style('opacity', show ? 1 : 0)
58455             .on('end', function() {
58456                 select(this)
58457                     .classed('hide', !show)
58458                     .style('opacity', null);
58459                 if (callback) callback.apply(this);
58460             });
58461     };
58462 }
58463
58464 // Tooltips and svg mask used to highlight certain features
58465 function uiCurtain() {
58466
58467     var surface = select(null),
58468         tooltip = select(null),
58469         darkness = select(null);
58470
58471     function curtain(selection$$1) {
58472         surface = selection$$1
58473             .append('svg')
58474             .attr('id', 'curtain')
58475             .style('z-index', 1000)
58476             .style('pointer-events', 'none')
58477             .style('position', 'absolute')
58478             .style('top', 0)
58479             .style('left', 0);
58480
58481         darkness = surface.append('path')
58482             .attr('x', 0)
58483             .attr('y', 0)
58484             .attr('class', 'curtain-darkness');
58485
58486         select(window).on('resize.curtain', resize);
58487
58488         tooltip = selection$$1.append('div')
58489             .attr('class', 'tooltip')
58490             .style('z-index', 1002);
58491
58492         tooltip
58493             .append('div')
58494             .attr('class', 'tooltip-arrow');
58495
58496         tooltip
58497             .append('div')
58498             .attr('class', 'tooltip-inner');
58499
58500         resize();
58501
58502
58503         function resize() {
58504             surface
58505                 .attr('width', window.innerWidth)
58506                 .attr('height', window.innerHeight);
58507             curtain.cut(darkness.datum());
58508         }
58509     }
58510
58511
58512     /**
58513      * Reveal cuts the curtain to highlight the given box,
58514      * and shows a tooltip with instructions next to the box.
58515      *
58516      * @param  {String|ClientRect} [box]   box used to cut the curtain
58517      * @param  {String}    [text]          text for a tooltip
58518      * @param  {Object}    [options]
58519      * @param  {string}    [options.tooltipClass]    optional class to add to the tooltip
58520      * @param  {integer}   [options.duration]        transition time in milliseconds
58521      * @param  {string}    [options.buttonText]      if set, create a button with this text label
58522      * @param  {function}  [options.buttonCallback]  if set, the callback for the button
58523      * @param  {String|ClientRect} [options.tooltipBox]  box for tooltip position, if different from box for the curtain
58524      */
58525     curtain.reveal = function(box, text$$1, options) {
58526         if (typeof box === 'string') {
58527             box = select(box).node();
58528         }
58529         if (box && box.getBoundingClientRect) {
58530             box = copyBox(box.getBoundingClientRect());
58531         }
58532
58533         options = options || {};
58534
58535         var tooltipBox;
58536         if (options.tooltipBox) {
58537             tooltipBox = options.tooltipBox;
58538             if (typeof tooltipBox === 'string') {
58539                 tooltipBox = select(tooltipBox).node();
58540             }
58541             if (tooltipBox && tooltipBox.getBoundingClientRect) {
58542                 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
58543             }
58544         } else {
58545             tooltipBox = box;
58546         }
58547
58548         if (tooltipBox && text$$1) {
58549             // pseudo markdown bold text for the instruction section..
58550             var parts = text$$1.split('**');
58551             var html$$1 = parts[0] ? '<span>' + parts[0] + '</span>' : '';
58552             if (parts[1]) {
58553                 html$$1 += '<span class="instruction">' + parts[1] + '</span>';
58554             }
58555
58556             html$$1 = html$$1.replace(/\*(.*?)\*/g, '<em>$1</em>');   // emphasis
58557             html$$1 = html$$1.replace(/\{br\}/g, '<br/><br/>');       // linebreak
58558
58559             if (options.buttonText && options.buttonCallback) {
58560                 html$$1 += '<div class="button-section">' +
58561                     '<button href="#" class="button action col8">' + options.buttonText + '</button></div>';
58562             }
58563
58564             var classes = 'curtain-tooltip tooltip in ' + (options.tooltipClass || '');
58565             tooltip
58566                 .classed(classes, true)
58567                 .selectAll('.tooltip-inner')
58568                 .html(html$$1);
58569
58570             if (options.buttonText && options.buttonCallback) {
58571                 var button = tooltip.selectAll('.button-section .button.action');
58572                 button
58573                     .on('click', function() {
58574                         event.preventDefault();
58575                         options.buttonCallback();
58576                     });
58577             }
58578
58579             var tip = copyBox(tooltip.node().getBoundingClientRect()),
58580                 w = window.innerWidth,
58581                 h = window.innerHeight,
58582                 tooltipWidth = 200,
58583                 tooltipArrow = 5,
58584                 side, pos;
58585
58586
58587             // hack: this will have bottom placement,
58588             // so need to reserve extra space for the tooltip illustration.
58589             if (options.tooltipClass === 'intro-mouse') {
58590                 tip.height += 80;
58591             }
58592
58593             // trim box dimensions to just the portion that fits in the window..
58594             if (tooltipBox.top + tooltipBox.height > h) {
58595                 tooltipBox.height -= (tooltipBox.top + tooltipBox.height - h);
58596             }
58597             if (tooltipBox.left + tooltipBox.width > w) {
58598                 tooltipBox.width -= (tooltipBox.left + tooltipBox.width - w);
58599             }
58600
58601             // determine tooltip placement..
58602
58603             if (tooltipBox.top + tooltipBox.height < 100) {
58604                 // tooltip below box..
58605                 side = 'bottom';
58606                 pos = [
58607                     tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
58608                     tooltipBox.top + tooltipBox.height
58609                 ];
58610
58611             } else if (tooltipBox.top > h - 140) {
58612                 // tooltip above box..
58613                 side = 'top';
58614                 pos = [
58615                     tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
58616                     tooltipBox.top - tip.height
58617                 ];
58618
58619             } else {
58620                 // tooltip to the side of the tooltipBox..
58621                 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
58622
58623                 if (textDirection === 'rtl') {
58624                     if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
58625                         side = 'right';
58626                         pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
58627
58628                     } else {
58629                         side = 'left';
58630                         pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
58631                     }
58632
58633                 } else {
58634                     if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
58635                         side = 'left';
58636                         pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
58637                     }
58638                     else {
58639                         side = 'right';
58640                         pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
58641                     }
58642                 }
58643             }
58644
58645             if (options.duration !== 0 || !tooltip.classed(side)) {
58646                 tooltip.call(uiToggle(true));
58647             }
58648
58649             tooltip
58650                 .style('top', pos[1] + 'px')
58651                 .style('left', pos[0] + 'px')
58652                 .attr('class', classes + ' ' + side);
58653
58654
58655             // shift tooltip-inner if it is very close to the top or bottom edge
58656             // (doesn't affect the placement of the tooltip-arrow)
58657             var shiftY = 0;
58658             if (side === 'left' || side === 'right') {
58659                 if (pos[1] < 60) {
58660                     shiftY = 60 - pos[1];
58661                 }
58662                 else if (pos[1] + tip.height > h - 100) {
58663                     shiftY = h - pos[1] - tip.height - 100;
58664                 }
58665             }
58666             tooltip.selectAll('.tooltip-inner')
58667                 .style('top', shiftY + 'px');
58668
58669         } else {
58670             tooltip
58671                 .classed('in', false)
58672                 .call(uiToggle(false));
58673         }
58674
58675         curtain.cut(box, options.duration);
58676
58677         return tooltip;
58678     };
58679
58680
58681     curtain.cut = function(datum, duration) {
58682         darkness.datum(datum)
58683             .interrupt();
58684
58685         var selection$$1;
58686         if (duration === 0) {
58687             selection$$1 = darkness;
58688         } else {
58689             selection$$1 = darkness
58690                 .transition()
58691                 .duration(duration || 600)
58692                 .ease(linear$1);
58693         }
58694
58695         selection$$1
58696             .attr('d', function(d) {
58697                 var string = 'M 0,0 L 0,' + window.innerHeight + ' L ' +
58698                     window.innerWidth + ',' + window.innerHeight + 'L' +
58699                     window.innerWidth + ',0 Z';
58700
58701                 if (!d) return string;
58702                 return string + 'M' +
58703                     d.left + ',' + d.top + 'L' +
58704                     d.left + ',' + (d.top + d.height) + 'L' +
58705                     (d.left + d.width) + ',' + (d.top + d.height) + 'L' +
58706                     (d.left + d.width) + ',' + (d.top) + 'Z';
58707
58708             });
58709     };
58710
58711
58712     curtain.remove = function() {
58713         surface.remove();
58714         tooltip.remove();
58715         select(window).on('resize.curtain', null);
58716     };
58717
58718
58719     // ClientRects are immutable, so copy them to an object,
58720     // in case we need to trim the height/width.
58721     function copyBox(src) {
58722         return {
58723             top: src.top,
58724             right: src.right,
58725             bottom: src.bottom,
58726             left: src.left,
58727             width: src.width,
58728             height: src.height
58729         };
58730     }
58731
58732
58733     return curtain;
58734 }
58735
58736 function uiIntroWelcome(context, reveal) {
58737     var dispatch$$1 = dispatch('done'),
58738         listener = clickListener();
58739
58740     var chapter = {
58741         title: 'intro.welcome.title'
58742     };
58743
58744
58745     function welcome() {
58746         context.map().centerZoom([-85.63591, 41.94285], 19);
58747         reveal('.intro-nav-wrap .chapter-welcome',
58748             t('intro.welcome.welcome'),
58749             { buttonText: t('intro.ok'), buttonCallback: practice }
58750         );
58751     }
58752
58753     function practice() {
58754         reveal('.intro-nav-wrap .chapter-welcome',
58755             t('intro.welcome.practice'),
58756             { buttonText: t('intro.ok'), buttonCallback: words }
58757         );
58758     }
58759
58760     function words() {
58761         reveal('.intro-nav-wrap .chapter-welcome',
58762             t('intro.welcome.words'),
58763             { buttonText: t('intro.ok'), buttonCallback: mouse$$1 }
58764         );
58765     }
58766
58767
58768     function mouse$$1() {
58769         reveal('.intro-nav-wrap .chapter-welcome',
58770             t('intro.welcome.mouse'),
58771             { buttonText: t('intro.ok'), buttonCallback: leftClick }
58772         );
58773     }
58774
58775
58776     function leftClick() {
58777         var counter = 0,
58778             times = 5;
58779
58780         var tooltip = reveal('.intro-nav-wrap .chapter-welcome',
58781             t('intro.welcome.leftclick', { num: times }),
58782             { tooltipClass: 'intro-mouse' }
58783         );
58784
58785         tooltip.selectAll('.tooltip-inner')
58786             .insert('svg', 'span')
58787             .attr('class', 'tooltip-illustration')
58788             .append('use')
58789             .attr('xlink:href', '#walkthrough-mouse');
58790
58791         tooltip
58792             .append('div')
58793             .attr('class', 'counter');
58794
58795         tooltip.call(listener);
58796
58797         listener.on('click', function(which) {
58798             if (which === 'left') {
58799                 select('.curtain-tooltip.intro-mouse .counter')
58800                     .text(String(++counter));
58801
58802                 if (counter === times) {
58803                     window.setTimeout(function() { continueTo(rightClick); }, 1000);
58804                 }
58805             }
58806         });
58807
58808         function continueTo(nextStep) {
58809             listener.on('click', null);
58810             tooltip.call(listener.off);
58811             tooltip.select('.counter').remove();
58812             nextStep();
58813         }
58814     }
58815
58816
58817     function rightClick() {
58818         var counter = 0,
58819             times = 5;
58820
58821         var tooltip = reveal('.intro-nav-wrap .chapter-welcome',
58822             t('intro.welcome.rightclick', { num: times }),
58823             { tooltipClass: 'intro-mouse' }
58824         );
58825
58826         tooltip.selectAll('.tooltip-inner')
58827             .insert('svg', 'span')
58828             .attr('class', 'tooltip-illustration')
58829             .append('use')
58830             .attr('xlink:href', '#walkthrough-mouse');
58831
58832         tooltip
58833             .append('div')
58834             .attr('class', 'counter');
58835
58836         tooltip.call(listener);
58837
58838         listener.on('click', function(which) {
58839             if (which === 'right') {
58840                 select('.curtain-tooltip.intro-mouse .counter')
58841                     .text(String(++counter));
58842
58843                 if (counter === times) {
58844                     window.setTimeout(function() { continueTo(chapters); }, 1000);
58845                 }
58846             }
58847         });
58848
58849         function continueTo(nextStep) {
58850             listener.on('click', null);
58851             tooltip.call(listener.off);
58852             tooltip.select('.counter').remove();
58853             nextStep();
58854         }
58855     }
58856
58857
58858     function chapters() {
58859         dispatch$$1.call('done');
58860         reveal('.intro-nav-wrap .chapter-navigation',
58861             t('intro.welcome.chapters', { next: t('intro.navigation.title') })
58862         );
58863     }
58864
58865
58866     chapter.enter = function() {
58867         welcome();
58868     };
58869
58870
58871     chapter.exit = function() {
58872         listener.off();
58873     };
58874
58875
58876     chapter.restart = function() {
58877         chapter.exit();
58878         chapter.enter();
58879     };
58880
58881
58882     return utilRebind(chapter, dispatch$$1, 'on');
58883 }
58884
58885
58886
58887 function clickListener() {
58888     var dispatch$$1 = dispatch('click'),
58889         minTime = 120,
58890         tooltip = select(null),
58891         down = {};
58892
58893     // `down` keeps track of which buttons/keys are down.
58894     // Setting a property in `down` happens immediately.
58895     // Unsetting a property in `down` is delayed because
58896     //   on Windows a contextmenu event happens after keyup/mouseup
58897
58898     function keydown() {
58899         if (event.keyCode === 93)  {   // context menu
58900             event.preventDefault();
58901             event.stopPropagation();
58902             down.menu = event.timeStamp;
58903             tooltip.classed('rightclick', true);
58904         }
58905     }
58906
58907
58908     function keyup() {
58909         if (event.keyCode === 93)  {   // context menu
58910             event.preventDefault();
58911             event.stopPropagation();
58912             var endTime = event.timeStamp,
58913                 startTime = down.menu || endTime,
58914                 delay = (endTime - startTime < minTime) ? minTime : 0;
58915
58916             window.setTimeout(function() {
58917                 tooltip.classed('rightclick', false);
58918                 down.menu = undefined;  // delayed, for Windows
58919             }, delay);
58920
58921             dispatch$$1.call('click', this, 'right');
58922         }
58923     }
58924
58925
58926     function mousedown() {
58927         var button = event.button;
58928         if (button === 0 && !event.ctrlKey) {
58929             tooltip.classed('leftclick', true);
58930         } else if (button === 2) {
58931             tooltip.classed('rightclick', true);
58932         }
58933         down[button] = event.timeStamp;
58934     }
58935
58936
58937     function mouseup() {
58938         var button = event.button,
58939             endTime = event.timeStamp,
58940             startTime = down[button] || endTime,
58941             delay = (endTime - startTime < minTime) ? minTime : 0;
58942
58943         if (button === 0 && !event.ctrlKey) {
58944             window.setTimeout(function() {
58945                 tooltip.classed('leftclick', false);
58946                 down[button] = undefined;  // delayed, for Windows
58947             }, delay);
58948
58949             dispatch$$1.call('click', this, 'left');
58950
58951         } else if (button === 2) {
58952             window.setTimeout(function() {
58953                 tooltip.classed('rightclick', false);
58954                 down[button] = undefined;  // delayed, for Windows
58955             }, delay);
58956
58957             dispatch$$1.call('click', this, 'right');
58958
58959         } else {
58960             window.setTimeout(function() {
58961                 down[button] = undefined;  // delayed, for Windows
58962             }, delay);
58963         }
58964     }
58965
58966
58967     function contextmenu() {
58968         event.preventDefault();
58969         event.stopPropagation();
58970         if (!down[2] && !down.menu) {
58971             tooltip.classed('rightclick', true);
58972             window.setTimeout(function() {
58973                 tooltip.classed('rightclick', false);
58974             }, minTime);
58975             dispatch$$1.call('click', this, 'right');
58976         }
58977     }
58978
58979
58980     var behavior = function(selection$$1) {
58981         tooltip = selection$$1;
58982         down = {};
58983
58984         select(window)
58985             .on('keydown.intro', keydown)
58986             .on('keyup.intro', keyup)
58987             .on('mousedown.intro', mousedown)
58988             .on('mouseup.intro', mouseup)
58989             .on('contextmenu.intro', contextmenu);
58990     };
58991
58992
58993     behavior.off = function() {
58994         select(window)
58995             .on('keydown.intro', null)
58996             .on('keyup.intro', null)
58997             .on('mousedown.intro', null)
58998             .on('mouseup.intro', null)
58999             .on('contextmenu.intro', null);
59000
59001         tooltip
59002             .classed('leftclick', false)
59003             .classed('rightclick', false);
59004     };
59005
59006     return utilRebind(behavior, dispatch$$1, 'on');
59007 }
59008
59009 function uiIntroNavigation(context, reveal) {
59010     var dispatch$$1 = dispatch('done'),
59011         timeouts = [],
59012         hallId = 'n2061',
59013         townHall = [-85.63591, 41.94285],
59014         springStreetId = 'w397',
59015         springStreetEndId = 'n1834',
59016         springStreet = [-85.63582, 41.94255],
59017         onewayField = context.presets().field('oneway'),
59018         maxspeedField = context.presets().field('maxspeed');
59019
59020
59021     var chapter = {
59022         title: 'intro.navigation.title'
59023     };
59024
59025
59026     function timeout$$1(f, t$$1) {
59027         timeouts.push(window.setTimeout(f, t$$1));
59028     }
59029
59030
59031     function eventCancel() {
59032         event.stopPropagation();
59033         event.preventDefault();
59034     }
59035
59036
59037     function isTownHallSelected() {
59038         var ids = context.selectedIDs();
59039         return ids.length === 1 && ids[0] === hallId;
59040     }
59041
59042
59043     function dragMap() {
59044         context.enter(modeBrowse(context));
59045         context.history().reset('initial');
59046
59047         var msec = transitionTime(townHall, context.map().center());
59048         if (msec) { reveal(null, null, { duration: 0 }); }
59049         context.map().zoom(19).centerEase(townHall, msec);
59050
59051         timeout$$1(function() {
59052             var centerStart = context.map().center();
59053
59054             reveal('#surface', t('intro.navigation.drag'));
59055             context.map().on('drawn.intro', function() {
59056                 reveal('#surface', t('intro.navigation.drag'), { duration: 0 });
59057             });
59058
59059             context.map().on('move.intro', function() {
59060                 var centerNow = context.map().center();
59061                 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
59062                     context.map().on('move.intro', null);
59063                     timeout$$1(function() { continueTo(zoomMap); }, 3000);
59064                 }
59065             });
59066
59067         }, msec + 100);
59068
59069         function continueTo(nextStep) {
59070             context.map().on('move.intro drawn.intro', null);
59071             nextStep();
59072         }
59073     }
59074
59075
59076     function zoomMap() {
59077         var zoomStart = context.map().zoom();
59078
59079         reveal('#surface',
59080             t('intro.navigation.zoom', {
59081                 plus: icon('#icon-plus', 'pre-text'),
59082                 minus: icon('#icon-minus', 'pre-text')
59083             })
59084         );
59085
59086         context.map().on('drawn.intro', function() {
59087             reveal('#surface',
59088                 t('intro.navigation.zoom', {
59089                     plus: icon('#icon-plus', 'pre-text'),
59090                     minus: icon('#icon-minus', 'pre-text')
59091                 }), { duration: 0 }
59092             );
59093         });
59094
59095         context.map().on('move.intro', function() {
59096             if (context.map().zoom() !== zoomStart) {
59097                 context.map().on('move.intro', null);
59098                 timeout$$1(function() { continueTo(features); }, 3000);
59099             }
59100         });
59101
59102         function continueTo(nextStep) {
59103             context.map().on('move.intro drawn.intro', null);
59104             nextStep();
59105         }
59106     }
59107
59108
59109     function features() {
59110         var onClick = function() { continueTo(pointsLinesAreas); };
59111
59112         reveal('#surface', t('intro.navigation.features'),
59113             { buttonText: t('intro.ok'), buttonCallback: onClick }
59114         );
59115
59116         context.map().on('drawn.intro', function() {
59117             reveal('#surface', t('intro.navigation.features'),
59118                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59119             );
59120         });
59121
59122         function continueTo(nextStep) {
59123             context.map().on('drawn.intro', null);
59124             nextStep();
59125         }
59126     }
59127
59128     function pointsLinesAreas() {
59129         var onClick = function() { continueTo(nodesWays); };
59130
59131         reveal('#surface', t('intro.navigation.points_lines_areas'),
59132             { buttonText: t('intro.ok'), buttonCallback: onClick }
59133         );
59134
59135         context.map().on('drawn.intro', function() {
59136             reveal('#surface', t('intro.navigation.points_lines_areas'),
59137                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59138             );
59139         });
59140
59141         function continueTo(nextStep) {
59142             context.map().on('drawn.intro', null);
59143             nextStep();
59144         }
59145     }
59146
59147     function nodesWays() {
59148         var onClick = function() { continueTo(clickTownHall); };
59149
59150         reveal('#surface', t('intro.navigation.nodes_ways'),
59151             { buttonText: t('intro.ok'), buttonCallback: onClick }
59152         );
59153
59154         context.map().on('drawn.intro', function() {
59155             reveal('#surface', t('intro.navigation.nodes_ways'),
59156                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59157             );
59158         });
59159
59160         function continueTo(nextStep) {
59161             context.map().on('drawn.intro', null);
59162             nextStep();
59163         }
59164     }
59165
59166     function clickTownHall() {
59167         context.enter(modeBrowse(context));
59168         context.history().reset('initial');
59169
59170         reveal(null, null, { duration: 0 });
59171         context.map().zoomEase(19, 500);
59172
59173         timeout$$1(function() {
59174             var entity = context.hasEntity(hallId);
59175             if (!entity) return;
59176             context.map().centerEase(entity.loc, 500);
59177
59178             timeout$$1(function() {
59179                 var entity = context.hasEntity(hallId);
59180                 if (!entity) return;
59181                 var box = pointBox(entity.loc, context);
59182                 reveal(box, t('intro.navigation.click_townhall'));
59183
59184                 context.map().on('move.intro drawn.intro', function() {
59185                     var entity = context.hasEntity(hallId);
59186                     if (!entity) return;
59187                     var box = pointBox(entity.loc, context);
59188                     reveal(box, t('intro.navigation.click_townhall'), { duration: 0 });
59189                 });
59190
59191                 context.on('enter.intro', function() {
59192                     if (isTownHallSelected()) continueTo(selectedTownHall);
59193                 });
59194
59195             }, 550);  // after centerEase
59196
59197         }, 550); // after zoomEase
59198
59199         context.history().on('change.intro', function() {
59200             if (!context.hasEntity(hallId)) {
59201                 continueTo(clickTownHall);
59202             }
59203         });
59204
59205         function continueTo(nextStep) {
59206             context.on('enter.intro', null);
59207             context.map().on('move.intro drawn.intro', null);
59208             context.history().on('change.intro', null);
59209             nextStep();
59210         }
59211     }
59212
59213
59214     function selectedTownHall() {
59215         if (!isTownHallSelected()) return clickTownHall();
59216
59217         var entity = context.hasEntity(hallId);
59218         if (!entity) return clickTownHall();
59219
59220         var box = pointBox(entity.loc, context);
59221         var onClick = function() { continueTo(editorTownHall); };
59222
59223         reveal(box, t('intro.navigation.selected_townhall'),
59224             { buttonText: t('intro.ok'), buttonCallback: onClick }
59225         );
59226
59227         context.map().on('move.intro drawn.intro', function() {
59228             var entity = context.hasEntity(hallId);
59229             if (!entity) return;
59230             var box = pointBox(entity.loc, context);
59231             reveal(box, t('intro.navigation.selected_townhall'),
59232                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59233             );
59234         });
59235
59236         context.history().on('change.intro', function() {
59237             if (!context.hasEntity(hallId)) {
59238                 continueTo(clickTownHall);
59239             }
59240         });
59241
59242         function continueTo(nextStep) {
59243             context.map().on('move.intro drawn.intro', null);
59244             context.history().on('change.intro', null);
59245             nextStep();
59246         }
59247     }
59248
59249
59250     function editorTownHall() {
59251         if (!isTownHallSelected()) return clickTownHall();
59252
59253         // disallow scrolling
59254         select('.inspector-wrap').on('wheel.intro', eventCancel);
59255
59256         var onClick = function() { continueTo(presetTownHall); };
59257
59258         reveal('.entity-editor-pane',
59259             t('intro.navigation.editor_townhall'),
59260             { buttonText: t('intro.ok'), buttonCallback: onClick }
59261         );
59262
59263         context.on('exit.intro', function() {
59264             continueTo(clickTownHall);
59265         });
59266
59267         context.history().on('change.intro', function() {
59268             if (!context.hasEntity(hallId)) {
59269                 continueTo(clickTownHall);
59270             }
59271         });
59272
59273         function continueTo(nextStep) {
59274             context.on('exit.intro', null);
59275             context.history().on('change.intro', null);
59276             select('.inspector-wrap').on('wheel.intro', null);
59277             nextStep();
59278         }
59279     }
59280
59281
59282     function presetTownHall() {
59283         if (!isTownHallSelected()) return clickTownHall();
59284
59285         // reset pane, in case user happened to change it..
59286         select('.inspector-wrap .panewrap').style('right', '0%');
59287         // disallow scrolling
59288         select('.inspector-wrap').on('wheel.intro', eventCancel);
59289
59290         // preset match, in case the user happened to change it.
59291         var entity = context.entity(context.selectedIDs()[0]);
59292         var preset = context.presets().match(entity, context.graph());
59293
59294         var onClick = function() { continueTo(fieldsTownHall); };
59295
59296         context.on('exit.intro', function() {
59297             continueTo(clickTownHall);
59298         });
59299
59300         context.history().on('change.intro', function() {
59301             if (!context.hasEntity(hallId)) {
59302                 continueTo(clickTownHall);
59303             }
59304         });
59305
59306         reveal('.inspector-body .preset-list-item.inspector-inner',
59307             t('intro.navigation.preset_townhall', { preset: preset.name() }),
59308             { buttonText: t('intro.ok'), buttonCallback: onClick }
59309         );
59310
59311         function continueTo(nextStep) {
59312             context.on('exit.intro', null);
59313             context.history().on('change.intro', null);
59314             select('.inspector-wrap').on('wheel.intro', null);
59315             nextStep();
59316         }
59317     }
59318
59319
59320     function fieldsTownHall() {
59321         if (!isTownHallSelected()) return clickTownHall();
59322
59323         // reset pane, in case user happened to change it..
59324         select('.inspector-wrap .panewrap').style('right', '0%');
59325         // disallow scrolling
59326         select('.inspector-wrap').on('wheel.intro', eventCancel);
59327
59328         var onClick = function() { continueTo(closeTownHall); };
59329
59330         reveal('.inspector-body .inspector-preset',
59331             t('intro.navigation.fields_townhall'),
59332             { buttonText: t('intro.ok'), buttonCallback: onClick }
59333         );
59334
59335         context.on('exit.intro', function() {
59336             continueTo(clickTownHall);
59337         });
59338
59339         context.history().on('change.intro', function() {
59340             if (!context.hasEntity(hallId)) {
59341                 continueTo(clickTownHall);
59342             }
59343         });
59344
59345         function continueTo(nextStep) {
59346             context.on('exit.intro', null);
59347             context.history().on('change.intro', null);
59348             select('.inspector-wrap').on('wheel.intro', null);
59349             nextStep();
59350         }
59351     }
59352
59353
59354     function closeTownHall() {
59355         if (!isTownHallSelected()) return clickTownHall();
59356
59357         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59358         var href = select(selector$$1).attr('href') || '#icon-close';
59359
59360         reveal('.entity-editor-pane',
59361             t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') })
59362         );
59363
59364         context.on('exit.intro', function() {
59365             continueTo(searchStreet);
59366         });
59367
59368         context.history().on('change.intro', function() {
59369             // update the close icon in the tooltip if the user edits something.
59370             var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59371             var href = select(selector$$1).attr('href') || '#icon-close';
59372
59373             reveal('.entity-editor-pane',
59374                 t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') }),
59375                 { duration: 0 }
59376             );
59377         });
59378
59379         function continueTo(nextStep) {
59380             context.on('exit.intro', null);
59381             context.history().on('change.intro', null);
59382             nextStep();
59383         }
59384     }
59385
59386
59387     function searchStreet() {
59388         context.enter(modeBrowse(context));
59389         context.history().reset('initial');  // ensure spring street exists
59390
59391         var msec = transitionTime(springStreet, context.map().center());
59392         if (msec) { reveal(null, null, { duration: 0 }); }
59393         context.map().zoom(19).centerEase(springStreet, msec);  // ..and user can see it
59394
59395         timeout$$1(function() {
59396             reveal('.search-header input',
59397                 t('intro.navigation.search_street', { name: t('intro.graph.name.spring-street') })
59398             );
59399
59400             select('.search-header input')
59401                 .on('keyup.intro', checkSearchResult);
59402         }, msec + 100);
59403     }
59404
59405
59406     function checkSearchResult() {
59407         var first = select('.feature-list-item:nth-child(0n+2)'),  // skip "No Results" item
59408             firstName = first.select('.entity-name'),
59409             name = t('intro.graph.name.spring-street');
59410
59411         if (!firstName.empty() && firstName.text() === name) {
59412             reveal(first.node(),
59413                 t('intro.navigation.choose_street', { name: name }),
59414                 { duration: 300 }
59415             );
59416
59417             context.on('exit.intro', function() {
59418                 continueTo(selectedStreet);
59419             });
59420
59421             select('.search-header input')
59422                 .on('keydown.intro', eventCancel, true)
59423                 .on('keyup.intro', null);
59424         }
59425
59426         function continueTo(nextStep) {
59427             context.on('exit.intro', null);
59428             select('.search-header input')
59429                 .on('keydown.intro', null)
59430                 .on('keyup.intro', null);
59431             nextStep();
59432         }
59433     }
59434
59435
59436     function selectedStreet() {
59437         if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
59438             return searchStreet();
59439         }
59440
59441         var onClick = function() { continueTo(editorStreet); };
59442         var entity = context.entity(springStreetEndId);
59443         var box = pointBox(entity.loc, context);
59444         box.height = 500;
59445
59446         reveal(box,
59447             t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
59448             { duration: 600, buttonText: t('intro.ok'), buttonCallback: onClick }
59449         );
59450
59451         timeout$$1(function() {
59452             context.map().on('move.intro drawn.intro', function() {
59453                 var entity = context.hasEntity(springStreetEndId);
59454                 if (!entity) return;
59455                 var box = pointBox(entity.loc, context);
59456                 box.height = 500;
59457                 reveal(box,
59458                     t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
59459                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59460                 );
59461             });
59462         }, 600);  // after reveal.
59463
59464         context.on('enter.intro', function(mode) {
59465             if (!context.hasEntity(springStreetId)) {
59466                 return continueTo(searchStreet);
59467             }
59468             var ids = context.selectedIDs();
59469             if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
59470                 // keep Spring Street selected..
59471                 context.enter(modeSelect(context, [springStreetId]));
59472             }
59473         });
59474
59475         context.history().on('change.intro', function() {
59476             if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
59477                 timeout$$1(function() {
59478                     continueTo(searchStreet);
59479                 }, 300);  // after any transition (e.g. if user deleted intersection)
59480             }
59481         });
59482
59483         function continueTo(nextStep) {
59484             context.map().on('move.intro drawn.intro', null);
59485             context.on('enter.intro', null);
59486             context.history().on('change.intro', null);
59487             nextStep();
59488         }
59489     }
59490
59491
59492     function editorStreet() {
59493         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59494         var href = select(selector$$1).attr('href') || '#icon-close';
59495
59496         reveal('.entity-editor-pane',
59497             t('intro.navigation.editor_street', {
59498                 button: icon(href, 'pre-text'),
59499                 field1: onewayField.label(),
59500                 field2: maxspeedField.label()
59501             })
59502         );
59503
59504         context.on('exit.intro', function() {
59505             continueTo(play);
59506         });
59507
59508         context.history().on('change.intro', function() {
59509             // update the close icon in the tooltip if the user edits something.
59510             var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59511             var href = select(selector$$1).attr('href') || '#icon-close';
59512
59513             reveal('.entity-editor-pane',
59514                 t('intro.navigation.editor_street', {
59515                     button: icon(href, 'pre-text'),
59516                     field1: onewayField.label().toLowerCase(),
59517                     field2: maxspeedField.label().toLowerCase()
59518                 }), { duration: 0 }
59519             );
59520         });
59521
59522         function continueTo(nextStep) {
59523             context.on('exit.intro', null);
59524             context.history().on('change.intro', null);
59525             nextStep();
59526         }
59527     }
59528
59529
59530     function play() {
59531         dispatch$$1.call('done');
59532         reveal('#id-container',
59533             t('intro.navigation.play', { next: t('intro.points.title') }), {
59534                 tooltipBox: '.intro-nav-wrap .chapter-point',
59535                 buttonText: t('intro.ok'),
59536                 buttonCallback: function() { reveal('#id-container'); }
59537             }
59538         );
59539     }
59540
59541
59542     chapter.enter = function() {
59543         dragMap();
59544     };
59545
59546
59547     chapter.exit = function() {
59548         timeouts.forEach(window.clearTimeout);
59549         context.on('enter.intro exit.intro', null);
59550         context.map().on('move.intro drawn.intro', null);
59551         context.history().on('change.intro', null);
59552         select('.inspector-wrap').on('wheel.intro', null);
59553         select('.search-header input').on('keydown.intro keyup.intro', null);
59554     };
59555
59556
59557     chapter.restart = function() {
59558         chapter.exit();
59559         chapter.enter();
59560     };
59561
59562
59563     return utilRebind(chapter, dispatch$$1, 'on');
59564 }
59565
59566 function uiIntroPoint(context, reveal) {
59567     var dispatch$$1 = dispatch('done'),
59568         timeouts = [],
59569         intersection = [-85.63279, 41.94394],
59570         building = [-85.632422, 41.944045],
59571         cafePreset = context.presets().item('amenity/cafe'),
59572         pointId = null;
59573
59574
59575     var chapter = {
59576         title: 'intro.points.title'
59577     };
59578
59579
59580     function timeout$$1(f, t$$1) {
59581         timeouts.push(window.setTimeout(f, t$$1));
59582     }
59583
59584
59585     function revealEditMenu(loc, text$$1, options) {
59586         var rect = context.surfaceRect();
59587         var point = context.curtainProjection(loc);
59588         var pad$$1 = 40;
59589         var width = 250 + (2 * pad$$1);
59590         var height = 250;
59591         var startX = rect.left + point[0];
59592         var left = (textDirection === 'rtl') ? (startX - width + pad$$1) : (startX - pad$$1);
59593         var box = {
59594             left: left,
59595             top: point[1] + rect.top - 60,
59596             width: width,
59597             height: height
59598         };
59599         reveal(box, text$$1, options);
59600     }
59601
59602
59603     function eventCancel() {
59604         event.stopPropagation();
59605         event.preventDefault();
59606     }
59607
59608
59609     function addPoint() {
59610         context.enter(modeBrowse(context));
59611         context.history().reset('initial');
59612
59613         var msec = transitionTime(intersection, context.map().center());
59614         if (msec) { reveal(null, null, { duration: 0 }); }
59615         context.map().zoom(19).centerEase(intersection, msec);
59616
59617         timeout$$1(function() {
59618             var tooltip = reveal('button.add-point',
59619                 t('intro.points.add_point', { button: icon('#icon-point', 'pre-text') }));
59620
59621             pointId = null;
59622
59623             tooltip.selectAll('.tooltip-inner')
59624                 .insert('svg', 'span')
59625                 .attr('class', 'tooltip-illustration')
59626                 .append('use')
59627                 .attr('xlink:href', '#poi-images');
59628
59629             context.on('enter.intro', function(mode) {
59630                 if (mode.id !== 'add-point') return;
59631                 continueTo(placePoint);
59632             });
59633         }, msec + 100);
59634
59635         function continueTo(nextStep) {
59636             context.on('enter.intro', null);
59637             nextStep();
59638         }
59639     }
59640
59641
59642     function placePoint() {
59643         if (context.mode().id !== 'add-point') {
59644             return chapter.restart();
59645         }
59646
59647         var pointBox$$1 = pad$1(building, 150, context);
59648         reveal(pointBox$$1, t('intro.points.place_point'));
59649
59650         context.map().on('move.intro drawn.intro', function() {
59651             pointBox$$1 = pad$1(building, 150, context);
59652             reveal(pointBox$$1, t('intro.points.place_point'), { duration: 0 });
59653         });
59654
59655         context.on('enter.intro', function(mode) {
59656             if (mode.id !== 'select') return chapter.restart();
59657             pointId = context.mode().selectedIDs()[0];
59658             continueTo(searchPreset);
59659         });
59660
59661         function continueTo(nextStep) {
59662             context.map().on('move.intro drawn.intro', null);
59663             context.on('enter.intro', null);
59664             nextStep();
59665         }
59666     }
59667
59668
59669     function searchPreset() {
59670         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
59671             return addPoint();
59672         }
59673
59674         // disallow scrolling
59675         select('.inspector-wrap').on('wheel.intro', eventCancel);
59676
59677         select('.preset-search-input')
59678             .on('keydown.intro', null)
59679             .on('keyup.intro', checkPresetSearch);
59680
59681         reveal('.preset-search-input',
59682             t('intro.points.search_cafe', { preset: cafePreset.name() })
59683         );
59684
59685         context.on('enter.intro', function(mode) {
59686             if (!pointId || !context.hasEntity(pointId)) {
59687                 return continueTo(addPoint);
59688             }
59689
59690             var ids = context.selectedIDs();
59691             if (mode.id !== 'select' || !ids.length || ids[0] !== pointId) {
59692                 // keep the user's point selected..
59693                 context.enter(modeSelect(context, [pointId]));
59694
59695                 // disallow scrolling
59696                 select('.inspector-wrap').on('wheel.intro', eventCancel);
59697
59698                 select('.preset-search-input')
59699                     .on('keydown.intro', null)
59700                     .on('keyup.intro', checkPresetSearch);
59701
59702                 reveal('.preset-search-input',
59703                     t('intro.points.search_cafe', { preset: cafePreset.name() })
59704                 );
59705
59706                 context.history().on('change.intro', null);
59707             }
59708         });
59709
59710
59711         function checkPresetSearch() {
59712             var first = select('.preset-list-item:first-child');
59713
59714             if (first.classed('preset-amenity-cafe')) {
59715                 select('.preset-search-input')
59716                     .on('keydown.intro', eventCancel, true)
59717                     .on('keyup.intro', null);
59718
59719                 reveal(first.select('.preset-list-button').node(),
59720                     t('intro.points.choose_cafe', { preset: cafePreset.name() }),
59721                     { duration: 300 }
59722                 );
59723
59724                 context.history().on('change.intro', function() {
59725                     continueTo(aboutFeatureEditor);
59726                 });
59727             }
59728         }
59729
59730         function continueTo(nextStep) {
59731             context.on('enter.intro', null);
59732             context.history().on('change.intro', null);
59733             select('.inspector-wrap').on('wheel.intro', null);
59734             select('.preset-search-input').on('keydown.intro keyup.intro', null);
59735             nextStep();
59736         }
59737     }
59738
59739
59740     function aboutFeatureEditor() {
59741         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
59742             return addPoint();
59743         }
59744
59745         timeout$$1(function() {
59746             reveal('.entity-editor-pane', t('intro.points.feature_editor'), {
59747                 tooltipClass: 'intro-points-describe',
59748                 buttonText: t('intro.ok'),
59749                 buttonCallback: function() { continueTo(addName); }
59750             });
59751         }, 400);
59752
59753         context.on('exit.intro', function() {
59754             // if user leaves select mode here, just continue with the tutorial.
59755             continueTo(reselectPoint);
59756         });
59757
59758         function continueTo(nextStep) {
59759             context.on('exit.intro', null);
59760             nextStep();
59761         }
59762     }
59763
59764
59765     function addName() {
59766         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
59767             return addPoint();
59768         }
59769
59770         // reset pane, in case user happened to change it..
59771         select('.inspector-wrap .panewrap').style('right', '0%');
59772
59773         timeout$$1(function() {
59774             // It's possible for the user to add a name in a previous step..
59775             // If so, don't tell them to add the name in this step.
59776             // Give them an OK button instead.
59777             var entity = context.entity(pointId);
59778             if (entity.tags.name) {
59779                 var tooltip = reveal('.entity-editor-pane', t('intro.points.add_name'), {
59780                     tooltipClass: 'intro-points-describe',
59781                     buttonText: t('intro.ok'),
59782                     buttonCallback: function() { continueTo(addCloseEditor); }
59783                 });
59784                 tooltip.select('.instruction').style('display', 'none');
59785
59786             } else {
59787                 reveal('.entity-editor-pane', t('intro.points.add_name'),
59788                     { tooltipClass: 'intro-points-describe' }
59789                 );
59790             }
59791         }, 400);
59792
59793         context.history().on('change.intro', function() {
59794             continueTo(addCloseEditor);
59795         });
59796
59797         context.on('exit.intro', function() {
59798             // if user leaves select mode here, just continue with the tutorial.
59799             continueTo(reselectPoint);
59800         });
59801
59802         function continueTo(nextStep) {
59803             context.on('exit.intro', null);
59804             context.history().on('change.intro', null);
59805             nextStep();
59806         }
59807     }
59808
59809
59810     function addCloseEditor() {
59811         // reset pane, in case user happened to change it..
59812         select('.inspector-wrap .panewrap').style('right', '0%');
59813
59814         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59815         var href = select(selector$$1).attr('href') || '#icon-close';
59816
59817         context.on('exit.intro', function() {
59818             continueTo(reselectPoint);
59819         });
59820
59821         reveal('.entity-editor-pane',
59822             t('intro.points.add_close', { button: icon(href, 'pre-text') })
59823         );
59824
59825         function continueTo(nextStep) {
59826             context.on('exit.intro', null);
59827             nextStep();
59828         }
59829     }
59830
59831
59832     function reselectPoint() {
59833         if (!pointId) return chapter.restart();
59834         var entity = context.hasEntity(pointId);
59835         if (!entity) return chapter.restart();
59836
59837         // make sure it's still a cafe, in case user somehow changed it..
59838         var oldPreset = context.presets().match(entity, context.graph());
59839         context.replace(actionChangePreset(pointId, oldPreset, cafePreset));
59840
59841         context.enter(modeBrowse(context));
59842
59843         var msec = transitionTime(entity.loc, context.map().center());
59844         if (msec) { reveal(null, null, { duration: 0 }); }
59845         context.map().centerEase(entity.loc, msec);
59846
59847         timeout$$1(function() {
59848             var box = pointBox(entity.loc, context);
59849             reveal(box, t('intro.points.reselect'), { duration: 600 });
59850
59851             timeout$$1(function() {
59852                 context.map().on('move.intro drawn.intro', function() {
59853                     var entity = context.hasEntity(pointId);
59854                     if (!entity) return chapter.restart();
59855                     var box = pointBox(entity.loc, context);
59856                     reveal(box, t('intro.points.reselect'), { duration: 0 });
59857                 });
59858             }, 600); // after reveal..
59859
59860             context.on('enter.intro', function(mode) {
59861                 if (mode.id !== 'select') return;
59862                 continueTo(updatePoint);
59863             });
59864
59865         }, msec + 100);
59866
59867         function continueTo(nextStep) {
59868             context.map().on('move.intro drawn.intro', null);
59869             context.on('enter.intro', null);
59870             nextStep();
59871         }
59872     }
59873
59874
59875     function updatePoint() {
59876         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
59877             return continueTo(reselectPoint);
59878         }
59879
59880         // reset pane, in case user happened to untag the point..
59881         select('.inspector-wrap .panewrap').style('right', '0%');
59882
59883         context.on('exit.intro', function() {
59884             continueTo(reselectPoint);
59885         });
59886
59887         context.history().on('change.intro', function() {
59888             continueTo(updateCloseEditor);
59889         });
59890
59891         timeout$$1(function() {
59892             reveal('.entity-editor-pane', t('intro.points.update'),
59893                 { tooltipClass: 'intro-points-describe' }
59894             );
59895         }, 400);
59896
59897         function continueTo(nextStep) {
59898             context.on('exit.intro', null);
59899             context.history().on('change.intro', null);
59900             nextStep();
59901         }
59902     }
59903
59904
59905     function updateCloseEditor() {
59906         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
59907             return continueTo(reselectPoint);
59908         }
59909
59910         // reset pane, in case user happened to change it..
59911         select('.inspector-wrap .panewrap').style('right', '0%');
59912
59913         context.on('exit.intro', function() {
59914             continueTo(rightClickPoint);
59915         });
59916
59917         timeout$$1(function() {
59918             reveal('.entity-editor-pane',
59919                 t('intro.points.update_close', { button: icon('#icon-apply', 'pre-text') })
59920             );
59921         }, 500);
59922
59923         function continueTo(nextStep) {
59924             context.on('exit.intro', null);
59925             nextStep();
59926         }
59927     }
59928
59929
59930     function rightClickPoint() {
59931         if (!pointId) return chapter.restart();
59932         var entity = context.hasEntity(pointId);
59933         if (!entity) return chapter.restart();
59934
59935         context.enter(modeBrowse(context));
59936
59937         var box = pointBox(entity.loc, context);
59938         reveal(box, t('intro.points.rightclick'), { duration: 600 });
59939
59940         timeout$$1(function() {
59941             context.map().on('move.intro drawn.intro', function() {
59942                 var entity = context.hasEntity(pointId);
59943                 if (!entity) return chapter.restart();
59944                 var box = pointBox(entity.loc, context);
59945                 reveal(box, t('intro.points.rightclick'), { duration: 0 });
59946             });
59947         }, 600); // after reveal
59948
59949         context.on('enter.intro', function(mode) {
59950             if (mode.id !== 'select') return;
59951             var ids = context.selectedIDs();
59952             if (ids.length !== 1 || ids[0] !== pointId) return;
59953
59954             timeout$$1(function() {
59955                 var node = selectMenuItem('delete').node();
59956                 if (!node) return;
59957                 continueTo(enterDelete);
59958             }, 300);  // after menu visible
59959         });
59960
59961         function continueTo(nextStep) {
59962             context.on('enter.intro', null);
59963             context.map().on('move.intro drawn.intro', null);
59964             nextStep();
59965         }
59966     }
59967
59968
59969     function enterDelete() {
59970         if (!pointId) return chapter.restart();
59971         var entity = context.hasEntity(pointId);
59972         if (!entity) return chapter.restart();
59973
59974         var node = selectMenuItem('delete').node();
59975         if (!node) { return continueTo(rightClickPoint); }
59976
59977         revealEditMenu(entity.loc,
59978             t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') })
59979         );
59980
59981         timeout$$1(function() {
59982             context.map().on('move.intro drawn.intro', function() {
59983                 revealEditMenu(entity.loc,
59984                     t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') }),
59985                     { duration: 0}
59986                 );
59987             });
59988         }, 300); // after menu visible
59989
59990         context.on('exit.intro', function() {
59991             if (!pointId) return chapter.restart();
59992             var entity = context.hasEntity(pointId);
59993             if (entity) return continueTo(rightClickPoint);  // point still exists
59994         });
59995
59996         context.history().on('change.intro', function(changed) {
59997             if (changed.deleted().length) {
59998                 continueTo(undo);
59999             }
60000         });
60001
60002         function continueTo(nextStep) {
60003             context.map().on('move.intro drawn.intro', null);
60004             context.history().on('change.intro', null);
60005             context.on('exit.intro', null);
60006             nextStep();
60007         }
60008     }
60009
60010
60011     function undo() {
60012         context.history().on('change.intro', function() {
60013             continueTo(play);
60014         });
60015
60016         var iconName = '#icon-' + (textDirection === 'rtl' ? 'redo' : 'undo');
60017         reveal('#bar button.undo-button',
60018             t('intro.points.undo', { button: icon(iconName, 'pre-text') })
60019         );
60020
60021         function continueTo(nextStep) {
60022             context.history().on('change.intro', null);
60023             nextStep();
60024         }
60025     }
60026
60027
60028     function play() {
60029         dispatch$$1.call('done');
60030         reveal('#id-container',
60031             t('intro.points.play', { next: t('intro.areas.title') }), {
60032                 tooltipBox: '.intro-nav-wrap .chapter-area',
60033                 buttonText: t('intro.ok'),
60034                 buttonCallback: function() { reveal('#id-container'); }
60035             }
60036         );
60037     }
60038
60039
60040     chapter.enter = function() {
60041         addPoint();
60042     };
60043
60044
60045     chapter.exit = function() {
60046         timeouts.forEach(window.clearTimeout);
60047         context.on('enter.intro exit.intro', null);
60048         context.map().on('move.intro drawn.intro', null);
60049         context.history().on('change.intro', null);
60050         select('.inspector-wrap').on('wheel.intro', eventCancel);
60051         select('.preset-search-input').on('keydown.intro keyup.intro', null);
60052     };
60053
60054
60055     chapter.restart = function() {
60056         chapter.exit();
60057         chapter.enter();
60058     };
60059
60060
60061     return utilRebind(chapter, dispatch$$1, 'on');
60062 }
60063
60064 function uiIntroArea(context, reveal) {
60065     var dispatch$$1 = dispatch('done'),
60066         playground = [-85.63552, 41.94159],
60067         playgroundPreset = context.presets().item('leisure/playground'),
60068         descriptionField = context.presets().field('description'),
60069         timeouts = [],
60070         areaId;
60071
60072
60073     var chapter = {
60074         title: 'intro.areas.title'
60075     };
60076
60077
60078     function timeout$$1(f, t$$1) {
60079         timeouts.push(window.setTimeout(f, t$$1));
60080     }
60081
60082
60083     function eventCancel() {
60084         event.stopPropagation();
60085         event.preventDefault();
60086     }
60087
60088
60089     function revealPlayground(center, text$$1, options) {
60090         var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
60091         var box = pad$1(center, padding, context);
60092         reveal(box, text$$1, options);
60093     }
60094
60095
60096     function addArea() {
60097         context.enter(modeBrowse(context));
60098         context.history().reset('initial');
60099         areaId = null;
60100
60101         var msec = transitionTime(playground, context.map().center());
60102         if (msec) { reveal(null, null, { duration: 0 }); }
60103         context.map().zoom(19).centerEase(playground, msec);
60104
60105         timeout$$1(function() {
60106             var tooltip = reveal('button.add-area',
60107                 t('intro.areas.add_playground', { button: icon('#icon-area', 'pre-text') }));
60108
60109             tooltip.selectAll('.tooltip-inner')
60110                 .insert('svg', 'span')
60111                 .attr('class', 'tooltip-illustration')
60112                 .append('use')
60113                 .attr('xlink:href', '#landuse-images');
60114
60115             context.on('enter.intro', function(mode) {
60116                 if (mode.id !== 'add-area') return;
60117                 continueTo(startPlayground);
60118             });
60119         }, msec + 100);
60120
60121         function continueTo(nextStep) {
60122             context.on('enter.intro', null);
60123             nextStep();
60124         }
60125     }
60126
60127
60128     function startPlayground() {
60129         if (context.mode().id !== 'add-area') {
60130             return chapter.restart();
60131         }
60132
60133         areaId = null;
60134         context.map().zoomEase(19.5, 500);
60135
60136         timeout$$1(function() {
60137             revealPlayground(playground,
60138                 t('intro.areas.start_playground'), { duration: 250 }
60139             );
60140
60141             timeout$$1(function() {
60142                 context.map().on('move.intro drawn.intro', function() {
60143                     revealPlayground(playground,
60144                         t('intro.areas.start_playground'), { duration: 0 }
60145                     );
60146                 });
60147                 context.on('enter.intro', function(mode) {
60148                     if (mode.id !== 'draw-area') return chapter.restart();
60149                     continueTo(continuePlayground);
60150                 });
60151             }, 250);  // after reveal
60152
60153         }, 550);  // after easing
60154
60155         function continueTo(nextStep) {
60156             context.map().on('move.intro drawn.intro', null);
60157             context.on('enter.intro', null);
60158             nextStep();
60159         }
60160     }
60161
60162
60163     function continuePlayground() {
60164         if (context.mode().id !== 'draw-area') {
60165             return chapter.restart();
60166         }
60167
60168         areaId = null;
60169         revealPlayground(playground,
60170             t('intro.areas.continue_playground'), { duration: 250 }
60171         );
60172
60173         timeout$$1(function() {
60174             context.map().on('move.intro drawn.intro', function() {
60175                 revealPlayground(playground,
60176                     t('intro.areas.continue_playground'), { duration: 0 }
60177                 );
60178             });
60179         }, 250);  // after reveal
60180
60181         context.on('enter.intro', function(mode) {
60182             if (mode.id === 'draw-area') {
60183                 var entity = context.hasEntity(context.selectedIDs()[0]);
60184                 if (entity && entity.nodes.length >= 6) {
60185                     return continueTo(finishPlayground);
60186                 } else {
60187                     return;
60188                 }
60189             } else if (mode.id === 'select') {
60190                 areaId = context.selectedIDs()[0];
60191                 return continueTo(searchPresets);
60192             } else {
60193                 return chapter.restart();
60194             }
60195         });
60196
60197         function continueTo(nextStep) {
60198             context.map().on('move.intro drawn.intro', null);
60199             context.on('enter.intro', null);
60200             nextStep();
60201         }
60202     }
60203
60204
60205     function finishPlayground() {
60206         if (context.mode().id !== 'draw-area') {
60207             return chapter.restart();
60208         }
60209
60210         areaId = null;
60211         revealPlayground(playground,
60212             t('intro.areas.finish_playground'), { duration: 250 }
60213         );
60214
60215         timeout$$1(function() {
60216             context.map().on('move.intro drawn.intro', function() {
60217                 revealPlayground(playground,
60218                     t('intro.areas.finish_playground'), { duration: 0 }
60219                 );
60220             });
60221         }, 250);  // after reveal
60222
60223         context.on('enter.intro', function(mode) {
60224             if (mode.id === 'draw-area') {
60225                 return;
60226             } else if (mode.id === 'select') {
60227                 areaId = context.selectedIDs()[0];
60228                 return continueTo(searchPresets);
60229             } else {
60230                 return chapter.restart();
60231             }
60232         });
60233
60234         function continueTo(nextStep) {
60235             context.map().on('move.intro drawn.intro', null);
60236             context.on('enter.intro', null);
60237             nextStep();
60238         }
60239     }
60240
60241
60242     function searchPresets() {
60243         if (!areaId || !context.hasEntity(areaId)) {
60244             return addArea();
60245         }
60246         var ids = context.selectedIDs();
60247         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60248             context.enter(modeSelect(context, [areaId]));
60249         }
60250
60251         // disallow scrolling
60252         select('.inspector-wrap').on('wheel.intro', eventCancel);
60253
60254         timeout$$1(function() {
60255             // reset pane, in case user somehow happened to change it..
60256             select('.inspector-wrap .panewrap').style('right', '-100%');
60257
60258             select('.preset-search-input')
60259                 .on('keydown.intro', null)
60260                 .on('keyup.intro', checkPresetSearch);
60261
60262             reveal('.preset-search-input',
60263                 t('intro.areas.search_playground', { preset: playgroundPreset.name() })
60264             );
60265         }, 400);  // after preset list pane visible..
60266
60267         context.on('enter.intro', function(mode) {
60268             if (!areaId || !context.hasEntity(areaId)) {
60269                 return continueTo(addArea);
60270             }
60271
60272             var ids = context.selectedIDs();
60273             if (mode.id !== 'select' || !ids.length || ids[0] !== areaId) {
60274                 // keep the user's area selected..
60275                 context.enter(modeSelect(context, [areaId]));
60276
60277                 // reset pane, in case user somehow happened to change it..
60278                 select('.inspector-wrap .panewrap').style('right', '-100%');
60279                 // disallow scrolling
60280                 select('.inspector-wrap').on('wheel.intro', eventCancel);
60281
60282                 select('.preset-search-input')
60283                     .on('keydown.intro', null)
60284                     .on('keyup.intro', checkPresetSearch);
60285
60286                 reveal('.preset-search-input',
60287                     t('intro.areas.search_playground', { preset: playgroundPreset.name() })
60288                 );
60289
60290                 context.history().on('change.intro', null);
60291             }
60292         });
60293
60294         function checkPresetSearch() {
60295             var first = select('.preset-list-item:first-child');
60296
60297             if (first.classed('preset-leisure-playground')) {
60298                 reveal(first.select('.preset-list-button').node(),
60299                     t('intro.areas.choose_playground', { preset: playgroundPreset.name() }),
60300                     { duration: 300 }
60301                 );
60302
60303                 select('.preset-search-input')
60304                     .on('keydown.intro', eventCancel, true)
60305                     .on('keyup.intro', null);
60306
60307                 context.history().on('change.intro', function() {
60308                     continueTo(clickAddField);
60309                 });
60310             }
60311         }
60312
60313         function continueTo(nextStep) {
60314             select('.inspector-wrap').on('wheel.intro', null);
60315             context.on('enter.intro', null);
60316             context.history().on('change.intro', null);
60317             select('.preset-search-input').on('keydown.intro keyup.intro', null);
60318             nextStep();
60319         }
60320     }
60321
60322
60323     function clickAddField() {
60324         if (!areaId || !context.hasEntity(areaId)) {
60325             return addArea();
60326         }
60327         var ids = context.selectedIDs();
60328         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60329             return searchPresets();
60330         }
60331
60332         if (!select('.form-field-description').empty()) {
60333             return continueTo(describePlayground);
60334         }
60335
60336         // disallow scrolling
60337         select('.inspector-wrap').on('wheel.intro', eventCancel);
60338
60339         timeout$$1(function() {
60340             // reset pane, in case user somehow happened to change it..
60341             select('.inspector-wrap .panewrap').style('right', '0%');
60342
60343             // It's possible for the user to add a description in a previous step..
60344             // If they did this already, just continue to next step.
60345             var entity = context.entity(areaId);
60346             if (entity.tags.description) {
60347                 return continueTo(play);
60348             }
60349
60350             reveal('.more-fields .combobox-input',
60351                 t('intro.areas.add_field'),
60352                 { duration: 300 }
60353             );
60354
60355             select('.more-fields .combobox-input')
60356                 .on('click.intro', function() {
60357                     continueTo(chooseDescriptionField);
60358                 });
60359         }, 400);  // after editor pane visible
60360
60361         context.on('exit.intro', function() {
60362             return continueTo(searchPresets);
60363         });
60364
60365         function continueTo(nextStep) {
60366             select('.inspector-wrap').on('wheel.intro', null);
60367             select('.more-fields .combobox-input').on('click.intro', null);
60368             context.on('exit.intro', null);
60369             nextStep();
60370         }
60371     }
60372
60373
60374     function chooseDescriptionField() {
60375         if (!areaId || !context.hasEntity(areaId)) {
60376             return addArea();
60377         }
60378         var ids = context.selectedIDs();
60379         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60380             return searchPresets();
60381         }
60382
60383         if (!select('.form-field-description').empty()) {
60384             return continueTo(describePlayground);
60385         }
60386
60387         // Make sure combobox is ready..
60388         if (select('div.combobox').empty()) {
60389             return continueTo(clickAddField);
60390         }
60391         // Watch for the combobox to go away..
60392         var watcher;
60393         watcher = window.setInterval(function() {
60394             if (select('div.combobox').empty()) {
60395                 window.clearInterval(watcher);
60396                 timeout$$1(function() {
60397                     if (select('.form-field-description').empty()) {
60398                         continueTo(retryChooseDescription);
60399                     } else {
60400                         continueTo(describePlayground);
60401                     }
60402                 }, 300);  // after description field added.
60403             }
60404         }, 300);
60405
60406         reveal('div.combobox',
60407             t('intro.areas.choose_field', { field: descriptionField.label() }),
60408             { duration: 300 }
60409         );
60410
60411         context.on('exit.intro', function() {
60412             return continueTo(searchPresets);
60413         });
60414
60415         function continueTo(nextStep) {
60416             if (watcher) window.clearInterval(watcher);
60417             context.on('exit.intro', null);
60418             nextStep();
60419         }
60420     }
60421
60422
60423     function describePlayground() {
60424         if (!areaId || !context.hasEntity(areaId)) {
60425             return addArea();
60426         }
60427         var ids = context.selectedIDs();
60428         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60429             return searchPresets();
60430         }
60431
60432         // reset pane, in case user happened to change it..
60433         select('.inspector-wrap .panewrap').style('right', '0%');
60434
60435         if (select('.form-field-description').empty()) {
60436             return continueTo(retryChooseDescription);
60437         }
60438
60439         context.on('exit.intro', function() {
60440             continueTo(play);
60441         });
60442
60443         reveal('.entity-editor-pane',
60444             t('intro.areas.describe_playground', { button: icon('#icon-apply', 'pre-text') }),
60445             { duration: 300 }
60446         );
60447
60448         function continueTo(nextStep) {
60449             context.on('exit.intro', null);
60450             nextStep();
60451         }
60452     }
60453
60454
60455     function retryChooseDescription() {
60456         if (!areaId || !context.hasEntity(areaId)) {
60457             return addArea();
60458         }
60459         var ids = context.selectedIDs();
60460         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60461             return searchPresets();
60462         }
60463
60464         // reset pane, in case user happened to change it..
60465         select('.inspector-wrap .panewrap').style('right', '0%');
60466
60467         reveal('.entity-editor-pane',
60468             t('intro.areas.retry_add_field', { field: descriptionField.label() }), {
60469             buttonText: t('intro.ok'),
60470             buttonCallback: function() { continueTo(clickAddField); }
60471         });
60472
60473         context.on('exit.intro', function() {
60474             return continueTo(searchPresets);
60475         });
60476
60477         function continueTo(nextStep) {
60478             context.on('exit.intro', null);
60479             nextStep();
60480         }
60481     }
60482
60483
60484     function play() {
60485         dispatch$$1.call('done');
60486         reveal('#id-container',
60487             t('intro.areas.play', { next: t('intro.lines.title') }), {
60488                 tooltipBox: '.intro-nav-wrap .chapter-line',
60489                 buttonText: t('intro.ok'),
60490                 buttonCallback: function() { reveal('#id-container'); }
60491             }
60492         );
60493     }
60494
60495
60496     chapter.enter = function() {
60497         addArea();
60498     };
60499
60500
60501     chapter.exit = function() {
60502         timeouts.forEach(window.clearTimeout);
60503         context.on('enter.intro exit.intro', null);
60504         context.map().on('move.intro drawn.intro', null);
60505         context.history().on('change.intro', null);
60506         select('.inspector-wrap').on('wheel.intro', null);
60507         select('.preset-search-input').on('keydown.intro keyup.intro', null);
60508         select('.more-fields .combobox-input').on('click.intro', null);
60509     };
60510
60511
60512     chapter.restart = function() {
60513         chapter.exit();
60514         chapter.enter();
60515     };
60516
60517
60518     return utilRebind(chapter, dispatch$$1, 'on');
60519 }
60520
60521 function uiIntroLine(context, reveal) {
60522     var dispatch$$1 = dispatch('done'),
60523         timeouts = [],
60524         tulipRoadId = null,
60525         flowerRoadId = 'w646',
60526         tulipRoadStart = [-85.6297754121684, 41.95805253325314],
60527         tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204],
60528         tulipRoadIntersection = [-85.62974496187628, 41.95742515554585],
60529         roadCategory = context.presets().item('category-road'),
60530         residentialPreset = context.presets().item('highway/residential'),
60531         woodRoadId = 'w525',
60532         woodRoadEndId = 'n2862',
60533         woodRoadAddNode = [-85.62390110349587, 41.95397111462291],
60534         woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487],
60535         woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872],
60536         washingtonStreetId = 'w522',
60537         twelfthAvenueId = 'w1',
60538         eleventhAvenueEndId = 'n3550',
60539         twelfthAvenueEndId = 'n5',
60540         washingtonSegmentId = null,
60541         eleventhAvenueEnd = context.entity(eleventhAvenueEndId).loc,
60542         twelfthAvenueEnd = context.entity(twelfthAvenueEndId).loc,
60543         deleteLinesLoc = [-85.6219395542764, 41.95228033922477],
60544         twelfthAvenue = [-85.62219310052491, 41.952505413152956];
60545
60546
60547     var chapter = {
60548         title: 'intro.lines.title'
60549     };
60550
60551
60552     function timeout$$1(f, t$$1) {
60553         timeouts.push(window.setTimeout(f, t$$1));
60554     }
60555
60556
60557     function eventCancel() {
60558         event.stopPropagation();
60559         event.preventDefault();
60560     }
60561
60562
60563     function revealEditMenu(loc, text$$1, options) {
60564         var rect = context.surfaceRect();
60565         var point = context.curtainProjection(loc);
60566         var pad$$1 = 40;
60567         var width = 250 + (2 * pad$$1);
60568         var height = 350;
60569         var startX = rect.left + point[0];
60570         var left = (textDirection === 'rtl') ? (startX - width + pad$$1) : (startX - pad$$1);
60571         var box = {
60572             left: left,
60573             top: point[1] + rect.top - 60,
60574             width: width,
60575             height: height
60576         };
60577         reveal(box, text$$1, options);
60578     }
60579
60580
60581     function addLine() {
60582         context.enter(modeBrowse(context));
60583         context.history().reset('initial');
60584
60585         var msec = transitionTime(tulipRoadStart, context.map().center());
60586         if (msec) { reveal(null, null, { duration: 0 }); }
60587         context.map().zoom(18.5).centerEase(tulipRoadStart, msec);
60588
60589         timeout$$1(function() {
60590             var tooltip = reveal('button.add-line',
60591                 t('intro.lines.add_line', { button: icon('#icon-line', 'pre-text') }));
60592
60593             tooltip.selectAll('.tooltip-inner')
60594                 .insert('svg', 'span')
60595                 .attr('class', 'tooltip-illustration')
60596                 .append('use')
60597                 .attr('xlink:href', '#feature-images');
60598
60599             context.on('enter.intro', function(mode) {
60600                 if (mode.id !== 'add-line') return;
60601                 continueTo(startLine);
60602             });
60603         }, msec + 100);
60604
60605         function continueTo(nextStep) {
60606             context.on('enter.intro', null);
60607             nextStep();
60608         }
60609     }
60610
60611
60612     function startLine() {
60613         if (context.mode().id !== 'add-line') {
60614             return chapter.restart();
60615         }
60616
60617         tulipRoadId = null;
60618
60619         var padding = 70 * Math.pow(2, context.map().zoom() - 18);
60620         var box = pad$1(tulipRoadStart, padding, context);
60621         box.height = box.height + 100;
60622         reveal(box, t('intro.lines.start_line'));
60623
60624         context.map().on('move.intro drawn.intro', function() {
60625             padding = 70 * Math.pow(2, context.map().zoom() - 18);
60626             box = pad$1(tulipRoadStart, padding, context);
60627             box.height = box.height + 100;
60628             reveal(box, t('intro.lines.start_line'), { duration: 0 });
60629         });
60630
60631         context.on('enter.intro', function(mode) {
60632             if (mode.id !== 'draw-line') return chapter.restart();
60633             continueTo(drawLine);
60634         });
60635
60636         function continueTo(nextStep) {
60637             context.map().on('move.intro drawn.intro', null);
60638             context.on('enter.intro', null);
60639             nextStep();
60640         }
60641     }
60642
60643
60644     function drawLine() {
60645         if (context.mode().id !== 'draw-line') {
60646             return chapter.restart();
60647         }
60648
60649         tulipRoadId = context.mode().selectedIDs()[0];
60650         context.map().centerEase(tulipRoadMidpoint, 500);
60651
60652         timeout$$1(function() {
60653             var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
60654             var box = pad$1(tulipRoadMidpoint, padding, context);
60655             box.height = box.height * 2;
60656             reveal(box,
60657                 t('intro.lines.intersect', { name: t('intro.graph.name.flower-street') })
60658             );
60659
60660             context.map().on('move.intro drawn.intro', function() {
60661                 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
60662                 box = pad$1(tulipRoadMidpoint, padding, context);
60663                 box.height = box.height * 2;
60664                 reveal(box,
60665                     t('intro.lines.intersect', { name: t('intro.graph.name.flower-street') }),
60666                     { duration: 0 }
60667                 );
60668             });
60669         }, 550);  // after easing..
60670
60671         context.history().on('change.intro', function() {
60672             var entity = tulipRoadId && context.hasEntity(tulipRoadId);
60673             if (!entity) return chapter.restart();
60674
60675             if (isLineConnected()) {
60676                 continueTo(continueLine);
60677             }
60678         });
60679
60680         context.on('enter.intro', function(mode) {
60681             if (mode.id === 'draw-line')
60682                 return;
60683             else if (mode.id === 'select') {
60684                 continueTo(retryIntersect);
60685                 return;
60686             }
60687             else
60688                 return chapter.restart();
60689         });
60690
60691         function continueTo(nextStep) {
60692             context.map().on('move.intro drawn.intro', null);
60693             context.history().on('change.intro', null);
60694             context.on('enter.intro', null);
60695             nextStep();
60696         }
60697     }
60698
60699
60700     function isLineConnected() {
60701         var entity = tulipRoadId && context.hasEntity(tulipRoadId);
60702         if (!entity) return false;
60703
60704         var drawNodes = context.graph().childNodes(entity);
60705         return lodash.some(drawNodes, function(node) {
60706             return lodash.some(context.graph().parentWays(node), function(parent) {
60707                 return parent.id === flowerRoadId;
60708             });
60709         });
60710     }
60711
60712
60713     function retryIntersect() {
60714         select(window).on('mousedown.intro', eventCancel, true);
60715
60716         var box = pad$1(tulipRoadIntersection, 80, context);
60717         reveal(box,
60718             t('intro.lines.retry_intersect', { name: t('intro.graph.name.flower-street') })
60719         );
60720
60721         timeout$$1(chapter.restart, 3000);
60722     }
60723
60724
60725     function continueLine() {
60726         if (context.mode().id !== 'draw-line') return chapter.restart();
60727         var entity = tulipRoadId && context.hasEntity(tulipRoadId);
60728         if (!entity) return chapter.restart();
60729
60730         context.map().centerEase(tulipRoadIntersection, 500);
60731
60732         reveal('#surface', t('intro.lines.continue_line'));
60733
60734         context.on('enter.intro', function(mode) {
60735             if (mode.id === 'draw-line')
60736                 return;
60737             else if (mode.id === 'select')
60738                 return continueTo(chooseCategoryRoad);
60739             else
60740                 return chapter.restart();
60741         });
60742
60743         function continueTo(nextStep) {
60744             context.on('enter.intro', null);
60745             nextStep();
60746         }
60747     }
60748
60749
60750     function chooseCategoryRoad() {
60751         if (context.mode().id !== 'select') {
60752             return chapter.restart();
60753         }
60754
60755         context.on('exit.intro', function() {
60756             return chapter.restart();
60757         });
60758
60759         var button = select('.preset-category-road .preset-list-button');
60760         if (button.empty()) return chapter.restart();
60761
60762         // disallow scrolling
60763         select('.inspector-wrap').on('wheel.intro', eventCancel);
60764
60765         timeout$$1(function() {
60766             // reset pane, in case user somehow happened to change it..
60767             select('.inspector-wrap .panewrap').style('right', '-100%');
60768
60769             reveal(button.node(),
60770                 t('intro.lines.choose_category_road', { category: roadCategory.name() })
60771             );
60772
60773             button.on('click.intro', function() {
60774                 continueTo(choosePresetResidential);
60775             });
60776
60777         }, 400);  // after editor pane visible
60778
60779         function continueTo(nextStep) {
60780             select('.inspector-wrap').on('wheel.intro', null);
60781             select('.preset-list-button').on('click.intro', null);
60782             context.on('exit.intro', null);
60783             nextStep();
60784         }
60785     }
60786
60787
60788     function choosePresetResidential() {
60789         if (context.mode().id !== 'select') {
60790             return chapter.restart();
60791         }
60792
60793         context.on('exit.intro', function() {
60794             return chapter.restart();
60795         });
60796
60797         var subgrid = select('.preset-category-road .subgrid');
60798         if (subgrid.empty()) return chapter.restart();
60799
60800         subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button')
60801             .on('click.intro', function() {
60802                 continueTo(retryPresetResidential);
60803             });
60804
60805         subgrid.selectAll('.preset-highway-residential .preset-list-button')
60806             .on('click.intro', function() {
60807                 continueTo(nameRoad);
60808             });
60809
60810         timeout$$1(function() {
60811             reveal(subgrid.node(),
60812                 t('intro.lines.choose_preset_residential', { preset: residentialPreset.name() }),
60813                 { tooltipBox: '.preset-highway-residential .preset-list-button', duration: 300 }
60814             );
60815         }, 300);
60816
60817         function continueTo(nextStep) {
60818             select('.preset-list-button').on('click.intro', null);
60819             context.on('exit.intro', null);
60820             nextStep();
60821         }
60822     }
60823
60824
60825     // selected wrong road type
60826     function retryPresetResidential() {
60827         if (context.mode().id !== 'select') {
60828             return chapter.restart();
60829         }
60830
60831         context.on('exit.intro', function() {
60832             return chapter.restart();
60833         });
60834
60835         // disallow scrolling
60836         select('.inspector-wrap').on('wheel.intro', eventCancel);
60837
60838         timeout$$1(function() {
60839             var button = select('.entity-editor-pane .preset-list-button');
60840
60841             reveal(button.node(),
60842                 t('intro.lines.retry_preset_residential', { preset: residentialPreset.name() })
60843             );
60844
60845             button.on('click.intro', function() {
60846                 continueTo(chooseCategoryRoad);
60847             });
60848
60849         }, 500);
60850
60851         function continueTo(nextStep) {
60852             select('.inspector-wrap').on('wheel.intro', null);
60853             select('.preset-list-button').on('click.intro', null);
60854             context.on('exit.intro', null);
60855             nextStep();
60856         }
60857     }
60858
60859
60860     function nameRoad() {
60861         context.on('exit.intro', function() {
60862             continueTo(didNameRoad);
60863         });
60864
60865         timeout$$1(function() {
60866             reveal('.entity-editor-pane',
60867                 t('intro.lines.name_road', { button: icon('#icon-apply', 'pre-text') }),
60868                 { tooltipClass: 'intro-lines-name_road' }
60869             );
60870         }, 500);
60871
60872         function continueTo(nextStep) {
60873             context.on('exit.intro', null);
60874             nextStep();
60875         }
60876     }
60877
60878
60879     function didNameRoad() {
60880         context.history().checkpoint('doneAddLine');
60881
60882         timeout$$1(function() {
60883             reveal('#surface', t('intro.lines.did_name_road'), {
60884                 buttonText: t('intro.ok'),
60885                 buttonCallback: function() { continueTo(updateLine); }
60886             });
60887         }, 500);
60888
60889         function continueTo(nextStep) {
60890             nextStep();
60891         }
60892     }
60893
60894
60895     function updateLine() {
60896         context.history().reset('doneAddLine');
60897         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60898             return chapter.restart();
60899         }
60900
60901         var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
60902         if (msec) { reveal(null, null, { duration: 0 }); }
60903         context.map().zoom(19).centerEase(woodRoadDragMidpoint, msec);
60904
60905         timeout$$1(function() {
60906             var padding = 250 * Math.pow(2, context.map().zoom() - 19);
60907             var box = pad$1(woodRoadDragMidpoint, padding, context);
60908             var advance = function() { continueTo(addNode); };
60909
60910             reveal(box, t('intro.lines.update_line'),
60911                 { buttonText: t('intro.ok'), buttonCallback: advance }
60912             );
60913
60914             context.map().on('move.intro drawn.intro', function() {
60915                 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
60916                 var box = pad$1(woodRoadDragMidpoint, padding, context);
60917                 reveal(box, t('intro.lines.update_line'),
60918                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
60919                 );
60920             });
60921         }, msec + 100);
60922
60923         function continueTo(nextStep) {
60924             context.map().on('move.intro drawn.intro', null);
60925             nextStep();
60926         }
60927     }
60928
60929
60930     function addNode() {
60931         context.history().reset('doneAddLine');
60932         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60933             return chapter.restart();
60934         }
60935
60936         var padding = 40 * Math.pow(2, context.map().zoom() - 19);
60937         var box = pad$1(woodRoadAddNode, padding, context);
60938         reveal(box, t('intro.lines.add_node'));
60939
60940         context.map().on('move.intro drawn.intro', function() {
60941             var padding = 40 * Math.pow(2, context.map().zoom() - 19);
60942             var box = pad$1(woodRoadAddNode, padding, context);
60943             reveal(box, t('intro.lines.add_node'), { duration: 0 });
60944         });
60945
60946         context.history().on('change.intro', function(changed) {
60947             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60948                 return continueTo(updateLine);
60949             }
60950             if (changed.created().length === 1) {
60951                 timeout$$1(function() { continueTo(startDragEndpoint); }, 500);
60952             }
60953         });
60954
60955         context.on('enter.intro', function(mode) {
60956             if (mode.id !== 'select') {
60957                 continueTo(updateLine);
60958             }
60959         });
60960
60961         function continueTo(nextStep) {
60962             context.map().on('move.intro drawn.intro', null);
60963             context.history().on('change.intro', null);
60964             context.on('enter.intro', null);
60965             nextStep();
60966         }
60967     }
60968
60969
60970     function startDragEndpoint() {
60971         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60972             return continueTo(updateLine);
60973         }
60974         if (context.selectedIDs().indexOf(woodRoadId) === -1) {
60975             context.enter(modeSelect(context, [woodRoadId]));
60976         }
60977
60978         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
60979         var box = pad$1(woodRoadDragEndpoint, padding, context);
60980         reveal(box, t('intro.lines.start_drag_endpoint'));
60981
60982         context.map().on('move.intro drawn.intro', function() {
60983             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
60984                 return continueTo(updateLine);
60985             }
60986             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
60987             var box = pad$1(woodRoadDragEndpoint, padding, context);
60988             reveal(box, t('intro.lines.start_drag_endpoint'), { duration: 0 });
60989
60990             var entity = context.entity(woodRoadEndId);
60991             if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
60992                 continueTo(finishDragEndpoint);
60993             }
60994         });
60995
60996         context.on('enter.intro', function(mode) {
60997             if (mode.id !== 'select') {
60998                 // keep Wood Road selected so endpoint stays draggable..
60999                 context.enter(modeSelect(context, [woodRoadId]));
61000             }
61001         });
61002
61003         function continueTo(nextStep) {
61004             context.map().on('move.intro drawn.intro', null);
61005             context.on('enter.intro', null);
61006             nextStep();
61007         }
61008     }
61009
61010
61011     function finishDragEndpoint() {
61012         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61013             return continueTo(updateLine);
61014         }
61015
61016         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
61017         var box = pad$1(woodRoadDragEndpoint, padding, context);
61018         reveal(box, t('intro.lines.finish_drag_endpoint'));
61019
61020         context.map().on('move.intro drawn.intro', function() {
61021             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61022                 return continueTo(updateLine);
61023             }
61024             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
61025             var box = pad$1(woodRoadDragEndpoint, padding, context);
61026             reveal(box, t('intro.lines.finish_drag_endpoint'), { duration: 0 });
61027
61028             var entity = context.entity(woodRoadEndId);
61029             if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
61030                 continueTo(startDragEndpoint);
61031             }
61032         });
61033
61034         context.on('enter.intro', function() {
61035             continueTo(startDragMidpoint);
61036         });
61037
61038         function continueTo(nextStep) {
61039             context.map().on('move.intro drawn.intro', null);
61040             context.on('enter.intro', null);
61041             nextStep();
61042         }
61043     }
61044
61045
61046     function startDragMidpoint() {
61047         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61048             return continueTo(updateLine);
61049         }
61050         if (context.selectedIDs().indexOf(woodRoadId) === -1) {
61051             context.enter(modeSelect(context, [woodRoadId]));
61052         }
61053
61054         var padding = 80 * Math.pow(2, context.map().zoom() - 19);
61055         var box = pad$1(woodRoadDragMidpoint, padding, context);
61056         reveal(box, t('intro.lines.start_drag_midpoint'));
61057
61058         context.map().on('move.intro drawn.intro', function() {
61059             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61060                 return continueTo(updateLine);
61061             }
61062             var padding = 80 * Math.pow(2, context.map().zoom() - 19);
61063             var box = pad$1(woodRoadDragMidpoint, padding, context);
61064             reveal(box, t('intro.lines.start_drag_midpoint'), { duration: 0 });
61065         });
61066
61067         context.history().on('change.intro', function(changed) {
61068             if (changed.created().length === 1) {
61069                 continueTo(continueDragMidpoint);
61070             }
61071         });
61072
61073         context.on('enter.intro', function(mode) {
61074             if (mode.id !== 'select') {
61075                 // keep Wood Road selected so midpoint triangles are drawn..
61076                 context.enter(modeSelect(context, [woodRoadId]));
61077             }
61078         });
61079
61080         function continueTo(nextStep) {
61081             context.map().on('move.intro drawn.intro', null);
61082             context.history().on('change.intro', null);
61083             context.on('enter.intro', null);
61084             nextStep();
61085         }
61086     }
61087
61088
61089     function continueDragMidpoint() {
61090         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61091             return continueTo(updateLine);
61092         }
61093
61094         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
61095         var box = pad$1(woodRoadDragEndpoint, padding, context);
61096         box.height += 400;
61097
61098         var advance = function() {
61099             context.history().checkpoint('doneUpdateLine');
61100             continueTo(deleteLines);
61101         };
61102
61103         reveal(box, t('intro.lines.continue_drag_midpoint'),
61104             { buttonText: t('intro.ok'), buttonCallback: advance }
61105         );
61106
61107         context.map().on('move.intro drawn.intro', function() {
61108             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61109                 return continueTo(updateLine);
61110             }
61111             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
61112             var box = pad$1(woodRoadDragEndpoint, padding, context);
61113             box.height += 400;
61114             reveal(box, t('intro.lines.continue_drag_midpoint'),
61115                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
61116             );
61117         });
61118
61119         function continueTo(nextStep) {
61120             context.map().on('move.intro drawn.intro', null);
61121             nextStep();
61122         }
61123     }
61124
61125
61126     function deleteLines() {
61127         context.history().reset('doneUpdateLine');
61128         context.enter(modeBrowse(context));
61129
61130         if (!context.hasEntity(washingtonStreetId) ||
61131             !context.hasEntity(twelfthAvenueId) ||
61132             !context.hasEntity(eleventhAvenueEndId)) {
61133             return chapter.restart();
61134         }
61135
61136         var msec = transitionTime(deleteLinesLoc, context.map().center());
61137         if (msec) { reveal(null, null, { duration: 0 }); }
61138         context.map().zoom(18).centerEase(deleteLinesLoc, msec);
61139
61140         timeout$$1(function() {
61141             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61142             var box = pad$1(deleteLinesLoc, padding, context);
61143             box.top -= 200;
61144             box.height += 400;
61145             var advance = function() { continueTo(rightClickIntersection); };
61146
61147             reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }),
61148                 { buttonText: t('intro.ok'), buttonCallback: advance }
61149             );
61150
61151             context.map().on('move.intro drawn.intro', function() {
61152                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61153                 var box = pad$1(deleteLinesLoc, padding, context);
61154                 box.top -= 200;
61155                 box.height += 400;
61156                 reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }),
61157                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
61158                 );
61159             });
61160
61161             context.history().on('change.intro', function() {
61162                 timeout$$1(function() {
61163                     continueTo(deleteLines);
61164                 }, 500);  // after any transition (e.g. if user deleted intersection)
61165             });
61166
61167         }, msec + 100);
61168
61169         function continueTo(nextStep) {
61170             context.map().on('move.intro drawn.intro', null);
61171             context.history().on('change.intro', null);
61172             nextStep();
61173         }
61174     }
61175
61176
61177     function rightClickIntersection() {
61178         context.history().reset('doneUpdateLine');
61179         context.enter(modeBrowse(context));
61180
61181         context.map().zoom(18).centerEase(eleventhAvenueEnd, 500);
61182
61183         timeout$$1(function() {
61184             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
61185             var box = pad$1(eleventhAvenueEnd, padding, context);
61186             reveal(box, t('intro.lines.rightclick_intersection',
61187                 { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') })
61188             );
61189
61190             context.map().on('move.intro drawn.intro', function() {
61191                 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
61192                 var box = pad$1(eleventhAvenueEnd, padding, context);
61193                 reveal(box, t('intro.lines.rightclick_intersection',
61194                     { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') }),
61195                     { duration: 0 }
61196                 );
61197             });
61198
61199             context.on('enter.intro', function(mode) {
61200                 if (mode.id !== 'select') return;
61201                 var ids = context.selectedIDs();
61202                 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndId) return;
61203
61204                 timeout$$1(function() {
61205                     var node = selectMenuItem('split').node();
61206                     if (!node) return;
61207                     continueTo(splitIntersection);
61208                 }, 300);  // after menu visible
61209             });
61210
61211             context.history().on('change.intro', function() {
61212                 timeout$$1(function() {
61213                     continueTo(deleteLines);
61214                 }, 300);  // after any transition (e.g. if user deleted intersection)
61215             });
61216
61217         }, 600);
61218
61219         function continueTo(nextStep) {
61220             context.map().on('move.intro drawn.intro', null);
61221             context.on('enter.intro', null);
61222             context.history().on('change.intro', null);
61223             nextStep();
61224         }
61225     }
61226
61227
61228     function splitIntersection() {
61229         if (!context.hasEntity(washingtonStreetId) ||
61230             !context.hasEntity(twelfthAvenueId) ||
61231             !context.hasEntity(eleventhAvenueEndId)) {
61232             return continueTo(deleteLines);
61233         }
61234
61235         var node = selectMenuItem('split').node();
61236         if (!node) { return continueTo(rightClickIntersection); }
61237
61238         var wasChanged = false;
61239         var menuCoords = context.map().mouseCoordinates();
61240         washingtonSegmentId = null;
61241
61242         revealEditMenu(menuCoords, t('intro.lines.split_intersection',
61243             { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') })
61244         );
61245
61246         context.map().on('move.intro drawn.intro', function() {
61247             var node = selectMenuItem('split').node();
61248             if (!wasChanged && !node) { return continueTo(rightClickIntersection); }
61249
61250             revealEditMenu(menuCoords, t('intro.lines.split_intersection',
61251                 { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') }),
61252                 { duration: 0 }
61253             );
61254         });
61255
61256         context.history().on('change.intro', function(changed) {
61257             wasChanged = true;
61258             timeout$$1(function() {
61259                 if (context.history().undoAnnotation() === t('operations.split.annotation.line')) {
61260                     washingtonSegmentId = changed.created()[0].id;
61261                     continueTo(didSplit);
61262                 } else {
61263                     washingtonSegmentId = null;
61264                     continueTo(retrySplit);
61265                 }
61266             }, 300);  // after any transition (e.g. if user deleted intersection)
61267         });
61268
61269         function continueTo(nextStep) {
61270             context.map().on('move.intro drawn.intro', null);
61271             context.history().on('change.intro', null);
61272             nextStep();
61273         }
61274     }
61275
61276
61277     function retrySplit() {
61278         context.enter(modeBrowse(context));
61279         context.map().zoom(18).centerEase(eleventhAvenueEnd, 500);
61280         var advance = function() { continueTo(rightClickIntersection); };
61281
61282         var padding = 60 * Math.pow(2, context.map().zoom() - 18);
61283         var box = pad$1(eleventhAvenueEnd, padding, context);
61284         reveal(box, t('intro.lines.retry_split'),
61285             { buttonText: t('intro.ok'), buttonCallback: advance }
61286         );
61287
61288         context.map().on('move.intro drawn.intro', function() {
61289             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
61290             var box = pad$1(eleventhAvenueEnd, padding, context);
61291             reveal(box, t('intro.lines.retry_split'),
61292                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
61293             );
61294         });
61295
61296         function continueTo(nextStep) {
61297             context.map().on('move.intro drawn.intro', null);
61298             nextStep();
61299         }
61300     }
61301
61302
61303     function didSplit() {
61304         if (!washingtonSegmentId ||
61305             !context.hasEntity(washingtonSegmentId) ||
61306             !context.hasEntity(washingtonStreetId) ||
61307             !context.hasEntity(twelfthAvenueId) ||
61308             !context.hasEntity(eleventhAvenueEndId)) {
61309             return continueTo(rightClickIntersection);
61310         }
61311
61312         var ids = context.selectedIDs();
61313         var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
61314         var street = t('intro.graph.name.washington-street');
61315
61316         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61317         var box = pad$1(twelfthAvenue, padding, context);
61318         box.width = box.width / 2;
61319         reveal(box, t(string, { street1: street, street2: street }),
61320             { duration: 500 }
61321         );
61322
61323         timeout$$1(function() {
61324             context.map().zoom(18).centerEase(twelfthAvenue, 500);
61325
61326             context.map().on('move.intro drawn.intro', function() {
61327                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61328                 var box = pad$1(twelfthAvenue, padding, context);
61329                 box.width = box.width / 2;
61330                 reveal(box, t(string, { street1: street, street2: street }),
61331                     { duration: 0 }
61332                 );
61333             });
61334         }, 600);  // after initial reveal and curtain cut
61335
61336         context.on('enter.intro', function() {
61337             var ids = context.selectedIDs();
61338             if (ids.length === 1 && ids[0] === washingtonSegmentId) {
61339                 continueTo(multiSelect);
61340             }
61341         });
61342
61343         context.history().on('change.intro', function() {
61344             if (!washingtonSegmentId ||
61345                 !context.hasEntity(washingtonSegmentId) ||
61346                 !context.hasEntity(washingtonStreetId) ||
61347                 !context.hasEntity(twelfthAvenueId) ||
61348                 !context.hasEntity(eleventhAvenueEndId)) {
61349                 return continueTo(rightClickIntersection);
61350             }
61351         });
61352
61353         function continueTo(nextStep) {
61354             context.map().on('move.intro drawn.intro', null);
61355             context.on('enter.intro', null);
61356             context.history().on('change.intro', null);
61357             nextStep();
61358         }
61359     }
61360
61361
61362     function multiSelect() {
61363         if (!washingtonSegmentId ||
61364             !context.hasEntity(washingtonSegmentId) ||
61365             !context.hasEntity(washingtonStreetId) ||
61366             !context.hasEntity(twelfthAvenueId) ||
61367             !context.hasEntity(eleventhAvenueEndId)) {
61368             return continueTo(rightClickIntersection);
61369         }
61370
61371         var ids = context.selectedIDs();
61372         var hasWashington = ids.indexOf(washingtonSegmentId) !== -1;
61373         var hasTwelfth = ids.indexOf(twelfthAvenueId) !== -1;
61374
61375         if (hasWashington && hasTwelfth) {
61376             return continueTo(multiRightClick);
61377         } else if (!hasWashington && !hasTwelfth) {
61378             return continueTo(didSplit);
61379         }
61380
61381         context.map().zoom(18).centerEase(twelfthAvenue, 500);
61382
61383         timeout$$1(function() {
61384             var selected, other, padding, box;
61385             if (hasWashington) {
61386                 selected = t('intro.graph.name.washington-street');
61387                 other = t('intro.graph.name.12th-avenue');
61388                 padding = 60 * Math.pow(2, context.map().zoom() - 18);
61389                 box = pad$1(twelfthAvenueEnd, padding, context);
61390                 box.width *= 3;
61391             } else {
61392                 selected = t('intro.graph.name.12th-avenue');
61393                 other = t('intro.graph.name.washington-street');
61394                 padding = 200 * Math.pow(2, context.map().zoom() - 18);
61395                 box = pad$1(twelfthAvenue, padding, context);
61396                 box.width /= 2;
61397             }
61398
61399             reveal(box,
61400                 t('intro.lines.multi_select', { selected: selected, other1: other, other2: other })
61401             );
61402
61403             context.map().on('move.intro drawn.intro', function() {
61404                 if (hasWashington) {
61405                     selected = t('intro.graph.name.washington-street');
61406                     other = t('intro.graph.name.12th-avenue');
61407                     padding = 60 * Math.pow(2, context.map().zoom() - 18);
61408                     box = pad$1(twelfthAvenueEnd, padding, context);
61409                     box.width *= 3;
61410                 } else {
61411                     selected = t('intro.graph.name.12th-avenue');
61412                     other = t('intro.graph.name.washington-street');
61413                     padding = 200 * Math.pow(2, context.map().zoom() - 18);
61414                     box = pad$1(twelfthAvenue, padding, context);
61415                     box.width /= 2;
61416                 }
61417
61418                 reveal(box,
61419                     t('intro.lines.multi_select', { selected: selected, other1: other, other2: other }),
61420                     { duration: 0 }
61421                 );
61422             });
61423
61424             context.on('enter.intro', function() {
61425                 continueTo(multiSelect);
61426             });
61427
61428             context.history().on('change.intro', function() {
61429                 if (!washingtonSegmentId ||
61430                     !context.hasEntity(washingtonSegmentId) ||
61431                     !context.hasEntity(washingtonStreetId) ||
61432                     !context.hasEntity(twelfthAvenueId) ||
61433                     !context.hasEntity(eleventhAvenueEndId)) {
61434                     return continueTo(rightClickIntersection);
61435                 }
61436             });
61437         }, 600);
61438
61439         function continueTo(nextStep) {
61440             context.map().on('move.intro drawn.intro', null);
61441             context.on('enter.intro', null);
61442             context.history().on('change.intro', null);
61443             nextStep();
61444         }
61445     }
61446
61447
61448     function multiRightClick() {
61449         if (!washingtonSegmentId ||
61450             !context.hasEntity(washingtonSegmentId) ||
61451             !context.hasEntity(washingtonStreetId) ||
61452             !context.hasEntity(twelfthAvenueId) ||
61453             !context.hasEntity(eleventhAvenueEndId)) {
61454             return continueTo(rightClickIntersection);
61455         }
61456
61457         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61458         var box = pad$1(twelfthAvenue, padding, context);
61459         reveal(box, t('intro.lines.multi_rightclick'));
61460
61461         context.map().on('move.intro drawn.intro', function() {
61462             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61463             var box = pad$1(twelfthAvenue, padding, context);
61464             reveal(box, t('intro.lines.multi_rightclick'), { duration: 0 });
61465         });
61466
61467         select(window).on('click.intro contextmenu.intro', function() {
61468             timeout$$1(function() {
61469                 var ids = context.selectedIDs();
61470                 if (ids.length === 2 &&
61471                     ids.indexOf(twelfthAvenueId) !== -1 &&
61472                     ids.indexOf(washingtonSegmentId) !== -1) {
61473                         var node = selectMenuItem('delete').node();
61474                         if (!node) return;
61475                         continueTo(multiDelete);
61476                 } else if (ids.length === 1 &&
61477                     ids.indexOf(washingtonSegmentId) !== -1) {
61478                     return continueTo(multiSelect);
61479                 } else {
61480                     return continueTo(didSplit);
61481                 }
61482             }, 300);  // after edit menu visible
61483         }, true);
61484
61485         context.history().on('change.intro', function() {
61486             if (!washingtonSegmentId ||
61487                 !context.hasEntity(washingtonSegmentId) ||
61488                 !context.hasEntity(washingtonStreetId) ||
61489                 !context.hasEntity(twelfthAvenueId) ||
61490                 !context.hasEntity(eleventhAvenueEndId)) {
61491                 return continueTo(rightClickIntersection);
61492             }
61493         });
61494
61495         function continueTo(nextStep) {
61496             context.map().on('move.intro drawn.intro', null);
61497             select(window).on('click.intro contextmenu.intro', null, true);
61498             context.history().on('change.intro', null);
61499             nextStep();
61500         }
61501     }
61502
61503
61504     function multiDelete() {
61505         if (!washingtonSegmentId ||
61506             !context.hasEntity(washingtonSegmentId) ||
61507             !context.hasEntity(washingtonStreetId) ||
61508             !context.hasEntity(twelfthAvenueId) ||
61509             !context.hasEntity(eleventhAvenueEndId)) {
61510             return continueTo(rightClickIntersection);
61511         }
61512
61513         var node = selectMenuItem('delete').node();
61514         if (!node) return continueTo(multiRightClick);
61515
61516         var menuCoords = context.map().mouseCoordinates();
61517         revealEditMenu(menuCoords,
61518             t('intro.lines.multi_delete', { button: icon('#operation-delete', 'pre-text') })
61519         );
61520
61521         context.map().on('move.intro drawn.intro', function() {
61522             revealEditMenu(menuCoords,
61523                 t('intro.lines.multi_delete', { button: icon('#operation-delete', 'pre-text') }),
61524                 { duration: 0 }
61525             );
61526         });
61527
61528         context.on('exit.intro', function() {
61529             if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) {
61530                 return continueTo(multiSelect);  // left select mode but roads still exist
61531             }
61532         });
61533
61534         context.history().on('change.intro', function() {
61535             if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) {
61536                 continueTo(retryDelete);         // changed something but roads still exist
61537             } else {
61538                 continueTo(play);
61539             }
61540         });
61541
61542         function continueTo(nextStep) {
61543             context.map().on('move.intro drawn.intro', null);
61544             context.on('exit.intro', null);
61545             context.history().on('change.intro', null);
61546             nextStep();
61547         }
61548     }
61549
61550
61551     function retryDelete() {
61552         context.enter(modeBrowse(context));
61553
61554         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61555         var box = pad$1(twelfthAvenue, padding, context);
61556         reveal(box, t('intro.lines.retry_delete'), {
61557             buttonText: t('intro.ok'),
61558             buttonCallback: function() { continueTo(multiSelect); }
61559         });
61560
61561         function continueTo(nextStep) {
61562             nextStep();
61563         }
61564     }
61565
61566
61567     function play() {
61568         dispatch$$1.call('done');
61569         reveal('#id-container',
61570             t('intro.lines.play', { next: t('intro.buildings.title') }), {
61571                 tooltipBox: '.intro-nav-wrap .chapter-building',
61572                 buttonText: t('intro.ok'),
61573                 buttonCallback: function() { reveal('#id-container'); }
61574             }
61575         );
61576    }
61577
61578
61579     chapter.enter = function() {
61580         addLine();
61581     };
61582
61583
61584     chapter.exit = function() {
61585         timeouts.forEach(window.clearTimeout);
61586         select(window).on('mousedown.intro', null, true);
61587         context.on('enter.intro exit.intro', null);
61588         context.map().on('move.intro drawn.intro', null);
61589         context.history().on('change.intro', null);
61590         select('.inspector-wrap').on('wheel.intro', null);
61591         select('.preset-list-button').on('click.intro', null);
61592     };
61593
61594
61595     chapter.restart = function() {
61596         chapter.exit();
61597         chapter.enter();
61598     };
61599
61600
61601     return utilRebind(chapter, dispatch$$1, 'on');
61602 }
61603
61604 function uiIntroBuilding(context, reveal) {
61605     var dispatch$$1 = dispatch('done'),
61606         house = [-85.62815, 41.95638],
61607         tank = [-85.62732, 41.95347],
61608         buildingCatetory = context.presets().item('category-building'),
61609         housePreset = context.presets().item('building/house'),
61610         tankPreset = context.presets().item('man_made/storage_tank'),
61611         timeouts = [],
61612         houseId = null,
61613         tankId = null;
61614
61615
61616     var chapter = {
61617         title: 'intro.buildings.title'
61618     };
61619
61620
61621     function timeout$$1(f, t$$1) {
61622         timeouts.push(window.setTimeout(f, t$$1));
61623     }
61624
61625
61626     function eventCancel() {
61627         event.stopPropagation();
61628         event.preventDefault();
61629     }
61630
61631
61632     function revealHouse(center, text$$1, options) {
61633         var padding = 160 * Math.pow(2, context.map().zoom() - 20);
61634         var box = pad$1(center, padding, context);
61635         reveal(box, text$$1, options);
61636     }
61637
61638
61639     function revealTank(center, text$$1, options) {
61640         var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
61641         var box = pad$1(center, padding, context);
61642         reveal(box, text$$1, options);
61643     }
61644
61645
61646     function revealEditMenu(loc, text$$1, options) {
61647         var rect = context.surfaceRect();
61648         var point = context.curtainProjection(loc);
61649         var pad$$1 = 40;
61650         var width = 250 + (2 * pad$$1);
61651         var height = 350;
61652         var startX = rect.left + point[0];
61653         var left = (textDirection === 'rtl') ? (startX - width + pad$$1) : (startX - pad$$1);
61654         var box = {
61655             left: left,
61656             top: point[1] + rect.top - 60,
61657             width: width,
61658             height: height
61659         };
61660         reveal(box, text$$1, options);
61661     }
61662
61663
61664     function addHouse() {
61665         context.enter(modeBrowse(context));
61666         context.history().reset('initial');
61667         houseId = null;
61668
61669         var msec = transitionTime(house, context.map().center());
61670         if (msec) { reveal(null, null, { duration: 0 }); }
61671         context.map().zoom(19).centerEase(house, msec);
61672
61673         timeout$$1(function() {
61674             var tooltip = reveal('button.add-area',
61675                 t('intro.buildings.add_building', { button: icon('#icon-area', 'pre-text') }));
61676
61677             tooltip.selectAll('.tooltip-inner')
61678                 .insert('svg', 'span')
61679                 .attr('class', 'tooltip-illustration')
61680                 .append('use')
61681                 .attr('xlink:href', '#building-images');
61682
61683             context.on('enter.intro', function(mode) {
61684                 if (mode.id !== 'add-area') return;
61685                 continueTo(startHouse);
61686             });
61687         }, msec + 100);
61688
61689         function continueTo(nextStep) {
61690             context.on('enter.intro', null);
61691             nextStep();
61692         }
61693     }
61694
61695
61696     function startHouse() {
61697         if (context.mode().id !== 'add-area') {
61698             return continueTo(addHouse);
61699         }
61700
61701         houseId = null;
61702         context.map().zoomEase(20, 500);
61703
61704         timeout$$1(function() {
61705             revealHouse(house, t('intro.buildings.start_building'));
61706
61707             context.map().on('move.intro drawn.intro', function() {
61708                 revealHouse(house, t('intro.buildings.start_building'), { duration: 0 });
61709             });
61710
61711             context.on('enter.intro', function(mode) {
61712                 if (mode.id !== 'draw-area') return chapter.restart();
61713                 continueTo(continueHouse);
61714             });
61715
61716         }, 550);  // after easing
61717
61718         function continueTo(nextStep) {
61719             context.map().on('move.intro drawn.intro', null);
61720             context.on('enter.intro', null);
61721             nextStep();
61722         }
61723     }
61724
61725
61726     function continueHouse() {
61727         if (context.mode().id !== 'draw-area') {
61728             return continueTo(addHouse);
61729         }
61730
61731         houseId = null;
61732
61733         revealHouse(house, t('intro.buildings.continue_building'));
61734
61735         context.map().on('move.intro drawn.intro', function() {
61736             revealHouse(house, t('intro.buildings.continue_building'), { duration: 0 });
61737         });
61738
61739         context.on('enter.intro', function(mode) {
61740             if (mode.id === 'draw-area') {
61741                 return;
61742             } else if (mode.id === 'select') {
61743                 var graph = context.graph(),
61744                     way = context.entity(context.selectedIDs()[0]),
61745                     nodes = graph.childNodes(way),
61746                     points = lodash.uniq(nodes).map(function(n) { return context.projection(n.loc); });
61747
61748                 if (isMostlySquare(points)) {
61749                     houseId = way.id;
61750                     return continueTo(chooseCategoryBuilding);
61751                 } else {
61752                     return continueTo(retryHouse);
61753                 }
61754
61755             } else {
61756                 return chapter.restart();
61757             }
61758         });
61759
61760         function continueTo(nextStep) {
61761             context.map().on('move.intro drawn.intro', null);
61762             context.on('enter.intro', null);
61763             nextStep();
61764         }
61765     }
61766
61767
61768     function retryHouse() {
61769         var onClick = function() { continueTo(addHouse); };
61770
61771         revealHouse(house, t('intro.buildings.retry_building'),
61772             { buttonText: t('intro.ok'), buttonCallback: onClick }
61773         );
61774
61775         context.map().on('move.intro drawn.intro', function() {
61776             revealHouse(house, t('intro.buildings.retry_building'),
61777                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
61778             );
61779         });
61780
61781         function continueTo(nextStep) {
61782             context.map().on('move.intro drawn.intro', null);
61783             nextStep();
61784         }
61785     }
61786
61787
61788     function chooseCategoryBuilding() {
61789         if (!houseId || !context.hasEntity(houseId)) {
61790             return addHouse();
61791         }
61792         var ids = context.selectedIDs();
61793         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
61794             context.enter(modeSelect(context, [houseId]));
61795         }
61796
61797         // disallow scrolling
61798         select('.inspector-wrap').on('wheel.intro', eventCancel);
61799
61800         timeout$$1(function() {
61801             // reset pane, in case user somehow happened to change it..
61802             select('.inspector-wrap .panewrap').style('right', '-100%');
61803
61804             var button = select('.preset-category-building .preset-list-button');
61805
61806             reveal(button.node(),
61807                 t('intro.buildings.choose_category_building', { category: buildingCatetory.name() })
61808             );
61809
61810             button.on('click.intro', function() {
61811                 button.on('click.intro', null);
61812                 continueTo(choosePresetHouse);
61813             });
61814
61815         }, 400);  // after preset list pane visible..
61816
61817
61818         context.on('enter.intro', function(mode) {
61819             if (!houseId || !context.hasEntity(houseId)) {
61820                 return continueTo(addHouse);
61821             }
61822             var ids = context.selectedIDs();
61823             if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) {
61824                 return continueTo(chooseCategoryBuilding);
61825             }
61826         });
61827
61828         function continueTo(nextStep) {
61829             select('.inspector-wrap').on('wheel.intro', null);
61830             select('.preset-list-button').on('click.intro', null);
61831             context.on('enter.intro', null);
61832             nextStep();
61833         }
61834     }
61835
61836
61837     function choosePresetHouse() {
61838         if (!houseId || !context.hasEntity(houseId)) {
61839             return addHouse();
61840         }
61841         var ids = context.selectedIDs();
61842         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
61843             context.enter(modeSelect(context, [houseId]));
61844         }
61845
61846         // disallow scrolling
61847         select('.inspector-wrap').on('wheel.intro', eventCancel);
61848
61849         timeout$$1(function() {
61850             // reset pane, in case user somehow happened to change it..
61851             select('.inspector-wrap .panewrap').style('right', '-100%');
61852
61853             var button = select('.preset-building-house .preset-list-button');
61854
61855             reveal(button.node(),
61856                 t('intro.buildings.choose_preset_house', { preset: housePreset.name() }),
61857                 { duration: 300 }
61858             );
61859
61860             button.on('click.intro', function() {
61861                 button.on('click.intro', null);
61862                 continueTo(closeEditorHouse);
61863             });
61864
61865
61866         }, 400);  // after preset list pane visible..
61867
61868         context.on('enter.intro', function(mode) {
61869             if (!houseId || !context.hasEntity(houseId)) {
61870                 return continueTo(addHouse);
61871             }
61872             var ids = context.selectedIDs();
61873             if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) {
61874                 return continueTo(chooseCategoryBuilding);
61875             }
61876         });
61877
61878         function continueTo(nextStep) {
61879             select('.inspector-wrap').on('wheel.intro', null);
61880             select('.preset-list-button').on('click.intro', null);
61881             context.on('enter.intro', null);
61882             nextStep();
61883         }
61884     }
61885
61886
61887     function closeEditorHouse() {
61888         if (!houseId || !context.hasEntity(houseId)) {
61889             return addHouse();
61890         }
61891         var ids = context.selectedIDs();
61892         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
61893             context.enter(modeSelect(context, [houseId]));
61894         }
61895
61896         context.history().checkpoint('hasHouse');
61897
61898         context.on('exit.intro', function() {
61899             continueTo(rightClickHouse);
61900         });
61901
61902         timeout$$1(function() {
61903             reveal('.entity-editor-pane',
61904                 t('intro.buildings.close', { button: icon('#icon-apply', 'pre-text') })
61905             );
61906         }, 500);
61907
61908         function continueTo(nextStep) {
61909             context.on('exit.intro', null);
61910             nextStep();
61911         }
61912     }
61913
61914
61915     function rightClickHouse() {
61916         if (!houseId) return chapter.restart();
61917
61918         context.enter(modeBrowse(context));
61919         context.history().reset('hasHouse');
61920         context.map().centerEase(house, 500);
61921
61922         timeout$$1(function() {
61923             if (context.map().zoom() < 20) {
61924                 context.map().zoomEase(20, 500);
61925             }
61926         }, 520);
61927
61928         context.on('enter.intro', function(mode) {
61929             if (mode.id !== 'select') return;
61930             var ids = context.selectedIDs();
61931             if (ids.length !== 1 || ids[0] !== houseId) return;
61932
61933             timeout$$1(function() {
61934                 var node = selectMenuItem('orthogonalize').node();
61935                 if (!node) return;
61936                 continueTo(clickSquare);
61937             }, 300);  // after menu visible
61938         });
61939
61940         context.map().on('move.intro drawn.intro', function() {
61941             revealHouse(house, t('intro.buildings.rightclick_building'), { duration: 0 });
61942         });
61943
61944         context.history().on('change.intro', function() {
61945             continueTo(rightClickHouse);
61946         });
61947
61948         function continueTo(nextStep) {
61949             context.on('enter.intro', null);
61950             context.map().on('move.intro drawn.intro', null);
61951             context.history().on('change.intro', null);
61952             nextStep();
61953         }
61954     }
61955
61956
61957     function clickSquare() {
61958         if (!houseId) return chapter.restart();
61959         var entity = context.hasEntity(houseId);
61960         if (!entity) return continueTo(rightClickHouse);
61961
61962         var node = selectMenuItem('orthogonalize').node();
61963         if (!node) { return continueTo(rightClickHouse); }
61964
61965         var wasChanged = false;
61966         var menuCoords = context.map().mouseCoordinates();
61967
61968         revealEditMenu(menuCoords,
61969             t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') })
61970         );
61971
61972         context.on('enter.intro', function(mode) {
61973             if (mode.id === 'browse') {
61974                 continueTo(rightClickHouse);
61975             } else if (mode.id === 'move' || mode.id === 'rotate') {
61976                 continueTo(retryClickSquare);
61977             }
61978         });
61979
61980         context.map().on('move.intro drawn.intro', function() {
61981             var node = selectMenuItem('orthogonalize').node();
61982             if (!wasChanged && !node) { return continueTo(rightClickHouse); }
61983
61984             revealEditMenu(menuCoords,
61985                 t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') }),
61986                 { duration: 0 }
61987             );
61988         });
61989
61990         context.history().on('change.intro', function() {
61991             wasChanged = true;
61992             context.history().on('change.intro', null);
61993
61994             // Something changed.  Wait for transition to complete and check undo annotation.
61995             timeout$$1(function() {
61996                 if (context.history().undoAnnotation() === t('operations.orthogonalize.annotation.area')) {
61997                     continueTo(doneSquare);
61998                 } else {
61999                     continueTo(retryClickSquare);
62000                 }
62001             }, 500);  // after transitioned actions
62002         });
62003
62004         function continueTo(nextStep) {
62005             context.on('enter.intro', null);
62006             context.map().on('move.intro drawn.intro', null);
62007             context.history().on('change.intro', null);
62008             nextStep();
62009         }
62010     }
62011
62012
62013     function retryClickSquare() {
62014         context.enter(modeBrowse(context));
62015
62016         revealHouse(house, t('intro.buildings.retry_square'), {
62017             buttonText: t('intro.ok'),
62018             buttonCallback: function() { continueTo(rightClickHouse); }
62019         });
62020
62021         function continueTo(nextStep) {
62022             nextStep();
62023         }
62024     }
62025
62026
62027     function doneSquare() {
62028         context.history().checkpoint('doneSquare');
62029
62030         revealHouse(house, t('intro.buildings.done_square'), {
62031             buttonText: t('intro.ok'),
62032             buttonCallback: function() { continueTo(addTank); }
62033         });
62034
62035         function continueTo(nextStep) {
62036             nextStep();
62037         }
62038     }
62039
62040
62041     function addTank() {
62042         context.enter(modeBrowse(context));
62043         context.history().reset('doneSquare');
62044         tankId = null;
62045
62046         var msec = transitionTime(tank, context.map().center());
62047         if (msec) { reveal(null, null, { duration: 0 }); }
62048         context.map().zoom(19.5).centerEase(tank, msec);
62049
62050         timeout$$1(function() {
62051             reveal('button.add-area',
62052                 t('intro.buildings.add_tank', { button: icon('#icon-area', 'pre-text') })
62053             );
62054
62055             context.on('enter.intro', function(mode) {
62056                 if (mode.id !== 'add-area') return;
62057                 continueTo(startTank);
62058             });
62059         }, msec + 100);
62060
62061         function continueTo(nextStep) {
62062             context.on('enter.intro', null);
62063             nextStep();
62064         }
62065     }
62066
62067
62068     function startTank() {
62069         if (context.mode().id !== 'add-area') {
62070             return continueTo(addTank);
62071         }
62072
62073         tankId = null;
62074
62075         timeout$$1(function() {
62076             revealTank(tank, t('intro.buildings.start_tank'));
62077
62078             context.map().on('move.intro drawn.intro', function() {
62079                 revealTank(tank, t('intro.buildings.start_tank'), { duration: 0 });
62080             });
62081
62082             context.on('enter.intro', function(mode) {
62083                 if (mode.id !== 'draw-area') return chapter.restart();
62084                 continueTo(continueTank);
62085             });
62086
62087         }, 550);  // after easing
62088
62089         function continueTo(nextStep) {
62090             context.map().on('move.intro drawn.intro', null);
62091             context.on('enter.intro', null);
62092             nextStep();
62093         }
62094     }
62095
62096
62097     function continueTank() {
62098         if (context.mode().id !== 'draw-area') {
62099             return continueTo(addTank);
62100         }
62101
62102         tankId = null;
62103
62104         revealTank(tank, t('intro.buildings.continue_tank'));
62105
62106         context.map().on('move.intro drawn.intro', function() {
62107             revealTank(tank, t('intro.buildings.continue_tank'), { duration: 0 });
62108         });
62109
62110         context.on('enter.intro', function(mode) {
62111             if (mode.id === 'draw-area') {
62112                 return;
62113             } else if (mode.id === 'select') {
62114                 tankId = context.selectedIDs()[0];
62115                 return continueTo(searchPresetTank);
62116             } else {
62117                 return continueTo(addTank);
62118             }
62119         });
62120
62121         function continueTo(nextStep) {
62122             context.map().on('move.intro drawn.intro', null);
62123             context.on('enter.intro', null);
62124             nextStep();
62125         }
62126     }
62127
62128
62129     function searchPresetTank() {
62130         if (!tankId || !context.hasEntity(tankId)) {
62131             return addTank();
62132         }
62133         var ids = context.selectedIDs();
62134         if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) {
62135             context.enter(modeSelect(context, [tankId]));
62136         }
62137
62138         // disallow scrolling
62139         select('.inspector-wrap').on('wheel.intro', eventCancel);
62140
62141         timeout$$1(function() {
62142             // reset pane, in case user somehow happened to change it..
62143             select('.inspector-wrap .panewrap').style('right', '-100%');
62144
62145             select('.preset-search-input')
62146                 .on('keydown.intro', null)
62147                 .on('keyup.intro', checkPresetSearch);
62148
62149             reveal('.preset-search-input',
62150                 t('intro.buildings.search_tank', { preset: tankPreset.name() })
62151             );
62152         }, 400);  // after preset list pane visible..
62153
62154         context.on('enter.intro', function(mode) {
62155             if (!tankId || !context.hasEntity(tankId)) {
62156                 return continueTo(addTank);
62157             }
62158
62159             var ids = context.selectedIDs();
62160             if (mode.id !== 'select' || !ids.length || ids[0] !== tankId) {
62161                 // keep the user's area selected..
62162                 context.enter(modeSelect(context, [tankId]));
62163
62164                 // reset pane, in case user somehow happened to change it..
62165                 select('.inspector-wrap .panewrap').style('right', '-100%');
62166                 // disallow scrolling
62167                 select('.inspector-wrap').on('wheel.intro', eventCancel);
62168
62169                 select('.preset-search-input')
62170                     .on('keydown.intro', null)
62171                     .on('keyup.intro', checkPresetSearch);
62172
62173                 reveal('.preset-search-input',
62174                     t('intro.buildings.search_tank', { preset: tankPreset.name() })
62175                 );
62176
62177                 context.history().on('change.intro', null);
62178             }
62179         });
62180
62181         function checkPresetSearch() {
62182             var first = select('.preset-list-item:first-child');
62183
62184             if (first.classed('preset-man_made-storage_tank')) {
62185                 reveal(first.select('.preset-list-button').node(),
62186                     t('intro.buildings.choose_tank', { preset: tankPreset.name() }),
62187                     { duration: 300 }
62188                 );
62189
62190                 select('.preset-search-input')
62191                     .on('keydown.intro', eventCancel, true)
62192                     .on('keyup.intro', null);
62193
62194                 context.history().on('change.intro', function() {
62195                     continueTo(closeEditorTank);
62196                 });
62197             }
62198         }
62199
62200         function continueTo(nextStep) {
62201             select('.inspector-wrap').on('wheel.intro', null);
62202             context.on('enter.intro', null);
62203             context.history().on('change.intro', null);
62204             select('.preset-search-input').on('keydown.intro keyup.intro', null);
62205             nextStep();
62206         }
62207     }
62208
62209
62210     function closeEditorTank() {
62211         if (!tankId || !context.hasEntity(tankId)) {
62212             return addTank();
62213         }
62214         var ids = context.selectedIDs();
62215         if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) {
62216             context.enter(modeSelect(context, [tankId]));
62217         }
62218
62219         context.history().checkpoint('hasTank');
62220
62221         context.on('exit.intro', function() {
62222             continueTo(rightClickTank);
62223         });
62224
62225         timeout$$1(function() {
62226             reveal('.entity-editor-pane',
62227                 t('intro.buildings.close', { button: icon('#icon-apply', 'pre-text') })
62228             );
62229         }, 500);
62230
62231         function continueTo(nextStep) {
62232             context.on('exit.intro', null);
62233             nextStep();
62234         }
62235     }
62236
62237
62238     function rightClickTank() {
62239         if (!tankId) return continueTo(addTank);
62240
62241         context.enter(modeBrowse(context));
62242         context.history().reset('hasTank');
62243         context.map().centerEase(tank, 500);
62244
62245         timeout$$1(function() {
62246             context.on('enter.intro', function(mode) {
62247                 if (mode.id !== 'select') return;
62248                 var ids = context.selectedIDs();
62249                 if (ids.length !== 1 || ids[0] !== tankId) return;
62250
62251                 timeout$$1(function() {
62252                     var node = selectMenuItem('circularize').node();
62253                     if (!node) return;
62254                     continueTo(clickCircle);
62255                 }, 300);  // after menu visible
62256             });
62257
62258             revealTank(tank, t('intro.buildings.rightclick_tank'));
62259
62260             context.map().on('move.intro drawn.intro', function() {
62261                 revealTank(tank, t('intro.buildings.rightclick_tank'), { duration: 0 });
62262             });
62263
62264             context.history().on('change.intro', function() {
62265                 continueTo(rightClickTank);
62266             });
62267
62268         }, 600);
62269
62270         function continueTo(nextStep) {
62271             context.on('enter.intro', null);
62272             context.map().on('move.intro drawn.intro', null);
62273             context.history().on('change.intro', null);
62274             nextStep();
62275         }
62276     }
62277
62278
62279     function clickCircle() {
62280         if (!tankId) return chapter.restart();
62281         var entity = context.hasEntity(tankId);
62282         if (!entity) return continueTo(rightClickTank);
62283
62284         var node = selectMenuItem('circularize').node();
62285         if (!node) { return continueTo(rightClickTank); }
62286
62287         var wasChanged = false;
62288         var menuCoords = context.map().mouseCoordinates();
62289
62290         revealEditMenu(menuCoords,
62291             t('intro.buildings.circle_tank', { button: icon('#operation-circularize', 'pre-text') })
62292         );
62293
62294         context.on('enter.intro', function(mode) {
62295             if (mode.id === 'browse') {
62296                 continueTo(rightClickTank);
62297             } else if (mode.id === 'move' || mode.id === 'rotate') {
62298                 continueTo(retryClickCircle);
62299             }
62300         });
62301
62302         context.map().on('move.intro drawn.intro', function() {
62303             var node = selectMenuItem('circularize').node();
62304             if (!wasChanged && !node) { return continueTo(rightClickTank); }
62305
62306             revealEditMenu(menuCoords,
62307                 t('intro.buildings.circle_tank', { button: icon('#operation-circularize', 'pre-text') }),
62308                 { duration: 0 }
62309             );
62310         });
62311
62312         context.history().on('change.intro', function() {
62313             wasChanged = true;
62314             context.history().on('change.intro', null);
62315
62316             // Something changed.  Wait for transition to complete and check undo annotation.
62317             timeout$$1(function() {
62318                 if (context.history().undoAnnotation() === t('operations.circularize.annotation.area')) {
62319                     continueTo(play);
62320                 } else {
62321                     continueTo(retryClickCircle);
62322                 }
62323             }, 500);  // after transitioned actions
62324         });
62325
62326         function continueTo(nextStep) {
62327             context.on('enter.intro', null);
62328             context.map().on('move.intro drawn.intro', null);
62329             context.history().on('change.intro', null);
62330             nextStep();
62331         }
62332     }
62333
62334
62335     function retryClickCircle() {
62336         context.enter(modeBrowse(context));
62337
62338         revealTank(tank, t('intro.buildings.retry_circle'), {
62339             buttonText: t('intro.ok'),
62340             buttonCallback: function() { continueTo(rightClickTank); }
62341         });
62342
62343         function continueTo(nextStep) {
62344             nextStep();
62345         }
62346     }
62347
62348
62349     function play() {
62350         dispatch$$1.call('done');
62351         reveal('#id-container',
62352             t('intro.buildings.play', { next: t('intro.startediting.title') }), {
62353                 tooltipBox: '.intro-nav-wrap .chapter-startEditing',
62354                 buttonText: t('intro.ok'),
62355                 buttonCallback: function() { reveal('#id-container'); }
62356             }
62357         );
62358     }
62359
62360
62361     chapter.enter = function() {
62362         addHouse();
62363     };
62364
62365
62366     chapter.exit = function() {
62367         timeouts.forEach(window.clearTimeout);
62368         context.on('enter.intro exit.intro', null);
62369         context.map().on('move.intro drawn.intro', null);
62370         context.history().on('change.intro', null);
62371         select('.inspector-wrap').on('wheel.intro', null);
62372         select('.preset-search-input').on('keydown.intro keyup.intro', null);
62373         select('.more-fields .combobox-input').on('click.intro', null);
62374     };
62375
62376
62377     chapter.restart = function() {
62378         chapter.exit();
62379         chapter.enter();
62380     };
62381
62382
62383     return utilRebind(chapter, dispatch$$1, 'on');
62384 }
62385
62386 function uiIntroStartEditing(context, reveal) {
62387     var dispatch$$1 = dispatch('done', 'startEditing'),
62388         modalSelection = select(null);
62389
62390
62391     var chapter = {
62392         title: 'intro.startediting.title'
62393     };
62394
62395
62396     function showHelp() {
62397         reveal('.map-control.help-control',
62398             t('intro.startediting.help', { button: icon('#icon-help', 'pre-text') }), {
62399                 buttonText: t('intro.ok'),
62400                 buttonCallback: function() { showSave(); }
62401             }
62402         );
62403     }
62404
62405     function showSave() {
62406         reveal('#bar button.save',
62407             t('intro.startediting.save'), {
62408                 buttonText: t('intro.ok'),
62409                 buttonCallback: function() { showStart(); }
62410             }
62411         );
62412     }
62413
62414     function showStart() {
62415         modalSelection = uiModal(context.container());
62416
62417         modalSelection.select('.modal')
62418             .attr('class', 'modal-splash modal col6');
62419
62420         modalSelection.selectAll('.close').remove();
62421
62422         var startbutton = modalSelection.select('.content')
62423             .attr('class', 'fillL')
62424             .append('button')
62425                 .attr('class', 'modal-section huge-modal-button')
62426                 .on('click', function() {
62427                     modalSelection.remove();
62428                 });
62429
62430             startbutton
62431                 .append('svg')
62432                 .attr('class', 'illustration')
62433                 .append('use')
62434                 .attr('xlink:href', '#logo-walkthrough');
62435
62436             startbutton
62437                 .append('h2')
62438                 .text(t('intro.startediting.start'));
62439
62440         dispatch$$1.call('startEditing');
62441     }
62442
62443
62444     chapter.enter = function() {
62445         showHelp();
62446     };
62447
62448
62449     chapter.exit = function() {
62450         modalSelection.remove();
62451     };
62452
62453
62454     return utilRebind(chapter, dispatch$$1, 'on');
62455 }
62456
62457 var chapterUi = {
62458     welcome: uiIntroWelcome,
62459     navigation: uiIntroNavigation,
62460     point: uiIntroPoint,
62461     area: uiIntroArea,
62462     line: uiIntroLine,
62463     building: uiIntroBuilding,
62464     startEditing: uiIntroStartEditing
62465 };
62466
62467 var chapterFlow = [
62468     'welcome',
62469     'navigation',
62470     'point',
62471     'area',
62472     'line',
62473     'building',
62474     'startEditing'
62475 ];
62476
62477
62478 function uiIntro(context) {
62479     var introGraph = {},
62480         currChapter;
62481
62482
62483     // create entities for intro graph and localize names
62484     for (var id in dataIntroGraph) {
62485         introGraph[id] = osmEntity$$1(localize(dataIntroGraph[id]));
62486     }
62487
62488
62489     function intro(selection$$1) {
62490         context.enter(modeBrowse(context));
62491
62492         // Save current map state
62493         var history = context.history().toJSON(),
62494             hash = window.location.hash,
62495             center = context.map().center(),
62496             zoom$$1 = context.map().zoom(),
62497             background = context.background().baseLayerSource(),
62498             overlays = context.background().overlayLayerSources(),
62499             opacity = selectAll('#map .layer-background').style('opacity'),
62500             loadedTiles = context.connection().loadedTiles(),
62501             baseEntities = context.history().graph().base().entities,
62502             countryCode = services.geocoder.countryCode;
62503
62504         // Block saving
62505         context.inIntro(true);
62506
62507         // Load semi-real data used in intro
62508         context.connection().toggle(false).reset();
62509         context.history().reset();
62510         context.history().merge(values(coreGraph$$1().load(introGraph).entities));
62511         context.history().checkpoint('initial');
62512         context.background().bing();
62513         overlays.forEach(function (d) { context.background().toggleOverlayLayer(d); });
62514
62515         // Mock geocoder
62516         services.geocoder.countryCode = function(location, callback) {
62517             callback(null, t('intro.graph.countrycode'));
62518         };
62519
62520         selectAll('#map .layer-background').style('opacity', 1);
62521
62522         var curtain = uiCurtain();
62523         selection$$1.call(curtain);
62524
62525         var chapters = chapterFlow.map(function(chapter, i) {
62526             var s = chapterUi[chapter](context, curtain.reveal)
62527                 .on('done', function() {
62528                     context.presets().init();  // clear away "recent" presets
62529
62530                     buttons.filter(function(d) {
62531                         return d.title === s.title;
62532                     }).classed('finished', true);
62533
62534                     if (i < chapterFlow.length - 1) {
62535                         var next = chapterFlow[i + 1];
62536                         select('button.chapter-' + next)
62537                             .classed('next', true);
62538                     }
62539                 });
62540             return s;
62541         });
62542
62543         chapters[chapters.length - 1].on('startEditing', function() {
62544             curtain.remove();
62545             navwrap.remove();
62546             selectAll('#map .layer-background').style('opacity', opacity);
62547             context.connection().toggle(true).reset().loadedTiles(loadedTiles);
62548             context.history().reset().merge(values(baseEntities));
62549             context.background().baseLayerSource(background);
62550             overlays.forEach(function (d) { context.background().toggleOverlayLayer(d); });
62551             if (history) context.history().fromJSON(history, false);
62552             context.map().centerZoom(center, zoom$$1);
62553             window.location.replace(hash);
62554             services.geocoder.countryCode = countryCode;
62555             context.inIntro(false);
62556         });
62557
62558         var navwrap = selection$$1
62559             .append('div')
62560             .attr('class', 'intro-nav-wrap fillD');
62561
62562         navwrap
62563             .append('svg')
62564             .attr('class', 'intro-nav-wrap-logo')
62565             .append('use')
62566             .attr('xlink:href', '#logo-walkthrough');
62567
62568         var buttonwrap = navwrap
62569             .append('div')
62570             .attr('class', 'joined')
62571             .selectAll('button.chapter');
62572
62573         var buttons = buttonwrap
62574             .data(chapters)
62575             .enter()
62576             .append('button')
62577             .attr('class', function(d, i) { return 'chapter chapter-' + chapterFlow[i]; })
62578             .on('click', enterChapter);
62579
62580         buttons
62581             .append('span')
62582             .text(function(d) { return t(d.title); });
62583
62584         buttons
62585             .append('span')
62586             .attr('class', 'status')
62587             .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'));
62588
62589         enterChapter(chapters[0]);
62590
62591
62592         function enterChapter(newChapter) {
62593             if (currChapter) { currChapter.exit(); }
62594             context.enter(modeBrowse(context));
62595
62596             currChapter = newChapter;
62597             currChapter.enter();
62598
62599             buttons
62600                 .classed('next', false)
62601                 .classed('active', function(d) {
62602                     return d.title === currChapter.title;
62603                 });
62604         }
62605     }
62606
62607
62608     return intro;
62609 }
62610
62611 function uiHelp(context) {
62612     var key = 'H';
62613
62614     var docKeys = [
62615         'help.help',
62616         'help.editing_saving',
62617         'help.roads',
62618         'help.gps',
62619         'help.imagery',
62620         'help.addresses',
62621         'help.inspector',
62622         'help.buildings',
62623         'help.relations'];
62624
62625     var docs = docKeys.map(function(key) {
62626         var text$$1 = t(key);
62627         return {
62628             title: text$$1.split('\n')[0].replace('#', '').trim(),
62629             html: marked(text$$1.split('\n').slice(1).join('\n'))
62630         };
62631     });
62632
62633
62634     function help(selection$$1) {
62635
62636         function hide() {
62637             setVisible(false);
62638         }
62639
62640
62641         function toggle() {
62642             if (event) event.preventDefault();
62643             tooltipBehavior.hide(button);
62644             setVisible(!button.classed('active'));
62645         }
62646
62647
62648         function setVisible(show) {
62649             if (show !== shown) {
62650                 button.classed('active', show);
62651                 shown = show;
62652
62653                 if (show) {
62654                     selection$$1.on('mousedown.help-inside', function() {
62655                         return event.stopPropagation();
62656                     });
62657                     pane.style('display', 'block')
62658                         .style('right', '-500px')
62659                         .transition()
62660                         .duration(200)
62661                         .style('right', '0px');
62662                 } else {
62663                     pane.style('right', '0px')
62664                         .transition()
62665                         .duration(200)
62666                         .style('right', '-500px')
62667                         .on('end', function() {
62668                             select(this).style('display', 'none');
62669                         });
62670                     selection$$1.on('mousedown.help-inside', null);
62671                 }
62672             }
62673         }
62674
62675
62676         function clickHelp(d, i) {
62677             var rtl = (textDirection === 'rtl');
62678             pane.property('scrollTop', 0);
62679             doctitle.html(d.title);
62680
62681             body.html(d.html);
62682             body.selectAll('a')
62683                 .attr('target', '_blank');
62684             menuItems.classed('selected', function(m) {
62685                 return m.title === d.title;
62686             });
62687
62688             nav.html('');
62689             if (rtl) {
62690                 nav.call(drawNext).call(drawPrevious);
62691             } else {
62692                 nav.call(drawPrevious).call(drawNext);
62693             }
62694
62695
62696             function drawNext(selection$$1) {
62697                 if (i < docs.length - 1) {
62698                     var nextLink = selection$$1
62699                         .append('a')
62700                         .attr('class', 'next')
62701                         .on('click', function() {
62702                             clickHelp(docs[i + 1], i + 1);
62703                         });
62704
62705                     nextLink
62706                         .append('span')
62707                         .text(docs[i + 1].title)
62708                         .call(svgIcon((rtl ? '#icon-backward' : '#icon-forward'), 'inline'));
62709                 }
62710             }
62711
62712
62713             function drawPrevious(selection$$1) {
62714                 if (i > 0) {
62715                     var prevLink = selection$$1
62716                         .append('a')
62717                         .attr('class', 'previous')
62718                         .on('click', function() {
62719                             clickHelp(docs[i - 1], i - 1);
62720                         });
62721
62722                     prevLink
62723                         .call(svgIcon((rtl ? '#icon-forward' : '#icon-backward'), 'inline'))
62724                         .append('span')
62725                         .text(docs[i - 1].title);
62726                 }
62727             }
62728         }
62729
62730
62731         function clickWalkthrough() {
62732             if (context.inIntro()) return;
62733             context.container().call(uiIntro(context));
62734             setVisible(false);
62735         }
62736
62737
62738         var pane = selection$$1.append('div')
62739                 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
62740             tooltipBehavior = tooltip()
62741                 .placement((textDirection === 'rtl') ? 'right' : 'left')
62742                 .html(true)
62743                 .title(uiTooltipHtml(t('help.title'), key)),
62744             button = selection$$1.append('button')
62745                 .attr('tabindex', -1)
62746                 .on('click', toggle)
62747                 .call(svgIcon('#icon-help', 'light'))
62748                 .call(tooltipBehavior),
62749             shown = false;
62750
62751
62752         var toc = pane.append('ul')
62753             .attr('class', 'toc');
62754
62755         var menuItems = toc.selectAll('li')
62756             .data(docs)
62757             .enter()
62758             .append('li')
62759             .append('a')
62760             .html(function(d) { return d.title; })
62761             .on('click', clickHelp);
62762
62763         var walkthrough = toc
62764             .append('li')
62765             .attr('class', 'walkthrough')
62766             .append('a')
62767             .on('click', clickWalkthrough);
62768
62769         walkthrough
62770             .append('svg')
62771             .attr('class', 'logo logo-walkthrough')
62772             .append('use')
62773             .attr('xlink:href', '#logo-walkthrough');
62774
62775         walkthrough
62776             .append('div')
62777             .text(t('splash.walkthrough'));
62778
62779
62780         var content = pane.append('div')
62781             .attr('class', 'left-content');
62782
62783         var doctitle = content.append('h2')
62784             .text(t('help.title'));
62785
62786         var body = content.append('div')
62787             .attr('class', 'body');
62788
62789         var nav = content.append('div')
62790             .attr('class', 'nav');
62791
62792         clickHelp(docs[0], 0);
62793
62794         var keybinding = d3keybinding('help')
62795             .on(key, toggle)
62796             .on('B', hide)
62797             .on('F', hide);
62798
62799         select(document)
62800             .call(keybinding);
62801
62802         context.surface().on('mousedown.help-outside', hide);
62803         context.container().on('mousedown.help-outside', hide);
62804     }
62805
62806     return help;
62807 }
62808
62809 function uiInfo(context) {
62810     var key = uiCmd('⌘I'),
62811         isImperial = (utilDetect().locale.toLowerCase() === 'en-us'),
62812         isHidden = true;
62813
62814
62815     function info(selection$$1) {
62816
62817         function radiansToMeters(r) {
62818             // using WGS84 authalic radius (6371007.1809 m)
62819             return r * 6371007.1809;
62820         }
62821
62822         function steradiansToSqmeters(r) {
62823             // http://gis.stackexchange.com/a/124857/40446
62824             return r / (4 * Math.PI) * 510065621724000;
62825         }
62826
62827
62828         function toLineString(feature) {
62829             if (feature.type === 'LineString') return feature;
62830
62831             var result = { type: 'LineString', coordinates: [] };
62832             if (feature.type === 'Polygon') {
62833                 result.coordinates = feature.coordinates[0];
62834             } else if (feature.type === 'MultiPolygon') {
62835                 result.coordinates = feature.coordinates[0][0];
62836             }
62837
62838             return result;
62839         }
62840
62841
62842         function displayLength(m) {
62843             var d = m * (isImperial ? 3.28084 : 1),
62844                 p, unit;
62845
62846             if (isImperial) {
62847                 if (d >= 5280) {
62848                     d /= 5280;
62849                     unit = 'mi';
62850                 } else {
62851                     unit = 'ft';
62852                 }
62853             } else {
62854                 if (d >= 1000) {
62855                     d /= 1000;
62856                     unit = 'km';
62857                 } else {
62858                     unit = 'm';
62859                 }
62860             }
62861
62862             // drop unnecessary precision
62863             p = d > 1000 ? 0 : d > 100 ? 1 : 2;
62864
62865             return String(d.toFixed(p)) + ' ' + unit;
62866         }
62867
62868
62869         function displayArea(m2) {
62870             var d = m2 * (isImperial ? 10.7639111056 : 1),
62871                 d1, d2, p1, p2, unit1, unit2;
62872
62873             if (isImperial) {
62874                 if (d >= 6969600) {     // > 0.25mi² show mi²
62875                     d1 = d / 27878400;
62876                     unit1 = 'mi²';
62877                 } else {
62878                     d1 = d;
62879                     unit1 = 'ft²';
62880                 }
62881
62882                 if (d > 4356 && d < 43560000) {   // 0.1 - 1000 acres
62883                     d2 = d / 43560;
62884                     unit2 = 'ac';
62885                 }
62886
62887             } else {
62888                 if (d >= 250000) {    // > 0.25km² show km²
62889                     d1 = d / 1000000;
62890                     unit1 = 'km²';
62891                 } else {
62892                     d1 = d;
62893                     unit1 = 'm²';
62894                 }
62895
62896                 if (d > 1000 && d < 10000000) {   // 0.1 - 1000 hectares
62897                     d2 = d / 10000;
62898                     unit2 = 'ha';
62899                 }
62900             }
62901
62902             // drop unnecessary precision
62903             p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
62904             p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
62905
62906             return String(d1.toFixed(p1)) + ' ' + unit1 +
62907                 (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
62908         }
62909
62910
62911         function redraw() {
62912             if (isHidden) return;
62913
62914             var resolver = context.graph(),
62915                 selected = lodash.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
62916                 singular = selected.length === 1 ? selected[0] : null,
62917                 extent$$1 = geoExtent$$1(),
62918                 entity;
62919
62920             wrap.html('');
62921             wrap.append('h4')
62922                 .attr('class', 'infobox-heading fillD')
62923                 .text(singular || t('infobox.selected', { n: selected.length }));
62924
62925             if (!selected.length) return;
62926
62927             var center;
62928             for (var i = 0; i < selected.length; i++) {
62929                 entity = context.entity(selected[i]);
62930                 extent$$1._extend(entity.extent(resolver));
62931             }
62932             center = extent$$1.center();
62933
62934
62935             var list = wrap.append('ul');
62936
62937             // multiple features, just display extent center..
62938             if (!singular) {
62939                 list.append('li')
62940                     .text(t('infobox.center') + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
62941                 return;
62942             }
62943
62944             // single feature, display details..
62945             if (!entity) return;
62946             var geometry = entity.geometry(resolver);
62947
62948             if (geometry === 'line' || geometry === 'area') {
62949                 var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
62950                     feature = entity.asGeoJSON(resolver),
62951                     length = radiansToMeters(d3GeoLength(toLineString(feature))),
62952                     lengthLabel = t('infobox.' + (closed ? 'perimeter' : 'length')),
62953                     centroid = d3GeoCentroid(feature);
62954
62955                 list.append('li')
62956                     .text(t('infobox.geometry') + ': ' +
62957                         (closed ? t('infobox.closed') + ' ' : '') + t('geometry.' + geometry) );
62958
62959                 if (closed) {
62960                     var area$$1 = steradiansToSqmeters(entity.area(resolver));
62961                     list.append('li')
62962                         .text(t('infobox.area') + ': ' + displayArea(area$$1));
62963                 }
62964
62965                 list.append('li')
62966                     .text(lengthLabel + ': ' + displayLength(length));
62967
62968                 list.append('li')
62969                     .text(t('infobox.centroid') + ': ' + centroid[0].toFixed(5) + ', ' + centroid[1].toFixed(5));
62970
62971
62972                 var toggle  = isImperial ? 'imperial' : 'metric';
62973                 wrap.append('a')
62974                     .text(t('infobox.' + toggle))
62975                     .attr('href', '#')
62976                     .attr('class', 'button')
62977                     .on('click', function() {
62978                         event.preventDefault();
62979                         isImperial = !isImperial;
62980                         redraw();
62981                     });
62982
62983             } else {
62984                 var centerLabel = t('infobox.' + (entity.type === 'node' ? 'location' : 'center'));
62985
62986                 list.append('li')
62987                     .text(t('infobox.geometry') + ': ' + t('geometry.' + geometry));
62988
62989                 list.append('li')
62990                     .text(centerLabel + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
62991             }
62992         }
62993
62994
62995         function toggle() {
62996             if (event) {
62997                 event.preventDefault();
62998             }
62999
63000             isHidden = !isHidden;
63001
63002             if (isHidden) {
63003                 wrap
63004                     .style('display', 'block')
63005                     .style('opacity', 1)
63006                     .transition()
63007                     .duration(200)
63008                     .style('opacity', 0)
63009                     .on('end', function() {
63010                         select(this).style('display', 'none');
63011                     });
63012             } else {
63013                 wrap
63014                     .style('display', 'block')
63015                     .style('opacity', 0)
63016                     .transition()
63017                     .duration(200)
63018                     .style('opacity', 1)
63019                     .on('end', function() {
63020                         redraw();
63021                     });
63022             }
63023         }
63024
63025
63026         var wrap = selection$$1.selectAll('.infobox')
63027             .data([0]);
63028
63029         wrap = wrap.enter()
63030             .append('div')
63031             .attr('class', 'infobox fillD2')
63032             .style('display', (isHidden ? 'none' : 'block'))
63033             .merge(wrap);
63034
63035         context.map()
63036             .on('drawn.info', redraw);
63037
63038         redraw();
63039
63040         var keybinding = d3keybinding('info')
63041             .on(key, toggle);
63042
63043         select(document)
63044             .call(keybinding);
63045     }
63046
63047     return info;
63048 }
63049
63050 function uiMapData(context) {
63051     var key = 'F',
63052         features = context.features().keys(),
63053         layers = context.layers(),
63054         fills = ['wireframe', 'partial', 'full'],
63055         fillDefault = context.storage('area-fill') || 'partial',
63056         fillSelected = fillDefault;
63057
63058
63059     function map_data(selection$$1) {
63060
63061         function showsFeature(d) {
63062             return context.features().enabled(d);
63063         }
63064
63065
63066         function autoHiddenFeature(d) {
63067             return context.features().autoHidden(d);
63068         }
63069
63070
63071         function clickFeature(d) {
63072             context.features().toggle(d);
63073             update();
63074         }
63075
63076
63077         function showsFill(d) {
63078             return fillSelected === d;
63079         }
63080
63081
63082         function setFill(d) {
63083             lodash.each(fills, function(opt) {
63084                 context.surface().classed('fill-' + opt, Boolean(opt === d));
63085             });
63086
63087             fillSelected = d;
63088             if (d !== 'wireframe') {
63089                 fillDefault = d;
63090                 context.storage('area-fill', d);
63091             }
63092             update();
63093         }
63094
63095
63096         function showsLayer(which) {
63097             var layer = layers.layer(which);
63098             if (layer) {
63099                 return layer.enabled();
63100             }
63101             return false;
63102         }
63103
63104
63105         function setLayer(which, enabled) {
63106             var layer = layers.layer(which);
63107             if (layer) {
63108                 layer.enabled(enabled);
63109                 update();
63110             }
63111         }
63112
63113
63114         function toggleLayer(which) {
63115             setLayer(which, !showsLayer(which));
63116         }
63117
63118
63119         function clickGpx() {
63120             toggleLayer('gpx');
63121         }
63122
63123
63124         function clickMapillaryImages() {
63125             toggleLayer('mapillary-images');
63126             if (!showsLayer('mapillary-images')) {
63127                 setLayer('mapillary-signs', false);
63128             }
63129         }
63130
63131
63132         function clickMapillarySigns() {
63133             toggleLayer('mapillary-signs');
63134         }
63135
63136
63137         function drawMapillaryItems(selection$$1) {
63138             var mapillaryImages = layers.layer('mapillary-images'),
63139                 mapillarySigns = layers.layer('mapillary-signs'),
63140                 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
63141                 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
63142                 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
63143                 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
63144
63145             var mapillaryList = selection$$1
63146                 .selectAll('.layer-list-mapillary')
63147                 .data([0]);
63148
63149             mapillaryList = mapillaryList.enter()
63150                 .append('ul')
63151                 .attr('class', 'layer-list layer-list-mapillary')
63152                 .merge(mapillaryList);
63153
63154
63155             var mapillaryImageLayerItem = mapillaryList
63156                 .selectAll('.list-item-mapillary-images')
63157                 .data(supportsMapillaryImages ? [0] : []);
63158
63159             mapillaryImageLayerItem.exit()
63160                 .remove();
63161
63162             var enterImages = mapillaryImageLayerItem.enter()
63163                 .append('li')
63164                 .attr('class', 'list-item-mapillary-images');
63165
63166             var labelImages = enterImages
63167                 .append('label')
63168                 .call(tooltip()
63169                     .title(t('mapillary_images.tooltip'))
63170                     .placement('top'));
63171
63172             labelImages
63173                 .append('input')
63174                 .attr('type', 'checkbox')
63175                 .on('change', clickMapillaryImages);
63176
63177             labelImages
63178                 .append('span')
63179                 .text(t('mapillary_images.title'));
63180
63181
63182             var mapillarySignLayerItem = mapillaryList
63183                 .selectAll('.list-item-mapillary-signs')
63184                 .data(supportsMapillarySigns ? [0] : []);
63185
63186             mapillarySignLayerItem.exit()
63187                 .remove();
63188
63189             var enterSigns = mapillarySignLayerItem.enter()
63190                 .append('li')
63191                 .attr('class', 'list-item-mapillary-signs');
63192
63193             var labelSigns = enterSigns
63194                 .append('label')
63195                 .call(tooltip()
63196                     .title(t('mapillary_signs.tooltip'))
63197                     .placement('top'));
63198
63199             labelSigns
63200                 .append('input')
63201                 .attr('type', 'checkbox')
63202                 .on('change', clickMapillarySigns);
63203
63204             labelSigns
63205                 .append('span')
63206                 .text(t('mapillary_signs.title'));
63207
63208
63209             // Updates
63210             mapillaryImageLayerItem = mapillaryImageLayerItem
63211                 .merge(enterImages);
63212
63213             mapillaryImageLayerItem
63214                 .classed('active', showsMapillaryImages)
63215                 .selectAll('input')
63216                 .property('checked', showsMapillaryImages);
63217
63218
63219             mapillarySignLayerItem = mapillarySignLayerItem
63220                 .merge(enterSigns);
63221
63222             mapillarySignLayerItem
63223                 .classed('active', showsMapillarySigns)
63224                 .selectAll('input')
63225                 .property('disabled', !showsMapillaryImages)
63226                 .property('checked', showsMapillarySigns);
63227
63228             mapillarySignLayerItem
63229                 .selectAll('label')
63230                 .classed('deemphasize', !showsMapillaryImages);
63231         }
63232
63233
63234         function drawGpxItem(selection$$1) {
63235             var gpx = layers.layer('gpx'),
63236                 hasGpx = gpx && gpx.hasGpx(),
63237                 showsGpx = hasGpx && gpx.enabled();
63238
63239             var gpxLayerItem = selection$$1
63240                 .selectAll('.layer-list-gpx')
63241                 .data(gpx ? [0] : []);
63242
63243             // Exit
63244             gpxLayerItem.exit()
63245                 .remove();
63246
63247             // Enter
63248             var enter = gpxLayerItem.enter()
63249                 .append('ul')
63250                 .attr('class', 'layer-list layer-list-gpx')
63251                 .append('li')
63252                 .classed('list-item-gpx', true);
63253
63254             enter
63255                 .append('button')
63256                 .attr('class', 'list-item-gpx-extent')
63257                 .call(tooltip()
63258                     .title(t('gpx.zoom'))
63259                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
63260                 .on('click', function() {
63261                     event.preventDefault();
63262                     event.stopPropagation();
63263                     gpx.fitZoom();
63264                 })
63265                 .call(svgIcon('#icon-search'));
63266
63267             enter
63268                 .append('button')
63269                 .attr('class', 'list-item-gpx-browse')
63270                 .call(tooltip()
63271                     .title(t('gpx.browse'))
63272                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
63273                 .on('click', function() {
63274                     select(document.createElement('input'))
63275                         .attr('type', 'file')
63276                         .on('change', function() {
63277                             gpx.files(event.target.files);
63278                         })
63279                         .node().click();
63280                 })
63281                 .call(svgIcon('#icon-geolocate'));
63282
63283             var labelGpx = enter
63284                 .append('label')
63285                 .call(tooltip().title(t('gpx.drag_drop')).placement('top'));
63286
63287             labelGpx
63288                 .append('input')
63289                 .attr('type', 'checkbox')
63290                 .on('change', clickGpx);
63291
63292             labelGpx
63293                 .append('span')
63294                 .text(t('gpx.local_layer'));
63295
63296
63297             // Update
63298             gpxLayerItem = gpxLayerItem
63299                 .merge(enter);
63300
63301             gpxLayerItem
63302                 .classed('active', showsGpx)
63303                 .selectAll('input')
63304                 .property('disabled', !hasGpx)
63305                 .property('checked', showsGpx);
63306
63307             gpxLayerItem
63308                 .selectAll('label')
63309                 .classed('deemphasize', !hasGpx);
63310         }
63311
63312
63313         function drawList(selection$$1, data, type, name, change, active$$1) {
63314             var items = selection$$1.selectAll('li')
63315                 .data(data);
63316
63317             // Exit
63318             items.exit()
63319                 .remove();
63320
63321             // Enter
63322             var enter = items.enter()
63323                 .append('li')
63324                 .attr('class', 'layer')
63325                 .call(tooltip()
63326                     .html(true)
63327                     .title(function(d) {
63328                         var tip = t(name + '.' + d + '.tooltip'),
63329                             key = (d === 'wireframe' ? 'W' : null);
63330
63331                         if (name === 'feature' && autoHiddenFeature(d)) {
63332                             tip += '<div>' + t('map_data.autohidden') + '</div>';
63333                         }
63334                         return uiTooltipHtml(tip, key);
63335                     })
63336                     .placement('top')
63337                 );
63338
63339             var label = enter
63340                 .append('label');
63341
63342             label
63343                 .append('input')
63344                 .attr('type', type)
63345                 .attr('name', name)
63346                 .on('change', change);
63347
63348             label
63349                 .append('span')
63350                 .text(function(d) { return t(name + '.' + d + '.description'); });
63351
63352             // Update
63353             items = items
63354                 .merge(enter);
63355
63356             items
63357                 .classed('active', active$$1)
63358                 .selectAll('input')
63359                 .property('checked', active$$1)
63360                 .property('indeterminate', function(d) {
63361                     return (name === 'feature' && autoHiddenFeature(d));
63362                 });
63363         }
63364
63365
63366         function update() {
63367             dataLayerContainer.call(drawMapillaryItems);
63368             dataLayerContainer.call(drawGpxItem);
63369
63370             fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
63371             featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
63372         }
63373
63374
63375         function hidePanel() {
63376             setVisible(false);
63377         }
63378
63379
63380         function togglePanel() {
63381             if (event) event.preventDefault();
63382             tooltipBehavior.hide(button);
63383             setVisible(!button.classed('active'));
63384         }
63385
63386
63387         function toggleWireframe() {
63388             if (event) {
63389                 event.preventDefault();
63390                 event.stopPropagation();
63391             }
63392             setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
63393             context.map().pan([0,0]);  // trigger a redraw
63394         }
63395
63396
63397         function setVisible(show) {
63398             if (show !== shown) {
63399                 button.classed('active', show);
63400                 shown = show;
63401
63402                 if (show) {
63403                     update();
63404                     selection$$1.on('mousedown.map_data-inside', function() {
63405                         return event.stopPropagation();
63406                     });
63407                     content.style('display', 'block')
63408                         .style('right', '-300px')
63409                         .transition()
63410                         .duration(200)
63411                         .style('right', '0px');
63412                 } else {
63413                     content.style('display', 'block')
63414                         .style('right', '0px')
63415                         .transition()
63416                         .duration(200)
63417                         .style('right', '-300px')
63418                         .on('end', function() {
63419                             select(this).style('display', 'none');
63420                         });
63421                     selection$$1.on('mousedown.map_data-inside', null);
63422                 }
63423             }
63424         }
63425
63426
63427         var content = selection$$1
63428                 .append('div')
63429                 .attr('class', 'fillL map-overlay col3 content hide'),
63430             tooltipBehavior = tooltip()
63431                 .placement((textDirection === 'rtl') ? 'right' : 'left')
63432                 .html(true)
63433                 .title(uiTooltipHtml(t('map_data.description'), key)),
63434             button = selection$$1
63435                 .append('button')
63436                 .attr('tabindex', -1)
63437                 .on('click', togglePanel)
63438                 .call(svgIcon('#icon-data', 'light'))
63439                 .call(tooltipBehavior),
63440             shown = false;
63441
63442         content
63443             .append('h4')
63444             .text(t('map_data.title'));
63445
63446
63447         // data layers
63448         content
63449             .append('a')
63450             .text(t('map_data.data_layers'))
63451             .attr('href', '#')
63452             .classed('hide-toggle', true)
63453             .classed('expanded', true)
63454             .on('click', function() {
63455                 var exp = select(this).classed('expanded');
63456                 dataLayerContainer.style('display', exp ? 'none' : 'block');
63457                 select(this).classed('expanded', !exp);
63458                 event.preventDefault();
63459             });
63460
63461         var dataLayerContainer = content
63462             .append('div')
63463             .attr('class', 'data-data-layers')
63464             .style('display', 'block');
63465
63466
63467         // area fills
63468         content
63469             .append('a')
63470             .text(t('map_data.fill_area'))
63471             .attr('href', '#')
63472             .classed('hide-toggle', true)
63473             .classed('expanded', false)
63474             .on('click', function() {
63475                 var exp = select(this).classed('expanded');
63476                 fillContainer.style('display', exp ? 'none' : 'block');
63477                 select(this).classed('expanded', !exp);
63478                 event.preventDefault();
63479             });
63480
63481         var fillContainer = content
63482             .append('div')
63483             .attr('class', 'data-area-fills')
63484             .style('display', 'none');
63485
63486         var fillList = fillContainer
63487             .append('ul')
63488             .attr('class', 'layer-list layer-fill-list');
63489
63490
63491         // feature filters
63492         content
63493             .append('a')
63494             .text(t('map_data.map_features'))
63495             .attr('href', '#')
63496             .classed('hide-toggle', true)
63497             .classed('expanded', false)
63498             .on('click', function() {
63499                 var exp = select(this).classed('expanded');
63500                 featureContainer.style('display', exp ? 'none' : 'block');
63501                 select(this).classed('expanded', !exp);
63502                 event.preventDefault();
63503             });
63504
63505         var featureContainer = content
63506             .append('div')
63507             .attr('class', 'data-feature-filters')
63508             .style('display', 'none');
63509
63510         var featureList = featureContainer
63511             .append('ul')
63512             .attr('class', 'layer-list layer-feature-list');
63513
63514
63515         context.features()
63516             .on('change.map_data-update', update);
63517
63518         setFill(fillDefault);
63519
63520         var keybinding = d3keybinding('features')
63521             .on(key, togglePanel)
63522             .on('W', toggleWireframe)
63523             .on('B', hidePanel)
63524             .on('H', hidePanel);
63525
63526         select(document)
63527             .call(keybinding);
63528
63529         context.surface().on('mousedown.map_data-outside', hidePanel);
63530         context.container().on('mousedown.map_data-outside', hidePanel);
63531     }
63532
63533
63534     return map_data;
63535 }
63536
63537 function uiModes(context) {
63538     var modes = [
63539         modeAddPoint$$1(context),
63540         modeAddLine$$1(context),
63541         modeAddArea$$1(context)
63542     ];
63543
63544
63545     function editable() {
63546         return context.editable() && context.mode().id !== 'save';
63547     }
63548
63549
63550     return function(selection$$1) {
63551         var buttons = selection$$1.selectAll('button.add-button')
63552             .data(modes);
63553
63554         buttons = buttons.enter()
63555             .append('button')
63556             .attr('tabindex', -1)
63557             .attr('class', function(mode) { return mode.id + ' add-button col4'; })
63558             .on('click.mode-buttons', function(mode) {
63559                 if (mode.id === context.mode().id) {
63560                     context.enter(modeBrowse(context));
63561                 } else {
63562                     context.enter(mode);
63563                 }
63564             })
63565             .call(tooltip()
63566                 .placement('bottom')
63567                 .html(true)
63568                 .title(function(mode) {
63569                     return uiTooltipHtml(mode.description, mode.key);
63570                 })
63571             );
63572
63573         context.map()
63574             .on('move.modes', lodash.debounce(update, 500));
63575
63576         context
63577             .on('enter.modes', update);
63578
63579         buttons
63580             .each(function(d) {
63581                 select(this)
63582                     .call(svgIcon('#icon-' + d.button, 'pre-text'));
63583             });
63584
63585         buttons
63586             .append('span')
63587             .attr('class', 'label')
63588             .text(function(mode) { return mode.title; });
63589
63590         context
63591             .on('enter.editor', function(entered) {
63592                 selection$$1.selectAll('button.add-button')
63593                     .classed('active', function(mode) { return entered.button === mode.button; });
63594                 context.container()
63595                     .classed('mode-' + entered.id, true);
63596             });
63597
63598         context
63599             .on('exit.editor', function(exited) {
63600                 context.container()
63601                     .classed('mode-' + exited.id, false);
63602             });
63603
63604         var keybinding = d3keybinding('mode-buttons');
63605
63606         modes.forEach(function(mode) {
63607             keybinding.on(mode.key, function() {
63608                 if (editable()) {
63609                     if (mode.id === context.mode().id) {
63610                         context.enter(modeBrowse(context));
63611                     } else {
63612                         context.enter(mode);
63613                     }
63614                 }
63615             });
63616         });
63617
63618         select(document)
63619             .call(keybinding);
63620
63621
63622         function update() {
63623             selection$$1.selectAll('button.add-button')
63624                 .property('disabled', !editable());
63625         }
63626     };
63627 }
63628
63629 function uiRestore(context) {
63630
63631     return function(selection) {
63632         if (!context.history().lock() || !context.history().restorableChanges())
63633             return;
63634
63635         var modalSelection = uiModal(selection, true);
63636
63637         modalSelection.select('.modal')
63638             .attr('class', 'modal fillL col6');
63639
63640         var introModal = modalSelection.select('.content');
63641
63642         introModal
63643             .attr('class','cf');
63644
63645         introModal
63646             .append('div')
63647             .attr('class', 'modal-section')
63648             .append('h3')
63649             .text(t('restore.heading'));
63650
63651         introModal
63652             .append('div')
63653             .attr('class','modal-section')
63654             .append('p')
63655             .text(t('restore.description'));
63656
63657         var buttonWrap = introModal
63658             .append('div')
63659             .attr('class', 'modal-actions cf');
63660
63661         var restore = buttonWrap
63662             .append('button')
63663             .attr('class', 'restore col6')
63664             .on('click', function() {
63665                 context.history().restore();
63666                 modalSelection.remove();
63667             });
63668
63669         restore
63670             .append('svg')
63671             .attr('class', 'logo logo-restore')
63672             .append('use')
63673             .attr('xlink:href', '#logo-restore');
63674
63675         restore
63676             .append('div')
63677             .text(t('restore.restore'));
63678
63679         var reset = buttonWrap
63680             .append('button')
63681             .attr('class', 'reset col6')
63682             .on('click', function() {
63683                 context.history().clearSaved();
63684                 modalSelection.remove();
63685             });
63686
63687         reset
63688             .append('svg')
63689             .attr('class', 'logo logo-reset')
63690             .append('use')
63691             .attr('xlink:href', '#logo-reset');
63692
63693         reset
63694             .append('div')
63695             .text(t('restore.reset'));
63696
63697         restore.node().focus();
63698     };
63699 }
63700
63701 function uiSave(context) {
63702     var history = context.history(),
63703         key = uiCmd('⌘S');
63704
63705
63706     function saving() {
63707         return context.mode().id === 'save';
63708     }
63709
63710
63711     function save() {
63712         event.preventDefault();
63713         if (!context.inIntro() && !saving() && history.hasChanges()) {
63714             context.enter(modeSave$$1(context));
63715         }
63716     }
63717
63718
63719     function getBackground(numChanges) {
63720         var step;
63721         if (numChanges === 0) {
63722             return null;
63723         } else if (numChanges <= 50) {
63724             step = numChanges / 50;
63725             return interpolateRgb('#fff', '#ff8')(step);  // white -> yellow
63726         } else {
63727             step = Math.min((numChanges - 50) / 50, 1.0);
63728             return interpolateRgb('#ff8', '#f88')(step);  // yellow -> red
63729         }
63730     }
63731
63732
63733     return function(selection$$1) {
63734         var numChanges = 0;
63735
63736         function updateCount() {
63737             var _ = history.difference().summary().length;
63738             if (_ === numChanges) return;
63739             numChanges = _;
63740
63741             tooltipBehavior
63742                 .title(uiTooltipHtml(
63743                     t(numChanges > 0 ? 'save.help' : 'save.no_changes'), key)
63744                 );
63745
63746             var background = getBackground(numChanges);
63747
63748             button
63749                 .classed('disabled', numChanges === 0)
63750                 .classed('has-count', numChanges > 0)
63751                 .style('background', background);
63752
63753             button.select('span.count')
63754                 .text(numChanges)
63755                 .style('background', background)
63756                 .style('border-color', background);
63757         }
63758
63759
63760         var tooltipBehavior = tooltip()
63761             .placement('bottom')
63762             .html(true)
63763             .title(uiTooltipHtml(t('save.no_changes'), key));
63764
63765         var button = selection$$1
63766             .append('button')
63767             .attr('class', 'save col12 disabled')
63768             .attr('tabindex', -1)
63769             .on('click', save)
63770             .call(tooltipBehavior);
63771
63772         button
63773             .call(svgIcon('#icon-save', 'pre-text'))
63774             .append('span')
63775             .attr('class', 'label')
63776             .text(t('save.title'));
63777
63778         button
63779             .append('span')
63780             .attr('class', 'count')
63781             .text('0');
63782
63783         updateCount();
63784
63785
63786         var keybinding = d3keybinding('save')
63787             .on(key, save, true);
63788
63789         select(document)
63790             .call(keybinding);
63791
63792         context.history()
63793             .on('change.save', updateCount);
63794
63795         context
63796             .on('enter.save', function() {
63797                 button.property('disabled', saving());
63798                 if (saving()) button.call(tooltipBehavior.hide);
63799             });
63800     };
63801 }
63802
63803 function uiScale(context) {
63804     var projection = context.projection,
63805         isImperial = (utilDetect().locale.toLowerCase() === 'en-us'),
63806         maxLength = 180,
63807         tickHeight = 8;
63808
63809
63810     function scaleDefs(loc1, loc2) {
63811         var lat = (loc2[1] + loc1[1]) / 2,
63812             conversion = (isImperial ? 3.28084 : 1),
63813             dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
63814             scale = { dist: 0, px: 0, text: '' },
63815             buckets, i, val, dLon;
63816
63817         if (isImperial) {
63818             buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
63819         } else {
63820             buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
63821         }
63822
63823         // determine a user-friendly endpoint for the scale
63824         for (i = 0; i < buckets.length; i++) {
63825             val = buckets[i];
63826             if (dist >= val) {
63827                 scale.dist = Math.floor(dist / val) * val;
63828                 break;
63829             } else {
63830                 scale.dist = +dist.toFixed(2);
63831             }
63832         }
63833
63834         dLon = geoMetersToLon(scale.dist / conversion, lat);
63835         scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
63836
63837         if (isImperial) {
63838             if (scale.dist >= 5280) {
63839                 scale.dist /= 5280;
63840                 scale.text = String(scale.dist) + ' mi';
63841             } else {
63842                 scale.text = String(scale.dist) + ' ft';
63843             }
63844         } else {
63845             if (scale.dist >= 1000) {
63846                 scale.dist /= 1000;
63847                 scale.text = String(scale.dist) + ' km';
63848             } else {
63849                 scale.text = String(scale.dist) + ' m';
63850             }
63851         }
63852
63853         return scale;
63854     }
63855
63856
63857     function update(selection) {
63858         // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
63859         var dims = context.map().dimensions(),
63860             loc1 = projection.invert([0, dims[1]]),
63861             loc2 = projection.invert([maxLength, dims[1]]),
63862             scale = scaleDefs(loc1, loc2);
63863
63864         selection.select('#scale-path')
63865             .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
63866
63867         selection.select('#scale-textgroup')
63868             .attr('transform', 'translate(' + (scale.px + 8) + ',' + tickHeight + ')');
63869
63870         selection.select('#scale-text')
63871             .text(scale.text);
63872     }
63873
63874
63875     return function(selection) {
63876         function switchUnits() {
63877             isImperial = !isImperial;
63878             selection.call(update);
63879         }
63880
63881         var scalegroup = selection.append('svg')
63882             .attr('id', 'scale')
63883             .on('click', switchUnits)
63884             .append('g')
63885             .attr('transform', 'translate(10,11)');
63886
63887         scalegroup
63888             .append('path')
63889             .attr('id', 'scale-path');
63890
63891         scalegroup
63892             .append('g')
63893             .attr('id', 'scale-textgroup')
63894             .append('text')
63895             .attr('id', 'scale-text');
63896
63897         selection.call(update);
63898
63899         context.map().on('move.scale', function() {
63900             update(selection);
63901         });
63902     };
63903 }
63904
63905 var pair_1 = pair$1;
63906 function search(x, dims, r) {
63907   if (!dims) dims = 'NSEW';
63908   if (typeof x !== 'string') return { val: null, regex: r };
63909   r = r || /[\s\,]*([\-|\—|\―]?[0-9.]+)°? *(?:([0-9.]+)['’′‘] *)?(?:([0-9.]+)(?:''|"|”|″) *)?([NSEW])?/gi;
63910   var m = r.exec(x);
63911   if (!m) return { val: null, regex: r };
63912   else if (m[4] && dims.indexOf(m[4]) === -1) return { val: null, regex: r };
63913   else return {
63914     val: (((m[1]) ? parseFloat(m[1]) : 0) +
63915           ((m[2] ? parseFloat(m[2]) / 60 : 0)) +
63916           ((m[3] ? parseFloat(m[3]) / 3600 : 0))) *
63917           ((m[4] && m[4] === 'S' || m[4] === 'W') ? -1 : 1),
63918     regex: r,
63919     raw: m[0],
63920     dim: m[4]
63921   };
63922 }
63923
63924 function pair$1(x, dims) {
63925   x = x.trim();
63926   var one = search(x, dims);
63927   if (one.val === null) return null;
63928   var two = search(x, dims, one.regex);
63929   if (two.val === null) return null;
63930   // null if one/two are not contiguous.
63931   if (one.raw + two.raw !== x) return null;
63932   if (one.dim) {
63933     return swapdim(one.val, two.val, one.dim);
63934   } else {
63935     return [one.val, two.val];
63936   }
63937 }
63938
63939 function swapdim(a, b, dim) {
63940   if (dim === 'N' || dim === 'S') return [a, b];
63941   if (dim === 'W' || dim === 'E') return [b, a];
63942 }
63943
63944 function uiFeatureList(context) {
63945     var geocodeResults;
63946
63947
63948     function featureList(selection$$1) {
63949         var header = selection$$1
63950             .append('div')
63951             .attr('class', 'header fillL cf');
63952
63953         header.append('h3')
63954             .text(t('inspector.feature_list'));
63955
63956         var searchWrap = selection$$1
63957             .append('div')
63958             .attr('class', 'search-header');
63959
63960         var search = searchWrap
63961             .append('input')
63962             .attr('placeholder', t('inspector.search'))
63963             .attr('type', 'search')
63964             .call(utilNoAuto)
63965             .on('keypress', keypress)
63966             .on('input', inputevent);
63967
63968         searchWrap
63969             .call(svgIcon('#icon-search', 'pre-text'));
63970
63971         var listWrap = selection$$1
63972             .append('div')
63973             .attr('class', 'inspector-body');
63974
63975         var list = listWrap
63976             .append('div')
63977             .attr('class', 'feature-list cf');
63978
63979         context
63980             .on('exit.feature-list', clearSearch);
63981         context.map()
63982             .on('drawn.feature-list', mapDrawn);
63983
63984
63985         function keypress() {
63986             var q = search.property('value'),
63987                 items = list.selectAll('.feature-list-item');
63988             if (event.keyCode === 13 && q.length && items.size()) {
63989                 click(items.datum());
63990             }
63991         }
63992
63993
63994         function inputevent() {
63995             geocodeResults = undefined;
63996             drawList();
63997         }
63998
63999
64000         function clearSearch() {
64001             search.property('value', '');
64002             drawList();
64003         }
64004
64005
64006         function mapDrawn(e) {
64007             if (e.full) {
64008                 drawList();
64009             }
64010         }
64011
64012
64013         function features() {
64014             var entities = {},
64015                 result = [],
64016                 graph = context.graph(),
64017                 q = search.property('value').toLowerCase();
64018
64019             if (!q) return result;
64020
64021             var idMatch = q.match(/^([nwr])([0-9]+)$/);
64022
64023             if (idMatch) {
64024                 result.push({
64025                     id: idMatch[0],
64026                     geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
64027                     type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
64028                     name: idMatch[2]
64029                 });
64030             }
64031
64032             var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
64033
64034             if (locationMatch) {
64035                 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
64036                 result.push({
64037                     id: -1,
64038                     geometry: 'point',
64039                     type: t('inspector.location'),
64040                     name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
64041                     location: loc
64042                 });
64043             }
64044
64045             function addEntity(entity) {
64046                 if (entity.id in entities || result.length > 200)
64047                     return;
64048
64049                 entities[entity.id] = true;
64050
64051                 var name = utilDisplayName(entity) || '';
64052                 if (name.toLowerCase().indexOf(q) >= 0) {
64053                     var matched = context.presets().match(entity, graph),
64054                         type = (matched && matched.name()) || utilDisplayType(entity.id);
64055                     result.push({
64056                         id: entity.id,
64057                         entity: entity,
64058                         geometry: context.geometry(entity.id),
64059                         type: type,
64060                         name: name
64061                     });
64062                 }
64063
64064                 graph.parentRelations(entity).forEach(function(parent) {
64065                     addEntity(parent);
64066                 });
64067             }
64068
64069             var visible = context.surface().selectAll('.point, .line, .area').nodes();
64070             for (var i = 0; i < visible.length && result.length <= 200; i++) {
64071                 addEntity(visible[i].__data__);
64072             }
64073
64074             (geocodeResults || []).forEach(function(d) {
64075                 // https://github.com/openstreetmap/iD/issues/1890
64076                 if (d.osm_type && d.osm_id) {
64077                     result.push({
64078                         id: osmEntity$$1.id.fromOSM(d.osm_type, d.osm_id),
64079                         geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
64080                         type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
64081                                                : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
64082                         name: d.display_name,
64083                         extent: new geoExtent$$1(
64084                             [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
64085                             [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
64086                     });
64087                 }
64088             });
64089
64090             return result;
64091         }
64092
64093
64094         function drawList() {
64095             var value = search.property('value'),
64096                 results = features();
64097
64098             list.classed('filtered', value.length);
64099
64100             var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
64101
64102             var resultsIndicator = list.selectAll('.no-results-item')
64103                 .data([0])
64104                 .enter().append('button')
64105                 .property('disabled', true)
64106                 .attr('class', 'no-results-item')
64107                 .call(svgIcon('#icon-alert', 'pre-text'));
64108
64109             resultsIndicator.append('span')
64110                 .attr('class', 'entity-name');
64111
64112             list.selectAll('.no-results-item .entity-name')
64113                 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
64114
64115             if (services.geocoder) {
64116               list.selectAll('.geocode-item')
64117                   .data([0])
64118                   .enter().append('button')
64119                   .attr('class', 'geocode-item')
64120                   .on('click', geocoderSearch)
64121                   .append('div')
64122                   .attr('class', 'label')
64123                   .append('span')
64124                   .attr('class', 'entity-name')
64125                   .text(t('geocoder.search'));
64126             }
64127
64128             list.selectAll('.no-results-item')
64129                 .style('display', (value.length && !results.length) ? 'block' : 'none');
64130
64131             list.selectAll('.geocode-item')
64132                 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
64133
64134             list.selectAll('.feature-list-item')
64135                 .data([-1])
64136                 .remove();
64137
64138             var items = list.selectAll('.feature-list-item')
64139                 .data(results, function(d) { return d.id; });
64140
64141             var enter = items.enter()
64142                 .insert('button', '.geocode-item')
64143                 .attr('class', 'feature-list-item')
64144                 .on('mouseover', mouseover)
64145                 .on('mouseout', mouseout)
64146                 .on('click', click);
64147
64148             var label = enter
64149                 .append('div')
64150                 .attr('class', 'label');
64151
64152             label.each(function(d) {
64153                 select(this)
64154                     .call(svgIcon('#icon-' + d.geometry, 'pre-text'));
64155             });
64156
64157             label.append('span')
64158                 .attr('class', 'entity-type')
64159                 .text(function(d) { return d.type; });
64160
64161             label.append('span')
64162                 .attr('class', 'entity-name')
64163                 .text(function(d) { return d.name; });
64164
64165             enter.style('opacity', 0)
64166                 .transition()
64167                 .style('opacity', 1);
64168
64169             items.order();
64170
64171             items.exit()
64172                 .remove();
64173         }
64174
64175
64176         function mouseover(d) {
64177             if (d.id === -1) return;
64178
64179             context.surface().selectAll(utilEntityOrMemberSelector([d.id], context.graph()))
64180                 .classed('hover', true);
64181         }
64182
64183
64184         function mouseout() {
64185             context.surface().selectAll('.hover')
64186                 .classed('hover', false);
64187         }
64188
64189
64190         function click(d) {
64191             event.preventDefault();
64192             if (d.location) {
64193                 context.map().centerZoom([d.location[1], d.location[0]], 20);
64194             }
64195             else if (d.entity) {
64196                 if (d.entity.type === 'node') {
64197                     context.map().center(d.entity.loc);
64198                 } else if (d.entity.type === 'way') {
64199                     var center = context.projection(context.map().center()),
64200                         edge = geoChooseEdge(context.childNodes(d.entity), center, context.projection);
64201                     context.map().center(edge.loc);
64202                 }
64203                 context.enter(modeSelect(context, [d.entity.id]));
64204             } else {
64205                 context.zoomToEntity(d.id);
64206             }
64207         }
64208
64209
64210         function geocoderSearch() {
64211             services.geocoder.search(search.property('value'), function (err, resp) {
64212                 geocodeResults = resp || [];
64213                 drawList();
64214             });
64215         }
64216     }
64217
64218
64219     return featureList;
64220 }
64221
64222 function uiPresetIcon() {
64223     var preset, geometry;
64224
64225
64226     function presetIcon(selection$$1) {
64227         selection$$1.each(render);
64228     }
64229
64230
64231     function getIcon(p, geom) {
64232         if (p.icon)
64233             return p.icon;
64234         else if (geom === 'line')
64235             return 'other-line';
64236         else if (geom === 'vertex')
64237             return p.isFallback() ? '' : 'poi-vertex';
64238         else
64239             return 'marker-stroked';
64240     }
64241
64242
64243     function render() {
64244         var selection$$1 = select(this),
64245             p = preset.apply(this, arguments),
64246             geom = geometry.apply(this, arguments),
64247             picon = getIcon(p, geom),
64248             isPoi = picon.match(/^poi-/) !== null,
64249             isMaki = dataFeatureIcons.indexOf(picon) !== -1,
64250             isFramed = (geom === 'area' || geom === 'verex');
64251
64252
64253         function tag_classes(p) {
64254             var s = '';
64255             for (var i in p.tags) {
64256                 s += ' tag-' + i;
64257                 if (p.tags[i] !== '*') {
64258                     s += ' tag-' + i + '-' + p.tags[i];
64259                 }
64260             }
64261             return s;
64262         }
64263
64264
64265         var fill = selection$$1.selectAll('.preset-icon-fill')
64266             .data([0]);
64267
64268         fill = fill.enter()
64269             .append('div')
64270             .merge(fill);
64271
64272         fill
64273             .attr('class', function() {
64274                 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
64275             });
64276
64277
64278         var areaFrame = selection$$1.selectAll('.preset-icon-frame')
64279             .data((geom === 'area') ? [0] : []);
64280
64281         areaFrame.exit()
64282             .remove();
64283
64284         areaFrame = areaFrame.enter()
64285             .append('div')
64286             .attr('class', 'preset-icon-frame')
64287             .call(svgIcon('#preset-icon-frame'));
64288
64289
64290         var icon = selection$$1.selectAll('.preset-icon')
64291             .data([0]);
64292
64293         icon = icon.enter()
64294             .append('div')
64295             .attr('class', 'preset-icon')
64296             .call(svgIcon(''))
64297             .merge(icon);
64298
64299         icon
64300             .attr('class', 'preset-icon preset-icon-' +
64301                 ((isMaki || isPoi) ? (isFramed ? '24' : '28') : (isFramed ? '44' : '60'))
64302             );
64303
64304         icon.selectAll('svg')
64305             .attr('class', function() {
64306                 return 'icon ' + picon + (isMaki || isPoi ? '' : tag_classes(p));
64307             });
64308
64309         icon.selectAll('use')
64310             .attr('href', '#' + picon + (isMaki ? '-15' : ''));
64311     }
64312
64313
64314     presetIcon.preset = function(_) {
64315         if (!arguments.length) return preset;
64316         preset = utilFunctor(_);
64317         return presetIcon;
64318     };
64319
64320
64321     presetIcon.geometry = function(_) {
64322         if (!arguments.length) return geometry;
64323         geometry = utilFunctor(_);
64324         return presetIcon;
64325     };
64326
64327     return presetIcon;
64328 }
64329
64330 function d3combobox() {
64331     var dispatch$$1 = dispatch('accept'),
64332         container = select(document.body),
64333         data = [],
64334         suggestions = [],
64335         minItems = 2,
64336         caseSensitive = false;
64337
64338     var fetcher = function(val, cb) {
64339         cb(data.filter(function(d) {
64340             return d.value
64341                 .toString()
64342                 .toLowerCase()
64343                 .indexOf(val.toLowerCase()) !== -1;
64344         }));
64345     };
64346
64347     var combobox = function(input, attachTo) {
64348         var idx = -1,
64349             wrapper = container
64350                 .selectAll('div.combobox')
64351                 .filter(function(d) { return d === input.node(); }),
64352             shown = !wrapper.empty();
64353
64354         input
64355             .classed('combobox-input', true)
64356             .on('focus.typeahead', focus)
64357             .on('blur.typeahead', blur)
64358             .on('keydown.typeahead', keydown)
64359             .on('keyup.typeahead', keyup)
64360             .on('input.typeahead', change)
64361             .each(function() {
64362                 var parent = this.parentNode,
64363                     sibling = this.nextSibling;
64364
64365                 var caret = select(parent).selectAll('.combobox-caret')
64366                     .filter(function(d) { return d === input.node(); })
64367                     .data([input.node()]);
64368
64369                 caret = caret.enter()
64370                   .insert('div', function() { return sibling; })
64371                     .attr('class', 'combobox-caret')
64372                   .merge(caret);
64373
64374                 caret
64375                     .on('mousedown', function () {
64376                         // prevent the form element from blurring. it blurs
64377                         // on mousedown
64378                         event.stopPropagation();
64379                         event.preventDefault();
64380                         if (!shown) {
64381                             input.node().focus();
64382                             fetch('', render);
64383                         } else {
64384                             hide();
64385                         }
64386                     });
64387             });
64388
64389         function focus() {
64390             fetch(value(), render);
64391         }
64392
64393         function blur() {
64394             window.setTimeout(hide, 150);
64395         }
64396
64397         function show() {
64398             if (!shown) {
64399                 wrapper = container
64400                     .insert('div', ':first-child')
64401                     .datum(input.node())
64402                     .attr('class', 'combobox')
64403                     .style('position', 'absolute')
64404                     .style('display', 'block')
64405                     .style('left', '0px')
64406                     .on('mousedown', function () {
64407                         // prevent moving focus out of the text field
64408                         event.preventDefault();
64409                     });
64410
64411                 select('body')
64412                     .on('scroll.combobox', render, true);
64413
64414                 shown = true;
64415             }
64416         }
64417
64418         function hide() {
64419             if (shown) {
64420                 idx = -1;
64421                 wrapper.remove();
64422
64423                 select('body')
64424                     .on('scroll.combobox', null);
64425
64426                 shown = false;
64427             }
64428         }
64429
64430         function keydown() {
64431            switch (event.keyCode) {
64432                // backspace, delete
64433                case 8:
64434                case 46:
64435                    input.on('input.typeahead', function() {
64436                        idx = -1;
64437                        render();
64438                        var start = input.property('selectionStart');
64439                        input.node().setSelectionRange(start, start);
64440                        input.on('input.typeahead', change);
64441                    });
64442                    break;
64443                // tab
64444                case 9:
64445                    wrapper.selectAll('a.selected').each(function (d) {
64446                        dispatch$$1.call('accept', this, d);
64447                    });
64448                    hide();
64449                    break;
64450                // return
64451                case 13:
64452                    event.preventDefault();
64453                    break;
64454                // up arrow
64455                case 38:
64456                    nav(-1);
64457                    event.preventDefault();
64458                    break;
64459                // down arrow
64460                case 40:
64461                    nav(+1);
64462                    event.preventDefault();
64463                    break;
64464            }
64465            event.stopPropagation();
64466         }
64467
64468         function keyup() {
64469             switch (event.keyCode) {
64470                 // escape
64471                 case 27:
64472                     hide();
64473                     break;
64474                 // return
64475                 case 13:
64476                     wrapper.selectAll('a.selected').each(function (d) {
64477                        dispatch$$1.call('accept', this, d);
64478                     });
64479                     hide();
64480                     break;
64481             }
64482         }
64483
64484         function change() {
64485             fetch(value(), function() {
64486                 if (input.property('selectionEnd') === input.property('value').length) {
64487                     autocomplete();
64488                 }
64489                 render();
64490             });
64491         }
64492
64493         function nav(dir) {
64494             if (!suggestions.length) return;
64495             idx = Math.max(Math.min(idx + dir, suggestions.length - 1), 0);
64496             input.property('value', suggestions[idx].value);
64497             render();
64498             ensureVisible();
64499         }
64500
64501         function value() {
64502             var value = input.property('value'),
64503                 start = input.property('selectionStart'),
64504                 end = input.property('selectionEnd');
64505
64506             if (start && end) {
64507                 value = value.substring(0, start);
64508             }
64509
64510             return value;
64511         }
64512
64513         function fetch(v, cb) {
64514             fetcher.call(input, v, function(_) {
64515                 suggestions = _;
64516                 cb();
64517             });
64518         }
64519
64520         function autocomplete() {
64521             var v = caseSensitive ? value() : value().toLowerCase();
64522             idx = -1;
64523             if (!v) return;
64524
64525             for (var i = 0; i < suggestions.length; i++) {
64526                 var suggestion = suggestions[i].value,
64527                     compare = caseSensitive ? suggestion : suggestion.toLowerCase();
64528
64529                 if (compare.indexOf(v) === 0) {
64530                     idx = i;
64531                     input.property('value', suggestion);
64532                     input.node().setSelectionRange(v.length, suggestion.length);
64533                     return;
64534                 }
64535             }
64536         }
64537
64538         function render() {
64539             if (suggestions.length >= minItems && document.activeElement === input.node()) {
64540                 show();
64541             } else {
64542                 hide();
64543                 return;
64544             }
64545
64546             var options = wrapper
64547                 .selectAll('a.combobox-option')
64548                 .data(suggestions, function(d) { return d.value; });
64549
64550             options.exit()
64551                 .remove();
64552
64553             options.enter()
64554                 .append('a')
64555                 .attr('class', 'combobox-option')
64556                 .text(function(d) { return d.value; })
64557                 .merge(options)
64558                 .attr('title', function(d) { return d.title; })
64559                 .classed('selected', function(d, i) { return i === idx; })
64560                 .on('mouseover', select$$1)
64561                 .on('click', accept)
64562                 .order();
64563
64564
64565             var node = attachTo ? attachTo.node() : input.node(),
64566                 rect = node.getBoundingClientRect();
64567
64568             wrapper
64569                 .style('left', rect.left + 'px')
64570                 .style('width', rect.width + 'px')
64571                 .style('top', rect.height + rect.top + 'px');
64572         }
64573
64574         function select$$1(d, i) {
64575             idx = i;
64576             render();
64577         }
64578
64579         function ensureVisible() {
64580             var node = wrapper.selectAll('a.selected').node();
64581             if (node) node.scrollIntoView();
64582         }
64583
64584         function accept(d) {
64585             if (!shown) return;
64586             input.property('value', d.value);
64587             utilTriggerEvent(input, 'change');
64588             dispatch$$1.call('accept', this, d);
64589             hide();
64590         }
64591     };
64592
64593     combobox.fetcher = function(_) {
64594         if (!arguments.length) return fetcher;
64595         fetcher = _;
64596         return combobox;
64597     };
64598
64599     combobox.data = function(_) {
64600         if (!arguments.length) return data;
64601         data = _;
64602         return combobox;
64603     };
64604
64605     combobox.minItems = function(_) {
64606         if (!arguments.length) return minItems;
64607         minItems = _;
64608         return combobox;
64609     };
64610
64611     combobox.caseSensitive = function(_) {
64612         if (!arguments.length) return caseSensitive;
64613         caseSensitive = _;
64614         return combobox;
64615     };
64616
64617     combobox.container = function(_) {
64618         if (!arguments.length) return container;
64619         container = _;
64620         return combobox;
64621     };
64622
64623     return utilRebind(combobox, dispatch$$1, 'on');
64624 }
64625
64626
64627 d3combobox.off = function(input) {
64628     input
64629         .on('focus.typeahead', null)
64630         .on('blur.typeahead', null)
64631         .on('keydown.typeahead', null)
64632         .on('keyup.typeahead', null)
64633         .on('input.typeahead', null)
64634         .each(function() {
64635             select(this.parentNode).selectAll('.combobox-caret')
64636                 .filter(function(d) { return d === input.node(); })
64637                 .on('mousedown', null);
64638         });
64639
64640     select('body')
64641         .on('scroll.combobox', null);
64642 };
64643
64644 function uiDisclosure() {
64645     var dispatch$$1 = dispatch('toggled'),
64646         title,
64647         expanded = false,
64648         content = function () {};
64649
64650
64651     var disclosure = function(selection$$1) {
64652         var hideToggle = selection$$1.selectAll('.hide-toggle')
64653             .data([0]);
64654
64655         hideToggle = hideToggle.enter()
64656             .append('a')
64657             .attr('href', '#')
64658             .attr('class', 'hide-toggle')
64659             .merge(hideToggle);
64660
64661         hideToggle
64662             .text(title)
64663             .on('click', toggle)
64664             .classed('expanded', expanded);
64665
64666
64667         var wrap = selection$$1.selectAll('div')
64668             .data([0]);
64669
64670         wrap = wrap.enter()
64671             .append('div')
64672             .merge(wrap);
64673
64674         wrap
64675             .classed('hide', !expanded)
64676             .call(content);
64677
64678
64679         function toggle() {
64680             expanded = !expanded;
64681             hideToggle.classed('expanded', expanded);
64682             wrap.call(uiToggle(expanded));
64683             dispatch$$1.call('toggled', this, expanded);
64684         }
64685     };
64686
64687
64688     disclosure.title = function(_) {
64689         if (!arguments.length) return title;
64690         title = _;
64691         return disclosure;
64692     };
64693
64694
64695     disclosure.expanded = function(_) {
64696         if (!arguments.length) return expanded;
64697         expanded = _;
64698         return disclosure;
64699     };
64700
64701
64702     disclosure.content = function(_) {
64703         if (!arguments.length) return content;
64704         content = _;
64705         return disclosure;
64706     };
64707
64708
64709     return utilRebind(disclosure, dispatch$$1, 'on');
64710 }
64711
64712 function uiRawMemberEditor(context) {
64713     var id,
64714         taginfo = services.taginfo;
64715
64716
64717     function selectMember(d) {
64718         event.preventDefault();
64719         context.enter(modeSelect(context, [d.id]));
64720     }
64721
64722
64723     function changeRole(d) {
64724         var role = select(this).property('value');
64725         var member = { id: d.id, type: d.type, role: role };
64726         context.perform(
64727             actionChangeMember(d.relation.id, member, d.index),
64728             t('operations.change_role.annotation')
64729         );
64730     }
64731
64732
64733     function deleteMember(d) {
64734         context.perform(
64735             actionDeleteMember(d.relation.id, d.index),
64736             t('operations.delete_member.annotation')
64737         );
64738
64739         if (!context.hasEntity(d.relation.id)) {
64740             context.enter(modeBrowse(context));
64741         }
64742     }
64743
64744
64745     function rawMemberEditor(selection$$1) {
64746         var entity = context.entity(id),
64747             memberships = [];
64748
64749         entity.members.slice(0, 1000).forEach(function(member, index) {
64750             memberships.push({
64751                 index: index,
64752                 id: member.id,
64753                 type: member.type,
64754                 role: member.role,
64755                 relation: entity,
64756                 member: context.hasEntity(member.id)
64757             });
64758         });
64759
64760         var gt = entity.members.length > 1000 ? '>' : '';
64761         selection$$1.call(uiDisclosure()
64762             .title(t('inspector.all_members') + ' (' + gt + memberships.length + ')')
64763             .expanded(true)
64764             .on('toggled', toggled)
64765             .content(content)
64766         );
64767
64768
64769         function toggled(expanded) {
64770             if (expanded) {
64771                 selection$$1.node().parentNode.scrollTop += 200;
64772             }
64773         }
64774
64775
64776         function content(wrap) {
64777             var list = wrap.selectAll('.member-list')
64778                 .data([0]);
64779
64780             list = list.enter()
64781                 .append('ul')
64782                 .attr('class', 'member-list')
64783                 .merge(list);
64784
64785
64786             var items = list.selectAll('li')
64787                 .data(memberships, function(d) {
64788                     return osmEntity$$1.key(d.relation) + ',' + d.index + ',' +
64789                         (d.member ? osmEntity$$1.key(d.member) : 'incomplete');
64790                 });
64791
64792             items.exit()
64793                 .each(unbind)
64794                 .remove();
64795
64796             var enter = items.enter()
64797                 .append('li')
64798                 .attr('class', 'member-row form-field')
64799                 .classed('member-incomplete', function(d) { return !d.member; });
64800
64801             enter
64802                 .each(function(d) {
64803                     if (d.member) {
64804                         var label = select(this).append('label')
64805                             .attr('class', 'form-label')
64806                             .append('a')
64807                             .attr('href', '#')
64808                             .on('click', selectMember);
64809
64810                         label.append('span')
64811                             .attr('class', 'member-entity-type')
64812                             .text(function(d) {
64813                                 var matched = context.presets().match(d.member, context.graph());
64814                                 return (matched && matched.name()) || utilDisplayType(d.member.id);
64815                             });
64816
64817                         label.append('span')
64818                             .attr('class', 'member-entity-name')
64819                             .text(function(d) { return utilDisplayName(d.member); });
64820
64821                     } else {
64822                         select(this).append('label')
64823                             .attr('class', 'form-label')
64824                             .text(t('inspector.incomplete', { id: d.id }));
64825                     }
64826                 });
64827
64828             enter
64829                 .append('input')
64830                 .attr('class', 'member-role')
64831                 .property('type', 'text')
64832                 .attr('maxlength', 255)
64833                 .attr('placeholder', t('inspector.role'))
64834                 .call(utilNoAuto)
64835                 .property('value', function(d) { return d.role; })
64836                 .on('change', changeRole);
64837
64838             enter
64839                 .append('button')
64840                 .attr('tabindex', -1)
64841                 .attr('class', 'remove button-input-action member-delete minor')
64842                 .on('click', deleteMember)
64843                 .call(svgIcon('#operation-delete'));
64844
64845             if (taginfo) {
64846                 enter.each(bindTypeahead);
64847             }
64848
64849
64850             function bindTypeahead(d) {
64851                 var row = select(this),
64852                     role = row.selectAll('input.member-role');
64853
64854                 function sort(value, data) {
64855                     var sameletter = [],
64856                         other = [];
64857                     for (var i = 0; i < data.length; i++) {
64858                         if (data[i].value.substring(0, value.length) === value) {
64859                             sameletter.push(data[i]);
64860                         } else {
64861                             other.push(data[i]);
64862                         }
64863                     }
64864                     return sameletter.concat(other);
64865                 }
64866
64867                 role.call(d3combobox()
64868                     .container(context.container())
64869                     .fetcher(function(role, callback) {
64870                         var rtype = entity.tags.type;
64871                         taginfo.roles({
64872                             debounce: true,
64873                             rtype: rtype || '',
64874                             geometry: context.geometry(d.member.id),
64875                             query: role
64876                         }, function(err, data) {
64877                             if (!err) callback(sort(role, data));
64878                         });
64879                     }));
64880             }
64881
64882
64883             function unbind() {
64884                 var row = select(this);
64885
64886                 row.selectAll('input.member-role')
64887                     .call(d3combobox.off);
64888             }
64889         }
64890     }
64891
64892
64893     rawMemberEditor.entityID = function(_) {
64894         if (!arguments.length) return id;
64895         id = _;
64896         return rawMemberEditor;
64897     };
64898
64899
64900     return rawMemberEditor;
64901 }
64902
64903 function uiRawMembershipEditor(context) {
64904     var taginfo = services.taginfo,
64905         id, showBlank;
64906
64907
64908     function selectRelation(d) {
64909         event.preventDefault();
64910         context.enter(modeSelect(context, [d.relation.id]));
64911     }
64912
64913
64914     function changeRole(d) {
64915         var role = select(this).property('value');
64916         context.perform(
64917             actionChangeMember(d.relation.id, lodash.extend({}, d.member, { role: role }), d.index),
64918             t('operations.change_role.annotation')
64919         );
64920     }
64921
64922
64923     function addMembership(d, role) {
64924         showBlank = false;
64925
64926         if (d.relation) {
64927             context.perform(
64928                 actionAddMember(d.relation.id, { id: id, type: context.entity(id).type, role: role }),
64929                 t('operations.add_member.annotation')
64930             );
64931
64932         } else {
64933             var relation = osmRelation();
64934             context.perform(
64935                 actionAddEntity(relation),
64936                 actionAddMember(relation.id, { id: id, type: context.entity(id).type, role: role }),
64937                 t('operations.add.annotation.relation')
64938             );
64939
64940             context.enter(modeSelect(context, [relation.id]));
64941         }
64942     }
64943
64944
64945     function deleteMembership(d) {
64946         context.perform(
64947             actionDeleteMember(d.relation.id, d.index),
64948             t('operations.delete_member.annotation')
64949         );
64950     }
64951
64952
64953     function relations(q) {
64954         var newRelation = {
64955                 relation: null,
64956                 value: t('inspector.new_relation')
64957             },
64958             result = [],
64959             graph = context.graph();
64960
64961         context.intersects(context.extent()).forEach(function(entity) {
64962             if (entity.type !== 'relation' || entity.id === id)
64963                 return;
64964
64965             var matched = context.presets().match(entity, graph),
64966                 presetName = (matched && matched.name()) || t('inspector.relation'),
64967                 entityName = utilDisplayName(entity) || '';
64968
64969             var value = presetName + ' ' + entityName;
64970             if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
64971                 return;
64972
64973             result.push({
64974                 relation: entity,
64975                 value: value
64976             });
64977         });
64978
64979         result.sort(function(a, b) {
64980             return osmRelation.creationOrder(a.relation, b.relation);
64981         });
64982
64983         // Dedupe identical names by appending relation id - see #2891
64984         var dupeGroups = lodash(result)
64985             .groupBy('value')
64986             .filter(function(v) { return v.length > 1; })
64987             .value();
64988
64989         dupeGroups.forEach(function(group) {
64990             group.forEach(function(obj) {
64991                 obj.value += ' ' + obj.relation.id;
64992             });
64993         });
64994
64995         result.unshift(newRelation);
64996         return result;
64997     }
64998
64999
65000     function rawMembershipEditor(selection$$1) {
65001         var entity = context.entity(id),
65002             parents = context.graph().parentRelations(entity),
65003             memberships = [];
65004
65005         parents.slice(0, 1000).forEach(function(relation) {
65006             relation.members.forEach(function(member, index) {
65007                 if (member.id === entity.id) {
65008                     memberships.push({ relation: relation, member: member, index: index });
65009                 }
65010             });
65011         });
65012
65013         var gt = parents.length > 1000 ? '>' : '';
65014         selection$$1.call(uiDisclosure()
65015             .title(t('inspector.all_relations') + ' (' + gt + memberships.length + ')')
65016             .expanded(true)
65017             .on('toggled', toggled)
65018             .content(content)
65019         );
65020
65021
65022         function toggled(expanded) {
65023             if (expanded) {
65024                 selection$$1.node().parentNode.scrollTop += 200;
65025             }
65026         }
65027
65028
65029         function content(wrap) {
65030             var list = wrap.selectAll('.member-list')
65031                 .data([0]);
65032
65033             list = list.enter()
65034                 .append('ul')
65035                 .attr('class', 'member-list')
65036                 .merge(list);
65037
65038
65039             var items = list.selectAll('li.member-row-normal')
65040                 .data(memberships, function(d) {
65041                     return osmEntity$$1.key(d.relation) + ',' + d.index;
65042                 });
65043
65044             items.exit()
65045                 .each(unbind)
65046                 .remove();
65047
65048             var enter = items.enter()
65049                 .append('li')
65050                 .attr('class', 'member-row member-row-normal form-field');
65051
65052             var label = enter
65053                 .append('label')
65054                 .attr('class', 'form-label')
65055                 .append('a')
65056                 .attr('href', '#')
65057                 .on('click', selectRelation);
65058
65059             label
65060                 .append('span')
65061                 .attr('class', 'member-entity-type')
65062                 .text(function(d) {
65063                     var matched = context.presets().match(d.relation, context.graph());
65064                     return (matched && matched.name()) || t('inspector.relation');
65065                 });
65066
65067             label
65068                 .append('span')
65069                 .attr('class', 'member-entity-name')
65070                 .text(function(d) { return utilDisplayName(d.relation); });
65071
65072             enter
65073                 .append('input')
65074                 .attr('class', 'member-role')
65075                 .property('type', 'text')
65076                 .attr('maxlength', 255)
65077                 .attr('placeholder', t('inspector.role'))
65078                 .call(utilNoAuto)
65079                 .property('value', function(d) { return d.member.role; })
65080                 .on('change', changeRole);
65081
65082             enter
65083                 .append('button')
65084                 .attr('tabindex', -1)
65085                 .attr('class', 'remove button-input-action member-delete minor')
65086                 .on('click', deleteMembership)
65087                 .call(svgIcon('#operation-delete'));
65088
65089             if (taginfo) {
65090                 enter.each(bindTypeahead);
65091             }
65092
65093
65094             var newrow = list.selectAll('.member-row-new')
65095                 .data(showBlank ? [0] : []);
65096
65097             newrow.exit()
65098                 .remove();
65099
65100             enter = newrow.enter()
65101                 .append('li')
65102                 .attr('class', 'member-row member-row-new form-field');
65103
65104             enter
65105                 .append('input')
65106                 .attr('type', 'text')
65107                 .attr('class', 'member-entity-input')
65108                 .call(utilNoAuto);
65109
65110             enter
65111                 .append('input')
65112                 .attr('class', 'member-role')
65113                 .property('type', 'text')
65114                 .attr('maxlength', 255)
65115                 .attr('placeholder', t('inspector.role'))
65116                 .call(utilNoAuto)
65117                 .on('change', changeRole);
65118
65119             enter
65120                 .append('button')
65121                 .attr('tabindex', -1)
65122                 .attr('class', 'remove button-input-action member-delete minor')
65123                 .on('click', deleteMembership)
65124                 .call(svgIcon('#operation-delete'));
65125
65126             newrow = newrow
65127                 .merge(enter);
65128
65129             newrow.selectAll('.member-entity-input')
65130                 .call(d3combobox()
65131                     .container(context.container())
65132                     .minItems(1)
65133                     .fetcher(function(value, callback) { callback(relations(value)); })
65134                     .on('accept', onAccept)
65135                 );
65136
65137
65138             var addrel = wrap.selectAll('.add-relation')
65139                 .data([0]);
65140
65141             addrel = addrel.enter()
65142                 .append('button')
65143                 .attr('class', 'add-relation')
65144                 .merge(addrel);
65145
65146             addrel
65147                 .call(svgIcon('#icon-plus', 'light'))
65148                 .on('click', function() {
65149                     showBlank = true;
65150                     content(wrap);
65151                     list.selectAll('.member-entity-input').node().focus();
65152                 });
65153
65154
65155             function onAccept(d) {
65156                 var role = list.selectAll('.member-row-new .member-role').property('value');
65157                 addMembership(d, role);
65158             }
65159
65160
65161             function bindTypeahead(d) {
65162                 var row = select(this),
65163                     role = row.selectAll('input.member-role');
65164
65165                 function sort(value, data) {
65166                     var sameletter = [],
65167                         other = [];
65168                     for (var i = 0; i < data.length; i++) {
65169                         if (data[i].value.substring(0, value.length) === value) {
65170                             sameletter.push(data[i]);
65171                         } else {
65172                             other.push(data[i]);
65173                         }
65174                     }
65175                     return sameletter.concat(other);
65176                 }
65177
65178                 role.call(d3combobox()
65179                     .container(context.container())
65180                     .fetcher(function(role, callback) {
65181                         var rtype = d.relation.tags.type;
65182                         taginfo.roles({
65183                             debounce: true,
65184                             rtype: rtype || '',
65185                             geometry: context.geometry(id),
65186                             query: role
65187                         }, function(err, data) {
65188                             if (!err) callback(sort(role, data));
65189                         });
65190                     }));
65191             }
65192
65193
65194             function unbind() {
65195                 var row = select(this);
65196
65197                 row.selectAll('input.member-role')
65198                     .call(d3combobox.off);
65199             }
65200         }
65201     }
65202
65203
65204     rawMembershipEditor.entityID = function(_) {
65205         if (!arguments.length) return id;
65206         id = _;
65207         return rawMembershipEditor;
65208     };
65209
65210
65211     return rawMembershipEditor;
65212 }
65213
65214 function uiTagReference(tag) {
65215     var taginfo = services.taginfo,
65216         tagReference = {},
65217         button,
65218         body,
65219         loaded,
65220         showing;
65221
65222
65223     function findLocal(data) {
65224         var locale = utilDetect().locale.toLowerCase(),
65225             localized;
65226
65227         if (locale !== 'pt-br') {  // see #3776, prefer 'pt' over 'pt-br'
65228             localized = lodash.find(data, function(d) {
65229                 return d.lang.toLowerCase() === locale;
65230             });
65231             if (localized) return localized;
65232         }
65233
65234         // try the non-regional version of a language, like
65235         // 'en' if the language is 'en-US'
65236         if (locale.indexOf('-') !== -1) {
65237             var first = locale.split('-')[0];
65238             localized = lodash.find(data, function(d) {
65239                 return d.lang.toLowerCase() === first;
65240             });
65241             if (localized) return localized;
65242         }
65243
65244         // finally fall back to english
65245         return lodash.find(data, function(d) {
65246             return d.lang.toLowerCase() === 'en';
65247         });
65248     }
65249
65250
65251     function load(param) {
65252         if (!taginfo) return;
65253
65254         button.classed('tag-reference-loading', true);
65255
65256         taginfo.docs(param, function show(err, data) {
65257             var docs;
65258             if (!err && data) {
65259                 docs = findLocal(data);
65260             }
65261
65262             body.html('');
65263
65264
65265             if (!docs || !docs.title) {
65266                 if (param.hasOwnProperty('value')) {
65267                     load(lodash.omit(param, 'value'));   // retry with key only
65268                 } else {
65269                     body.append('p').text(t('inspector.no_documentation_key'));
65270                     done();
65271                 }
65272                 return;
65273             }
65274
65275
65276             if (docs.image && docs.image.thumb_url_prefix) {
65277                 body
65278                     .append('img')
65279                     .attr('class', 'wiki-image')
65280                     .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
65281                     .on('load', function() { done(); })
65282                     .on('error', function() { select(this).remove(); done(); });
65283             } else {
65284                 done();
65285             }
65286
65287             body
65288                 .append('p')
65289                 .text(docs.description || t('inspector.documentation_redirect'));
65290
65291             body
65292                 .append('a')
65293                 .attr('target', '_blank')
65294                 .attr('tabindex', -1)
65295                 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
65296                 .call(svgIcon('#icon-out-link', 'inline'))
65297                 .append('span')
65298                 .text(t('inspector.reference'));
65299         });
65300     }
65301
65302
65303     function done() {
65304         loaded = true;
65305
65306         button.classed('tag-reference-loading', false);
65307
65308         body.transition()
65309             .duration(200)
65310             .style('max-height', '200px')
65311             .style('opacity', '1');
65312
65313         showing = true;
65314     }
65315
65316
65317     function hide(selection$$1) {
65318         selection$$1 = selection$$1 || body.transition().duration(200);
65319
65320         selection$$1
65321             .style('max-height', '0px')
65322             .style('opacity', '0');
65323
65324         showing = false;
65325     }
65326
65327
65328     tagReference.button = function(selection$$1) {
65329         button = selection$$1.selectAll('.tag-reference-button')
65330             .data([0]);
65331
65332         button = button.enter()
65333             .append('button')
65334             .attr('class', 'tag-reference-button')
65335             .attr('tabindex', -1)
65336             .call(svgIcon('#icon-inspect'))
65337             .merge(button);
65338
65339         button
65340             .on('click', function () {
65341                 event.stopPropagation();
65342                 event.preventDefault();
65343                 if (showing) {
65344                     hide();
65345                 } else if (loaded) {
65346                     done();
65347                 } else {
65348                     load(tag);
65349                 }
65350             });
65351     };
65352
65353
65354     tagReference.body = function(selection$$1) {
65355         body = selection$$1.selectAll('.tag-reference-body')
65356             .data([0]);
65357
65358         body = body.enter()
65359             .append('div')
65360             .attr('class', 'tag-reference-body cf')
65361             .style('max-height', '0')
65362             .style('opacity', '0')
65363             .merge(body);
65364
65365         if (showing === false) {
65366             hide(body);
65367         }
65368     };
65369
65370
65371     tagReference.showing = function(_) {
65372         if (!arguments.length) return showing;
65373         showing = _;
65374         return tagReference;
65375     };
65376
65377
65378     return tagReference;
65379 }
65380
65381 function uiRawTagEditor(context) {
65382     var taginfo = services.taginfo,
65383         dispatch$$1 = dispatch('change'),
65384         expanded = context.storage('raw_tag_editor.expanded') === 'true',
65385         readOnlyTags = [],
65386         updatePreference = true,
65387         showBlank = false,
65388         newRow,
65389         state,
65390         preset,
65391         tags,
65392         id;
65393
65394
65395     function rawTagEditor(selection$$1) {
65396         var count = Object.keys(tags).filter(function(d) { return d; }).length;
65397
65398         selection$$1.call(uiDisclosure()
65399             .title(t('inspector.all_tags') + ' (' + count + ')')
65400             .expanded(expanded)
65401             .on('toggled', toggled)
65402             .content(content)
65403         );
65404
65405         function toggled(expanded) {
65406             if (updatePreference) {
65407                 context.storage('raw_tag_editor.expanded', expanded);
65408             }
65409             if (expanded) {
65410                 selection$$1.node().parentNode.scrollTop += 200;
65411             }
65412         }
65413     }
65414
65415
65416     function content(wrap) {
65417         var entries$$1 = entries(tags);
65418
65419         if (!entries$$1.length || showBlank) {
65420             showBlank = false;
65421             entries$$1.push({key: '', value: ''});
65422             newRow = '';
65423         }
65424
65425         var list = wrap.selectAll('.tag-list')
65426             .data([0]);
65427
65428         list = list.enter()
65429             .append('ul')
65430             .attr('class', 'tag-list')
65431             .merge(list);
65432
65433         var newTag = wrap.selectAll('.add-tag')
65434             .data([0]);
65435
65436         newTag.enter()
65437             .append('button')
65438             .attr('class', 'add-tag')
65439             .on('click', addTag)
65440             .call(svgIcon('#icon-plus', 'light'));
65441
65442
65443         var items = list.selectAll('.tag-row')
65444             .data(entries$$1, function(d) { return d.key; });
65445
65446         items.exit()
65447             .each(unbind)
65448             .remove();
65449
65450         // Enter
65451
65452         var enter = items.enter()
65453             .append('li')
65454             .attr('class', 'tag-row cf')
65455             .classed('readonly', isReadOnly);
65456
65457         enter
65458             .append('div')
65459             .attr('class', 'key-wrap')
65460             .append('input')
65461             .property('type', 'text')
65462             .attr('class', 'key')
65463             .attr('maxlength', 255)
65464             .call(utilNoAuto)
65465             .on('blur', keyChange)
65466             .on('change', keyChange);
65467
65468         enter
65469             .append('div')
65470             .attr('class', 'input-wrap-position')
65471             .append('input')
65472             .property('type', 'text')
65473             .attr('class', 'value')
65474             .attr('maxlength', 255)
65475             .call(utilNoAuto)
65476             .on('blur', valueChange)
65477             .on('change', valueChange)
65478             .on('keydown.push-more', pushMore);
65479
65480         enter
65481             .append('button')
65482             .attr('tabindex', -1)
65483             .attr('class', 'remove minor')
65484             .call(svgIcon('#operation-delete'));
65485
65486
65487         // Update
65488
65489         items = items
65490             .merge(enter)
65491             .sort(function(a, b) {
65492                 return (a.key === newRow && b.key !== newRow) ? 1
65493                     : (a.key !== newRow && b.key === newRow) ? -1
65494                     : ascending(a.key, b.key);
65495             });
65496
65497         items
65498             .each(function(tag) {
65499                 var row = select(this),
65500                     key = row.select('input.key'),      // propagate bound data to child
65501                     value = row.select('input.value');  // propagate bound data to child
65502
65503                 if (id && taginfo) {
65504                     bindTypeahead(key, value);
65505                 }
65506
65507                 var isRelation = (id && context.entity(id).type === 'relation'),
65508                     reference;
65509
65510                 if (isRelation && tag.key === 'type') {
65511                     reference = uiTagReference({ rtype: tag.value }, context);
65512                 } else {
65513                     reference = uiTagReference({ key: tag.key, value: tag.value }, context);
65514                 }
65515
65516                 if (state === 'hover') {
65517                     reference.showing(false);
65518                 }
65519
65520                 row
65521                     .call(reference.button)
65522                     .call(reference.body);
65523             });
65524
65525         items.selectAll('input.key')
65526             .attr('title', function(d) { return d.key; })
65527             .call(utilGetSetValue, function(d) { return d.key; })
65528             .property('disabled', isReadOnly);
65529
65530         items.selectAll('input.value')
65531             .attr('title', function(d) { return d.value; })
65532             .call(utilGetSetValue, function(d) { return d.value; })
65533             .property('disabled', isReadOnly);
65534
65535         items.selectAll('button.remove')
65536             .on('click', removeTag);
65537
65538
65539
65540         function isReadOnly(d) {
65541             return readOnlyTags.indexOf(d.key) !== -1;
65542         }
65543
65544
65545         function pushMore() {
65546             if (event.keyCode === 9 && !event.shiftKey &&
65547                 list.selectAll('li:last-child input.value').node() === this) {
65548                 addTag();
65549             }
65550         }
65551
65552
65553         function bindTypeahead(key, value) {
65554             if (isReadOnly({ key: key })) return;
65555             var geometry = context.geometry(id);
65556
65557             key.call(d3combobox()
65558                 .container(context.container())
65559                 .fetcher(function(value, callback) {
65560                     taginfo.keys({
65561                         debounce: true,
65562                         geometry: geometry,
65563                         query: value
65564                     }, function(err, data) {
65565                         if (!err) callback(sort(value, data));
65566                     });
65567                 }));
65568
65569             value.call(d3combobox()
65570                 .container(context.container())
65571                 .fetcher(function(value, callback) {
65572                     taginfo.values({
65573                         debounce: true,
65574                         key: utilGetSetValue(key),
65575                         geometry: geometry,
65576                         query: value
65577                     }, function(err, data) {
65578                         if (!err) callback(sort(value, data));
65579                     });
65580                 }));
65581
65582
65583             function sort(value, data) {
65584                 var sameletter = [],
65585                     other = [];
65586                 for (var i = 0; i < data.length; i++) {
65587                     if (data[i].value.substring(0, value.length) === value) {
65588                         sameletter.push(data[i]);
65589                     } else {
65590                         other.push(data[i]);
65591                     }
65592                 }
65593                 return sameletter.concat(other);
65594             }
65595         }
65596
65597
65598         function unbind() {
65599             var row = select(this);
65600
65601             row.selectAll('input.key')
65602                 .call(d3combobox.off);
65603
65604             row.selectAll('input.value')
65605                 .call(d3combobox.off);
65606         }
65607
65608
65609         function keyChange(d) {
65610             var kOld = d.key,
65611                 kNew = this.value.trim(),
65612                 tag = {};
65613
65614
65615             if (isReadOnly({ key: kNew })) {
65616                 this.value = kOld;
65617                 return;
65618             }
65619
65620             if (kNew && kNew !== kOld) {
65621                 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
65622                     base = match[1],
65623                     suffix = +(match[2] || 1);
65624                 while (tags[kNew]) {  // rename key if already in use
65625                     kNew = base + '_' + suffix++;
65626                 }
65627             }
65628             tag[kOld] = undefined;
65629             tag[kNew] = d.value;
65630
65631             d.key = kNew; // Maintain DOM identity through the subsequent update.
65632
65633             if (newRow === kOld) {  // see if this row is still a new row
65634                 newRow = ((d.value === '' || kNew === '') ? kNew : undefined);
65635             }
65636
65637             this.value = kNew;
65638             dispatch$$1.call('change', this, tag);
65639         }
65640
65641
65642         function valueChange(d) {
65643             if (isReadOnly(d)) return;
65644             var tag = {};
65645             tag[d.key] = this.value;
65646
65647             if (newRow === d.key && d.key !== '' && d.value !== '') {   // not a new row anymore
65648                 newRow = undefined;
65649             }
65650
65651             dispatch$$1.call('change', this, tag);
65652         }
65653
65654
65655         function removeTag(d) {
65656             if (isReadOnly(d)) return;
65657             var tag = {};
65658             tag[d.key] = undefined;
65659             dispatch$$1.call('change', this, tag);
65660             select(this.parentNode).remove();
65661         }
65662
65663
65664         function addTag() {
65665             // Wrapped in a setTimeout in case it's being called from a blur
65666             // handler. Without the setTimeout, the call to `content` would
65667             // wipe out the pending value change.
65668             setTimeout(function() {
65669                 showBlank = true;
65670                 content(wrap);
65671                 list.selectAll('li:last-child input.key').node().focus();
65672             }, 0);
65673         }
65674     }
65675
65676
65677     rawTagEditor.state = function(_) {
65678         if (!arguments.length) return state;
65679         state = _;
65680         return rawTagEditor;
65681     };
65682
65683
65684     rawTagEditor.preset = function(_) {
65685         if (!arguments.length) return preset;
65686         preset = _;
65687         if (preset.isFallback()) {
65688             expanded = true;
65689             updatePreference = false;
65690         } else {
65691             expanded = context.storage('raw_tag_editor.expanded') === 'true';
65692             updatePreference = true;
65693         }
65694         return rawTagEditor;
65695     };
65696
65697
65698     rawTagEditor.tags = function(_) {
65699         if (!arguments.length) return tags;
65700         tags = _;
65701         return rawTagEditor;
65702     };
65703
65704
65705     rawTagEditor.entityID = function(_) {
65706         if (!arguments.length) return id;
65707         id = _;
65708         return rawTagEditor;
65709     };
65710
65711
65712     rawTagEditor.expanded = function(_) {
65713         if (!arguments.length) return expanded;
65714         expanded = _;
65715         updatePreference = false;
65716         return rawTagEditor;
65717     };
65718
65719
65720     rawTagEditor.readOnlyTags = function(_) {
65721         if (!arguments.length) return readOnlyTags;
65722         readOnlyTags = _;
65723         return rawTagEditor;
65724     };
65725
65726
65727     return utilRebind(rawTagEditor, dispatch$$1, 'on');
65728 }
65729
65730 function uiFieldCheck(field, context) {
65731     var dispatch$$1 = dispatch('change'),
65732         options = field.strings && field.strings.options,
65733         values$$1 = [],
65734         texts = [],
65735         input = select(null),
65736         text$$1 = select(null),
65737         label = select(null),
65738         reverser = select(null),
65739         impliedYes,
65740         entityId,
65741         value;
65742
65743
65744     if (options) {
65745         for (var k in options) {
65746             values$$1.push(k === 'undefined' ? undefined : k);
65747             texts.push(field.t('options.' + k, { 'default': options[k] }));
65748         }
65749     } else {
65750         values$$1 = [undefined, 'yes'];
65751         texts = [t('inspector.unknown'), t('inspector.check.yes')];
65752         if (field.type !== 'defaultCheck') {
65753             values$$1.push('no');
65754             texts.push(t('inspector.check.no'));
65755         }
65756     }
65757
65758
65759     // Checks tags to see whether an undefined value is "Assumed to be Yes"
65760     function checkImpliedYes() {
65761         impliedYes = (field.id === 'oneway_yes');
65762
65763         // hack: pretend `oneway` field is a `oneway_yes` field
65764         // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
65765         if (field.id === 'oneway') {
65766             var entity = context.entity(entityId);
65767             for (var key in entity.tags) {
65768                 if (key in osmOneWayTags && (entity.tags[key] in osmOneWayTags[key])) {
65769                     impliedYes = true;
65770                     texts[0] = t('presets.fields.oneway_yes.options.undefined');
65771                     break;
65772                 }
65773             }
65774         }
65775     }
65776
65777
65778     function reverserHidden() {
65779         if (!select('div.inspector-hover').empty()) return true;
65780         return !(value === 'yes' || (impliedYes && !value));
65781     }
65782
65783
65784     function reverserSetText(selection$$1) {
65785         var entity = context.hasEntity(entityId);
65786         if (reverserHidden() || !entity) return selection$$1;
65787
65788         var first = entity.first(),
65789             last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last(),
65790             pseudoDirection = first < last,
65791             icon = pseudoDirection ? '#icon-forward' : '#icon-backward';
65792
65793         selection$$1.selectAll('.reverser-span')
65794             .text(t('inspector.check.reverser'))
65795             .call(svgIcon(icon, 'inline'));
65796
65797         return selection$$1;
65798     }
65799
65800
65801     var check = function(selection$$1) {
65802         checkImpliedYes();
65803         selection$$1.classed('checkselect', 'true');
65804
65805         label = selection$$1.selectAll('.preset-input-wrap')
65806             .data([0]);
65807
65808         var enter = label.enter()
65809             .append('label')
65810             .attr('class', 'preset-input-wrap');
65811
65812         enter
65813             .append('input')
65814             .property('indeterminate', field.type !== 'defaultCheck')
65815             .attr('type', 'checkbox')
65816             .attr('id', 'preset-input-' + field.id);
65817
65818         enter
65819             .append('span')
65820             .text(texts[0])
65821             .attr('class', 'value');
65822
65823         if (field.type === 'onewayCheck') {
65824             enter
65825                 .append('a')
65826                 .attr('id', 'preset-input-' + field.id + '-reverser')
65827                 .attr('class', 'reverser button' + (reverserHidden() ? ' hide' : ''))
65828                 .attr('href', '#')
65829                 .append('span')
65830                 .attr('class', 'reverser-span');
65831         }
65832
65833         label = label.merge(enter);
65834         input = label.selectAll('input');
65835         text$$1 = label.selectAll('span.value');
65836
65837         input
65838             .on('click', function() {
65839                 var t$$1 = {};
65840                 t$$1[field.key] = values$$1[(values$$1.indexOf(value) + 1) % values$$1.length];
65841                 dispatch$$1.call('change', this, t$$1);
65842                 event.stopPropagation();
65843             });
65844
65845         if (field.type === 'onewayCheck') {
65846             reverser = label.selectAll('.reverser');
65847
65848             reverser
65849                 .call(reverserSetText)
65850                 .on('click', function() {
65851                     event.preventDefault();
65852                     event.stopPropagation();
65853                     context.perform(
65854                         actionReverse(entityId),
65855                         t('operations.reverse.annotation')
65856                     );
65857                     select(this)
65858                         .call(reverserSetText);
65859                 });
65860         }
65861     };
65862
65863
65864     check.entity = function(_) {
65865         if (!arguments.length) return context.hasEntity(entityId);
65866         entityId = _.id;
65867         return check;
65868     };
65869
65870
65871     check.tags = function(tags) {
65872         checkImpliedYes();
65873         value = tags[field.key] && tags[field.key].toLowerCase();
65874
65875         if (field.type === 'onewayCheck' && (value === '1' || value === '-1')) {
65876             value = 'yes';
65877         }
65878
65879         input
65880             .property('indeterminate', field.type !== 'defaultCheck' && !value)
65881             .property('checked', value === 'yes');
65882
65883         text$$1
65884             .text(texts[values$$1.indexOf(value)]);
65885
65886         label
65887             .classed('set', !!value);
65888
65889         if (field.type === 'onewayCheck') {
65890             reverser
65891                 .classed('hide', reverserHidden())
65892                 .call(reverserSetText);
65893         }
65894     };
65895
65896
65897     check.focus = function() {
65898         input.node().focus();
65899     };
65900
65901     return utilRebind(check, dispatch$$1, 'on');
65902 }
65903
65904 function uiFieldCombo(field, context) {
65905     var dispatch$$1 = dispatch('change'),
65906         nominatim = services.geocoder,
65907         taginfo = services.taginfo,
65908         isMulti = (field.type === 'multiCombo'),
65909         isNetwork = (field.type === 'networkCombo'),
65910         isSemi = (field.type === 'semiCombo'),
65911         optstrings = field.strings && field.strings.options,
65912         optarray = field.options,
65913         snake_case = (field.snake_case || (field.snake_case === undefined)),
65914         combobox = d3combobox()
65915             .container(context.container())
65916             .minItems(isMulti || isSemi ? 1 : 2),
65917         comboData = [],
65918         multiData = [],
65919         container,
65920         input,
65921         entity,
65922         country;
65923
65924     // ensure multiCombo field.key ends with a ':'
65925     if (isMulti && field.key.match(/:$/) === null) {
65926         field.key += ':';
65927     }
65928
65929
65930     function snake(s) {
65931         return s.replace(/\s+/g, '_');
65932     }
65933
65934     function unsnake(s) {
65935         return s.replace(/_+/g, ' ');
65936     }
65937
65938     function clean(s) {
65939         return s.split(';')
65940             .map(function(s) { return s.trim(); })
65941             .join(';');
65942     }
65943
65944
65945     // returns the tag value for a display value
65946     // (for multiCombo, dval should be the key suffix, not the entire key)
65947     function tagValue(dval) {
65948         dval = clean(dval || '');
65949
65950         if (optstrings) {
65951             var match = lodash.find(comboData, function(o) {
65952                 return o.key && clean(o.value) === dval;
65953             });
65954             if (match) {
65955                 return match.key;
65956             }
65957         }
65958
65959         if (field.type === 'typeCombo' && !dval) {
65960             return 'yes';
65961         }
65962
65963         return (snake_case ? snake(dval) : dval) || undefined;
65964     }
65965
65966
65967     // returns the display value for a tag value
65968     // (for multiCombo, tval should be the key suffix, not the entire key)
65969     function displayValue(tval) {
65970         tval = tval || '';
65971
65972         if (optstrings) {
65973             var match = lodash.find(comboData, function(o) { return o.key === tval && o.value; });
65974             if (match) {
65975                 return match.value;
65976             }
65977         }
65978
65979         if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
65980             return '';
65981         }
65982
65983         return snake_case ? unsnake(tval) : tval;
65984     }
65985
65986
65987     function objectDifference(a, b) {
65988         return lodash.reject(a, function(d1) {
65989             return lodash.some(b, function(d2) { return d1.value === d2.value; });
65990         });
65991     }
65992
65993
65994     function initCombo(selection$$1, attachTo) {
65995         if (optstrings) {
65996             selection$$1.attr('readonly', 'readonly');
65997             selection$$1.call(combobox, attachTo);
65998             setStaticValues(setPlaceholder);
65999
66000         } else if (optarray) {
66001             selection$$1.call(combobox, attachTo);
66002             setStaticValues(setPlaceholder);
66003
66004         } else if (taginfo) {
66005             selection$$1.call(combobox.fetcher(setTaginfoValues), attachTo);
66006             setTaginfoValues('', setPlaceholder);
66007         }
66008     }
66009
66010
66011     function setStaticValues(callback) {
66012         if (!(optstrings || optarray)) return;
66013
66014         if (optstrings) {
66015             comboData = Object.keys(optstrings).map(function(k) {
66016                 var v = field.t('options.' + k, { 'default': optstrings[k] });
66017                 return {
66018                     key: k,
66019                     value: v,
66020                     title: v
66021                 };
66022             });
66023
66024         } else if (optarray) {
66025             comboData = optarray.map(function(k) {
66026                 var v = snake_case ? unsnake(k) : k;
66027                 return {
66028                     key: k,
66029                     value: v,
66030                     title: v
66031                 };
66032             });
66033         }
66034
66035         combobox.data(objectDifference(comboData, multiData));
66036         if (callback) callback(comboData);
66037     }
66038
66039
66040     function setTaginfoValues(q, callback) {
66041         var fn = isMulti ? 'multikeys' : 'values';
66042         var query = (isMulti ? field.key : '') + q;
66043         var hasCountryPrefix = isNetwork && country && country.indexOf(q.toLowerCase()) === 0;
66044         if (hasCountryPrefix) {
66045             query = country + ':';
66046         }
66047
66048         taginfo[fn]({
66049             debounce: (q !== ''),
66050             key: field.key,
66051             geometry: context.geometry(entity.id),
66052             query: query
66053         }, function(err, data) {
66054             if (err) return;
66055             if (hasCountryPrefix) {
66056                 data = lodash.filter(data, function(d) {
66057                     return d.value.toLowerCase().indexOf(country + ':') === 0;
66058                 });
66059             }
66060
66061             comboData = lodash.map(data, function(d) {
66062                 var k = d.value;
66063                 if (isMulti) k = k.replace(field.key, '');
66064                 var v = snake_case ? unsnake(k) : k;
66065                 return {
66066                     key: k,
66067                     value: v,
66068                     title: isMulti ? v : d.title
66069                 };
66070             });
66071
66072             comboData = objectDifference(comboData, multiData);
66073             if (callback) callback(comboData);
66074         });
66075     }
66076
66077
66078     function setPlaceholder(d) {
66079         var ph;
66080
66081         if (isMulti || isSemi) {
66082             ph = field.placeholder() || t('inspector.add');
66083         } else {
66084             var vals = lodash.map(d, 'value').filter(function(s) { return s.length < 20; }),
66085                 placeholders = vals.length > 1 ? vals : lodash.map(d, 'key');
66086             ph = field.placeholder() || placeholders.slice(0, 3).join(', ');
66087         }
66088
66089         if (ph.match(/(…|\.\.\.)$/) === null) {
66090             ph += '…';
66091         }
66092
66093         container.selectAll('input')
66094             .attr('placeholder', ph);
66095     }
66096
66097
66098     function change() {
66099         var val = tagValue(utilGetSetValue(input)),
66100             t$$1 = {};
66101
66102         if (isMulti || isSemi) {
66103             if (!val) return;
66104             container.classed('active', false);
66105             utilGetSetValue(input, '');
66106             if (isMulti) {
66107                 field.keys.push(field.key + val);
66108                 t$$1[field.key + val] = 'yes';
66109             } else if (isSemi) {
66110                 var arr = multiData.map(function(d) { return d.key; });
66111                 arr.push(val);
66112                 t$$1[field.key] = lodash.compact(lodash.uniq(arr)).join(';');
66113             }
66114             window.setTimeout(function() { input.node().focus(); }, 10);
66115
66116         } else {
66117             t$$1[field.key] = val;
66118         }
66119
66120         dispatch$$1.call('change', this, t$$1);
66121     }
66122
66123
66124     function removeMultikey(d) {
66125         event.stopPropagation();
66126         var t$$1 = {};
66127         if (isMulti) {
66128             t$$1[d.key] = undefined;
66129         } else if (isSemi) {
66130             lodash.remove(multiData, function(md) { return md.key === d.key; });
66131             var arr = multiData.map(function(md) { return md.key; });
66132             arr = lodash.compact(lodash.uniq(arr));
66133             t$$1[field.key] = arr.length ? arr.join(';') : undefined;
66134         }
66135         dispatch$$1.call('change', this, t$$1);
66136     }
66137
66138
66139     function combo(selection$$1) {
66140         if (isMulti || isSemi) {
66141             container = selection$$1.selectAll('ul').data([0]);
66142
66143             container = container.enter()
66144                 .append('ul')
66145                 .attr('class', 'form-field-multicombo')
66146                 .on('click', function() {
66147                     window.setTimeout(function() { input.node().focus(); }, 10);
66148                 })
66149                 .merge(container);
66150
66151         } else {
66152             container = selection$$1;
66153         }
66154
66155         input = container.selectAll('input')
66156             .data([0]);
66157
66158         input = input.enter()
66159             .append('input')
66160             .attr('type', 'text')
66161             .attr('id', 'preset-input-' + field.id)
66162             .call(utilNoAuto)
66163             .call(initCombo, selection$$1)
66164             .merge(input);
66165
66166         if (isNetwork && nominatim && entity) {
66167             var center = entity.extent(context.graph()).center();
66168             nominatim.countryCode(center, function (err, code) {
66169                 country = code;
66170             });
66171         }
66172
66173         input
66174             .on('change', change)
66175             .on('blur', change);
66176
66177         if (isMulti || isSemi) {
66178             combobox
66179                 .on('accept', function() {
66180                     input.node().blur();
66181                     input.node().focus();
66182                 });
66183
66184             input
66185                 .on('focus', function() { container.classed('active', true); });
66186         }
66187     }
66188
66189
66190     combo.tags = function(tags) {
66191         if (isMulti || isSemi) {
66192             multiData = [];
66193
66194             if (isMulti) {
66195                 // Build multiData array containing keys already set..
66196                 Object.keys(tags).forEach(function(key) {
66197                     if (key.indexOf(field.key) !== 0 || tags[key].toLowerCase() !== 'yes') return;
66198
66199                     var suffix = key.substring(field.key.length);
66200                     multiData.push({
66201                         key: key,
66202                         value: displayValue(suffix)
66203                     });
66204                 });
66205
66206                 // Set keys for form-field modified (needed for undo and reset buttons)..
66207                 field.keys = lodash.map(multiData, 'key');
66208
66209             } else if (isSemi) {
66210                 var arr = lodash.compact(lodash.uniq((tags[field.key] || '').split(';')));
66211                 multiData = arr.map(function(key) {
66212                     return {
66213                         key: key,
66214                         value: displayValue(key)
66215                     };
66216                 });
66217             }
66218
66219             // Exclude existing multikeys from combo options..
66220             var available = objectDifference(comboData, multiData);
66221             combobox.data(available);
66222
66223             // Hide 'Add' button if this field uses fixed set of
66224             // translateable optstrings and they're all currently used..
66225             container.selectAll('.combobox-input, .combobox-caret')
66226                 .classed('hide', optstrings && !available.length);
66227
66228
66229             // Render chips
66230             var chips = container.selectAll('.chips')
66231                 .data(multiData);
66232
66233             chips.exit()
66234                 .remove();
66235
66236             var enter = chips.enter()
66237                 .insert('li', 'input')
66238                 .attr('class', 'chips');
66239
66240             enter.append('span');
66241             enter.append('a');
66242
66243             chips = chips.merge(enter);
66244
66245             chips.select('span')
66246                 .text(function(d) { return d.value; });
66247
66248             chips.select('a')
66249                 .on('click', removeMultikey)
66250                 .attr('class', 'remove')
66251                 .text('×');
66252
66253         } else {
66254             utilGetSetValue(input, displayValue(tags[field.key]));
66255         }
66256     };
66257
66258
66259     combo.focus = function() {
66260         input.node().focus();
66261     };
66262
66263
66264     combo.entity = function(_) {
66265         if (!arguments.length) return entity;
66266         entity = _;
66267         return combo;
66268     };
66269
66270
66271     return utilRebind(combo, dispatch$$1, 'on');
66272 }
66273
66274 function uiFieldText(field, context) {
66275     var dispatch$$1 = dispatch('change'),
66276         nominatim = services.geocoder,
66277         input,
66278         entity;
66279
66280
66281     function i(selection$$1) {
66282         var fieldId = 'preset-input-' + field.id;
66283
66284         input = selection$$1.selectAll('input')
66285             .data([0]);
66286
66287         input = input.enter()
66288             .append('input')
66289             .attr('type', field.type)
66290             .attr('id', fieldId)
66291             .attr('placeholder', field.placeholder() || t('inspector.unknown'))
66292             .call(utilNoAuto)
66293             .merge(input);
66294
66295         input
66296             .on('input', change(true))
66297             .on('blur', change())
66298             .on('change', change());
66299
66300         if (field.type === 'tel' && nominatim && entity) {
66301             var center = entity.extent(context.graph()).center();
66302             nominatim.countryCode(center, function (err, countryCode) {
66303                 if (err || !dataPhoneFormats[countryCode]) return;
66304                 selection$$1.selectAll('#' + fieldId)
66305                     .attr('placeholder', dataPhoneFormats[countryCode]);
66306             });
66307
66308         } else if (field.type === 'number') {
66309             input.attr('type', 'text');
66310
66311             var spinControl = selection$$1.selectAll('.spin-control')
66312                 .data([0]);
66313
66314             var enter = spinControl.enter()
66315                 .append('div')
66316                 .attr('class', 'spin-control');
66317
66318             enter
66319                 .append('button')
66320                 .datum(-1)
66321                 .attr('class', 'decrement')
66322                 .attr('tabindex', -1);
66323
66324             enter
66325                 .append('button')
66326                 .datum(1)
66327                 .attr('class', 'increment')
66328                 .attr('tabindex', -1);
66329
66330             spinControl = spinControl
66331                 .merge(enter);
66332
66333             spinControl.selectAll('button')
66334                 .on('click', function(d) {
66335                     event.preventDefault();
66336                     var num = parseInt(input.node().value || 0, 10);
66337                     if (!isNaN(num)) input.node().value = num + d;
66338                     change()();
66339                 });
66340         }
66341     }
66342
66343
66344     function change(onInput) {
66345         return function() {
66346             var t$$1 = {};
66347             t$$1[field.key] = utilGetSetValue(input) || undefined;
66348             dispatch$$1.call('change', this, t$$1, onInput);
66349         };
66350     }
66351
66352
66353     i.entity = function(_) {
66354         if (!arguments.length) return entity;
66355         entity = _;
66356         return i;
66357     };
66358
66359
66360     i.tags = function(tags) {
66361         utilGetSetValue(input, tags[field.key] || '');
66362     };
66363
66364
66365     i.focus = function() {
66366         var node = input.node();
66367         if (node) node.focus();
66368     };
66369
66370     return utilRebind(i, dispatch$$1, 'on');
66371 }
66372
66373 function uiFieldAccess(field, context) {
66374     var dispatch$$1 = dispatch('change'),
66375         items;
66376
66377     function access(selection$$1) {
66378         var wrap = selection$$1.selectAll('.preset-input-wrap')
66379             .data([0]);
66380
66381         wrap = wrap.enter()
66382             .append('div')
66383             .attr('class', 'cf preset-input-wrap')
66384             .append('ul')
66385             .merge(wrap);
66386
66387         var list = wrap.selectAll('ul')
66388             .data([0]);
66389
66390         list = list.enter()
66391             .append('ul')
66392             .merge(list);
66393
66394
66395         items = list.selectAll('li')
66396             .data(field.keys);
66397
66398         // Enter
66399         var enter = items.enter()
66400             .append('li')
66401             .attr('class', function(d) { return 'cf preset-access-' + d; });
66402
66403         enter
66404             .append('span')
66405             .attr('class', 'col6 label preset-label-access')
66406             .attr('for', function(d) { return 'preset-input-access-' + d; })
66407             .text(function(d) { return field.t('types.' + d); });
66408
66409         enter
66410             .append('div')
66411             .attr('class', 'col6 preset-input-access-wrap')
66412             .append('input')
66413             .attr('type', 'text')
66414             .attr('class', 'preset-input-access')
66415             .attr('id', function(d) { return 'preset-input-access-' + d; })
66416             .call(utilNoAuto)
66417             .each(function(d) {
66418                 select(this)
66419                     .call(d3combobox()
66420                         .container(context.container())
66421                         .data(access.options(d))
66422                     );
66423             });
66424
66425
66426         // Update
66427         items = items.merge(enter);
66428
66429         wrap.selectAll('.preset-input-access')
66430             .on('change', change)
66431             .on('blur', change);
66432     }
66433
66434
66435     function change(d) {
66436         var tag = {};
66437         tag[d] = utilGetSetValue(select(this)) || undefined;
66438         dispatch$$1.call('change', this, tag);
66439     }
66440
66441
66442     access.options = function(type) {
66443         var options = ['no', 'permissive', 'private', 'destination'];
66444
66445         if (type !== 'access') {
66446             options.unshift('yes');
66447             options.push('designated');
66448
66449             if (type === 'bicycle') {
66450                 options.push('dismount');
66451             }
66452         }
66453
66454         return options.map(function(option) {
66455             return {
66456                 title: field.t('options.' + option + '.description'),
66457                 value: option
66458             };
66459         });
66460     };
66461
66462
66463     var placeholders = {
66464         footway: {
66465             foot: 'designated',
66466             motor_vehicle: 'no'
66467         },
66468         steps: {
66469             foot: 'yes',
66470             motor_vehicle: 'no',
66471             bicycle: 'no',
66472             horse: 'no'
66473         },
66474         pedestrian: {
66475             foot: 'yes',
66476             motor_vehicle: 'no'
66477         },
66478         cycleway: {
66479             motor_vehicle: 'no',
66480             bicycle: 'designated'
66481         },
66482         bridleway: {
66483             motor_vehicle: 'no',
66484             horse: 'designated'
66485         },
66486         path: {
66487             foot: 'yes',
66488             motor_vehicle: 'no',
66489             bicycle: 'yes',
66490             horse: 'yes'
66491         },
66492         motorway: {
66493             foot: 'no',
66494             motor_vehicle: 'yes',
66495             bicycle: 'no',
66496             horse: 'no'
66497         },
66498         trunk: {
66499             motor_vehicle: 'yes'
66500         },
66501         primary: {
66502             foot: 'yes',
66503             motor_vehicle: 'yes',
66504             bicycle: 'yes',
66505             horse: 'yes'
66506         },
66507         secondary: {
66508             foot: 'yes',
66509             motor_vehicle: 'yes',
66510             bicycle: 'yes',
66511             horse: 'yes'
66512         },
66513         tertiary: {
66514             foot: 'yes',
66515             motor_vehicle: 'yes',
66516             bicycle: 'yes',
66517             horse: 'yes'
66518         },
66519         residential: {
66520             foot: 'yes',
66521             motor_vehicle: 'yes',
66522             bicycle: 'yes',
66523             horse: 'yes'
66524         },
66525         unclassified: {
66526             foot: 'yes',
66527             motor_vehicle: 'yes',
66528             bicycle: 'yes',
66529             horse: 'yes'
66530         },
66531         service: {
66532             foot: 'yes',
66533             motor_vehicle: 'yes',
66534             bicycle: 'yes',
66535             horse: 'yes'
66536         },
66537         motorway_link: {
66538             foot: 'no',
66539             motor_vehicle: 'yes',
66540             bicycle: 'no',
66541             horse: 'no'
66542         },
66543         trunk_link: {
66544             motor_vehicle: 'yes'
66545         },
66546         primary_link: {
66547             foot: 'yes',
66548             motor_vehicle: 'yes',
66549             bicycle: 'yes',
66550             horse: 'yes'
66551         },
66552         secondary_link: {
66553             foot: 'yes',
66554             motor_vehicle: 'yes',
66555             bicycle: 'yes',
66556             horse: 'yes'
66557         },
66558         tertiary_link: {
66559             foot: 'yes',
66560             motor_vehicle: 'yes',
66561             bicycle: 'yes',
66562             horse: 'yes'
66563         }
66564     };
66565
66566
66567     access.tags = function(tags) {
66568         utilGetSetValue(items.selectAll('.preset-input-access'),
66569             function(d) { return tags[d] || ''; })
66570             .attr('placeholder', function() {
66571                 return tags.access ? tags.access : field.placeholder();
66572             });
66573
66574         items.selectAll('#preset-input-access-access')
66575             .attr('placeholder', 'yes');
66576
66577         lodash.forEach(placeholders[tags.highway], function(v, k) {
66578             items.selectAll('#preset-input-access-' + k)
66579                 .attr('placeholder', function() { return (tags.access || v); });
66580         });
66581     };
66582
66583
66584     access.focus = function() {
66585         items.selectAll('.preset-input-access')
66586             .node().focus();
66587     };
66588
66589
66590     return utilRebind(access, dispatch$$1, 'on');
66591 }
66592
66593 function uiFieldAddress(field, context) {
66594     var dispatch$$1 = dispatch('init', 'change'),
66595         nominatim = services.geocoder,
66596         wrap = select(null),
66597         isInitialized = false,
66598         entity;
66599
66600     function getNearStreets() {
66601         var extent$$1 = entity.extent(context.graph()),
66602             l = extent$$1.center(),
66603             box = geoExtent$$1(l).padByMeters(200);
66604
66605         var streets = context.intersects(box)
66606             .filter(isAddressable)
66607             .map(function(d) {
66608                 var loc = context.projection([
66609                     (extent$$1[0][0] + extent$$1[1][0]) / 2,
66610                     (extent$$1[0][1] + extent$$1[1][1]) / 2]),
66611                     choice = geoChooseEdge(context.childNodes(d), loc, context.projection);
66612                 return {
66613                     title: d.tags.name,
66614                     value: d.tags.name,
66615                     dist: choice.distance
66616                 };
66617             })
66618             .sort(function(a, b) {
66619                 return a.dist - b.dist;
66620             });
66621
66622         return lodash.uniqBy(streets, 'value');
66623
66624         function isAddressable(d) {
66625             return d.tags.highway && d.tags.name && d.type === 'way';
66626         }
66627     }
66628
66629
66630     function getNearCities() {
66631         var extent$$1 = entity.extent(context.graph()),
66632             l = extent$$1.center(),
66633             box = geoExtent$$1(l).padByMeters(200);
66634
66635         var cities = context.intersects(box)
66636             .filter(isAddressable)
66637             .map(function(d) {
66638                 return {
66639                     title: d.tags['addr:city'] || d.tags.name,
66640                     value: d.tags['addr:city'] || d.tags.name,
66641                     dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
66642                 };
66643             })
66644             .sort(function(a, b) {
66645                 return a.dist - b.dist;
66646             });
66647
66648         return lodash.uniqBy(cities, 'value');
66649
66650
66651         function isAddressable(d) {
66652             if (d.tags.name &&
66653                 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
66654                 return true;
66655
66656             if (d.tags.place && d.tags.name && (
66657                     d.tags.place === 'city' ||
66658                     d.tags.place === 'town' ||
66659                     d.tags.place === 'village'))
66660                 return true;
66661
66662             if (d.tags['addr:city']) return true;
66663
66664             return false;
66665         }
66666     }
66667
66668     function getNearValues(key) {
66669         var extent$$1 = entity.extent(context.graph()),
66670             l = extent$$1.center(),
66671             box = geoExtent$$1(l).padByMeters(200);
66672
66673         var results = context.intersects(box)
66674             .filter(function hasTag(d) {
66675                 return d.tags[key];
66676             })
66677             .map(function(d) {
66678                 return {
66679                     title: d.tags[key],
66680                     value: d.tags[key],
66681                     dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
66682                 };
66683             })
66684             .sort(function(a, b) {
66685                 return a.dist - b.dist;
66686             });
66687
66688         return lodash.uniqBy(results, 'value');
66689     }
66690
66691
66692     function initCallback(err, countryCode) {
66693         if (err) return;
66694
66695         var addressFormat = lodash.find(dataAddressFormats, function (a) {
66696             return a && a.countryCodes && lodash.includes(a.countryCodes, countryCode.toLowerCase());
66697         }) || lodash.first(dataAddressFormats);
66698
66699         var widths = addressFormat.widths || {
66700             housenumber: 1/3, street: 2/3,
66701             city: 2/3, state: 1/4, postcode: 1/3
66702         };
66703
66704         function row(r) {
66705             // Normalize widths.
66706             var total = lodash.reduce(r, function(sum$$1, field) {
66707                 return sum$$1 + (widths[field] || 0.5);
66708             }, 0);
66709
66710             return r.map(function (field) {
66711                 return {
66712                     id: field,
66713                     width: (widths[field] || 0.5) / total
66714                 };
66715             });
66716         }
66717
66718         wrap.selectAll('div.addr-row')
66719             .data(addressFormat.format)
66720             .enter()
66721             .append('div')
66722             .attr('class', 'addr-row')
66723             .selectAll('input')
66724             .data(row)
66725             .enter()
66726             .append('input')
66727             .property('type', 'text')
66728             .attr('placeholder', function (d) {
66729                 var localkey = d.id + '!' + countryCode.toLowerCase(),
66730                     tkey = field.strings.placeholders[localkey] ? localkey : d.id;
66731                 return field.t('placeholders.' + tkey);
66732             })
66733             .attr('class', function (d) { return 'addr-' + d.id; })
66734             .call(utilNoAuto)
66735             .style('width', function (d) { return d.width * 100 + '%'; });
66736
66737         // Update
66738
66739         // setup dropdowns for common address tags
66740         var dropdowns = addressFormat.dropdowns || [
66741             'city', 'county', 'country', 'district', 'hamlet',
66742             'neighbourhood', 'place', 'postcode', 'province',
66743             'quarter', 'state', 'street', 'subdistrict', 'suburb'
66744         ];
66745
66746         // If fields exist for any of these tags, create dropdowns to pick nearby values..
66747         dropdowns.forEach(function(tag) {
66748             var nearValues = (tag === 'street') ? getNearStreets
66749                     : (tag === 'city') ? getNearCities
66750                     : getNearValues;
66751
66752             wrap.selectAll('input.addr-' + tag)
66753                 .call(d3combobox()
66754                     .container(context.container())
66755                     .minItems(1)
66756                     .fetcher(function(value, callback) {
66757                         callback(nearValues('addr:' + tag));
66758                     })
66759                 );
66760         });
66761
66762         wrap.selectAll('input')
66763             .on('blur', change())
66764             .on('change', change());
66765
66766         wrap.selectAll('input:not(.combobox-input)')
66767             .on('input', change(true));
66768
66769         dispatch$$1.call('init');
66770         isInitialized = true;
66771     }
66772
66773
66774     function address(selection$$1) {
66775         isInitialized = false;
66776
66777         wrap = selection$$1.selectAll('.preset-input-wrap')
66778             .data([0]);
66779
66780         wrap = wrap.enter()
66781             .append('div')
66782             .attr('class', 'preset-input-wrap')
66783             .merge(wrap);
66784
66785         if (nominatim && entity) {
66786             var center = entity.extent(context.graph()).center();
66787             nominatim.countryCode(center, initCallback);
66788         }
66789     }
66790
66791
66792     function change(onInput) {
66793         return function() {
66794             var tags = {};
66795
66796             wrap.selectAll('input')
66797                 .each(function (field) {
66798                     tags['addr:' + field.id] = this.value || undefined;
66799                 });
66800
66801             dispatch$$1.call('change', this, tags, onInput);
66802         };
66803     }
66804
66805
66806     function updateTags(tags) {
66807         utilGetSetValue(wrap.selectAll('input'), function (field) {
66808             return tags['addr:' + field.id] || '';
66809         });
66810     }
66811
66812
66813     address.entity = function(_) {
66814         if (!arguments.length) return entity;
66815         entity = _;
66816         return address;
66817     };
66818
66819
66820     address.tags = function(tags) {
66821         if (isInitialized) {
66822             updateTags(tags);
66823         } else {
66824             dispatch$$1.on('init', function () {
66825                 dispatch$$1.on('init', null);
66826                 updateTags(tags);
66827             });
66828         }
66829     };
66830
66831
66832     address.focus = function() {
66833         var node = wrap.selectAll('input').node();
66834         if (node) node.focus();
66835     };
66836
66837
66838     return utilRebind(address, dispatch$$1, 'on');
66839 }
66840
66841 function uiFieldCycleway(field, context) {
66842     var dispatch$$1 = dispatch('change'),
66843         items = select(null);
66844
66845
66846     function cycleway(selection$$1) {
66847
66848         function stripcolon(s) {
66849             return s.replace(':', '');
66850         }
66851
66852
66853         var wrap = selection$$1.selectAll('.preset-input-wrap')
66854             .data([0]);
66855
66856         wrap = wrap.enter()
66857             .append('div')
66858             .attr('class', 'cf preset-input-wrap')
66859             .merge(wrap);
66860
66861
66862         var div = wrap.selectAll('ul')
66863             .data([0]);
66864
66865         div = div.enter()
66866             .append('ul')
66867             .merge(div);
66868
66869
66870         items = div.selectAll('li')
66871             .data(field.keys);
66872
66873         var enter = items.enter()
66874             .append('li')
66875             .attr('class', function(d) { return 'cf preset-cycleway-' + stripcolon(d); });
66876
66877         enter
66878             .append('span')
66879             .attr('class', 'col6 label preset-label-cycleway')
66880             .attr('for', function(d) { return 'preset-input-cycleway-' + stripcolon(d); })
66881             .text(function(d) { return field.t('types.' + d); });
66882
66883         enter
66884             .append('div')
66885             .attr('class', 'col6 preset-input-cycleway-wrap')
66886             .append('input')
66887             .attr('type', 'text')
66888             .attr('class', function(d) { return 'preset-input-cycleway preset-input-' + stripcolon(d); })
66889             .call(utilNoAuto)
66890             .each(function(d) {
66891                 select(this)
66892                     .call(d3combobox()
66893                         .container(context.container())
66894                         .data(cycleway.options(d))
66895                     );
66896             });
66897
66898
66899         // Update
66900         wrap.selectAll('.preset-input-cycleway')
66901             .on('change', change)
66902             .on('blur', change);
66903     }
66904
66905
66906     function change() {
66907         var left = utilGetSetValue(select('.preset-input-cyclewayleft')),
66908             right = utilGetSetValue(select('.preset-input-cyclewayright')),
66909             tag = {};
66910
66911         if (left === 'none' || left === '') { left = undefined; }
66912         if (right === 'none' || right === '') { right = undefined; }
66913
66914         // Always set both left and right as changing one can affect the other
66915         tag = {
66916             cycleway: undefined,
66917             'cycleway:left': left,
66918             'cycleway:right': right
66919         };
66920
66921         // If the left and right tags match, use the cycleway tag to tag both
66922         // sides the same way
66923         if (left === right) {
66924             tag = {
66925                 cycleway: left,
66926                 'cycleway:left': undefined,
66927                 'cycleway:right': undefined
66928             };
66929         }
66930
66931         dispatch$$1.call('change', this, tag);
66932     }
66933
66934
66935     cycleway.options = function() {
66936         return keys(field.strings.options).map(function(option) {
66937             return {
66938                 title: field.t('options.' + option + '.description'),
66939                 value: option
66940             };
66941         });
66942     };
66943
66944
66945     cycleway.tags = function(tags) {
66946         utilGetSetValue(items.selectAll('.preset-input-cycleway'), function(d) {
66947                 // If cycleway is set, always return that
66948                 if (tags.cycleway) {
66949                     return tags.cycleway;
66950                 }
66951                 return tags[d] || '';
66952             })
66953             .attr('placeholder', field.placeholder());
66954     };
66955
66956
66957     cycleway.focus = function() {
66958         items.selectAll('.preset-input-cycleway')
66959             .node().focus();
66960     };
66961
66962
66963     return utilRebind(cycleway, dispatch$$1, 'on');
66964 }
66965
66966 function uiFieldLanes(field, context) {
66967     var dispatch$$1 = dispatch('change'),
66968         LANE_WIDTH = 40,
66969         LANE_HEIGHT = 200,
66970         wayID,
66971         lanesData;
66972
66973     function lanes(selection$$1) {
66974         lanesData = context.entity(wayID).lanes();
66975
66976         if (!select('.inspector-wrap.inspector-hidden').empty() || !selection$$1.node().parentNode) {
66977             selection$$1.call(lanes.off);
66978             return;
66979         }
66980
66981         var wrap = selection$$1.selectAll('.preset-input-wrap')
66982             .data([0]);
66983
66984         wrap = wrap.enter()
66985             .append('div')
66986             .attr('class', 'preset-input-wrap')
66987             .merge(wrap);
66988
66989         var surface =  wrap.selectAll('.surface')
66990             .data([0]);
66991
66992         var d = utilGetDimensions(wrap);
66993         var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
66994
66995         surface = surface.enter()
66996             .append('svg')
66997             .attr('width', d[0])
66998             .attr('height', 300)
66999             .attr('class', 'surface')
67000             .merge(surface);
67001
67002
67003         var lanesSelection = surface.selectAll('.lanes')
67004             .data([0]);
67005
67006         lanesSelection = lanesSelection.enter()
67007             .append('g')
67008             .attr('class', 'lanes')
67009             .merge(lanesSelection);
67010
67011         lanesSelection
67012             .attr('transform', function () {
67013                 return 'translate(' + (freeSpace / 2) + ', 0)';
67014             });
67015
67016
67017         var lane = lanesSelection.selectAll('.lane')
67018            .data(lanesData.lanes);
67019
67020         lane.exit()
67021             .remove();
67022
67023         var enter = lane.enter()
67024             .append('g')
67025             .attr('class', 'lane');
67026
67027         enter
67028             .append('g')
67029             .append('rect')
67030             .attr('y', 50)
67031             .attr('width', LANE_WIDTH)
67032             .attr('height', LANE_HEIGHT);
67033
67034         enter
67035             .append('g')
67036             .attr('class', 'forward')
67037             .append('text')
67038             .attr('y', 40)
67039             .attr('x', 14)
67040             .text('▲');
67041
67042         enter
67043             .append('g')
67044             .attr('class', 'bothways')
67045             .append('text')
67046             .attr('y', 40)
67047             .attr('x', 14)
67048             .text('▲▼');
67049
67050         enter
67051             .append('g')
67052             .attr('class', 'backward')
67053             .append('text')
67054             .attr('y', 40)
67055             .attr('x', 14)
67056             .text('▼');
67057
67058
67059         lane = lane
67060             .merge(enter);
67061
67062         lane
67063             .attr('transform', function(d) {
67064                 return 'translate(' + (LANE_WIDTH * d.index * 1.5) + ', 0)';
67065             });
67066
67067         lane.select('.forward')
67068             .style('visibility', function(d) {
67069                 return d.direction === 'forward' ? 'visible' : 'hidden';
67070             });
67071
67072         lane.select('.bothways')
67073             .style('visibility', function(d) {
67074                 return d.direction === 'bothways' ? 'visible' : 'hidden';
67075             });
67076
67077         lane.select('.backward')
67078             .style('visibility', function(d) {
67079                 return d.direction === 'backward' ? 'visible' : 'hidden';
67080             });
67081     }
67082
67083
67084     lanes.entity = function(_) {
67085         if (!wayID || wayID !== _.id) {
67086             wayID = _.id;
67087         }
67088     };
67089
67090     lanes.tags = function() {};
67091     lanes.focus = function() {};
67092     lanes.off = function() {};
67093
67094     return utilRebind(lanes, dispatch$$1, 'on');
67095 }
67096
67097 function uiFieldLocalized(field, context) {
67098     var dispatch$$1 = dispatch('change', 'input'),
67099         wikipedia = services.wikipedia,
67100         input = select(null),
67101         localizedInputs = select(null),
67102         wikiTitles,
67103         entity;
67104
67105
67106     function localized(selection$$1) {
67107         input = selection$$1.selectAll('.localized-main')
67108             .data([0]);
67109
67110         input = input.enter()
67111             .append('input')
67112             .attr('type', 'text')
67113             .attr('id', 'preset-input-' + field.id)
67114             .attr('class', 'localized-main')
67115             .attr('placeholder', field.placeholder())
67116             .call(utilNoAuto)
67117             .merge(input);
67118
67119         if (field.id === 'name') {
67120             var preset = context.presets().match(entity, context.graph());
67121             input
67122                 .call(d3combobox()
67123                     .container(context.container())
67124                     .fetcher(utilSuggestNames(preset, dataSuggestions))
67125                 );
67126         }
67127
67128         input
67129             .on('input', change(true))
67130             .on('blur', change())
67131             .on('change', change());
67132
67133
67134         var translateButton = selection$$1.selectAll('.localized-add')
67135             .data([0]);
67136
67137         translateButton = translateButton.enter()
67138             .append('button')
67139             .attr('class', 'button-input-action localized-add minor')
67140             .attr('tabindex', -1)
67141             .call(svgIcon('#icon-plus'))
67142             .call(tooltip()
67143                 .title(t('translate.translate'))
67144                 .placement('left'))
67145             .merge(translateButton);
67146
67147         translateButton
67148             .on('click', addNew);
67149
67150
67151         localizedInputs = selection$$1.selectAll('.localized-wrap')
67152             .data([0]);
67153
67154         localizedInputs = localizedInputs.enter().append('div')
67155             .attr('class', 'localized-wrap')
67156             .merge(localizedInputs);
67157     }
67158
67159
67160     function addNew() {
67161         event.preventDefault();
67162         var data$$1 = localizedInputs.selectAll('div.entry').data();
67163         var defaultLang = utilDetect().locale.toLowerCase().split('-')[0];
67164         var langExists = lodash.find(data$$1, function(datum) { return datum.lang === defaultLang;});
67165         var isLangEn = defaultLang.indexOf('en') > -1;
67166         if (isLangEn || langExists) {
67167             defaultLang = '';
67168         }
67169         data$$1.push({ lang: defaultLang, value: '' });
67170         localizedInputs.call(render, data$$1);
67171     }
67172
67173
67174     function change(onInput) {
67175         return function() {
67176             var t$$1 = {};
67177             t$$1[field.key] = utilGetSetValue(select(this)) || undefined;
67178             dispatch$$1.call('change', this, t$$1, onInput);
67179         };
67180     }
67181
67182
67183     function key(lang) {
67184         return field.key + ':' + lang;
67185     }
67186
67187
67188     function changeLang(d) {
67189         var lang = utilGetSetValue(select(this)),
67190             t$$1 = {},
67191             language = lodash.find(dataWikipedia, function(d) {
67192                 return d[0].toLowerCase() === lang.toLowerCase() ||
67193                     d[1].toLowerCase() === lang.toLowerCase();
67194             });
67195
67196         if (language) lang = language[2];
67197
67198         if (d.lang && d.lang !== lang) {
67199             t$$1[key(d.lang)] = undefined;
67200         }
67201
67202         var value = utilGetSetValue(select(this.parentNode)
67203             .selectAll('.localized-value'));
67204
67205         if (lang && value) {
67206             t$$1[key(lang)] = value;
67207         } else if (lang && wikiTitles && wikiTitles[d.lang]) {
67208             t$$1[key(lang)] = wikiTitles[d.lang];
67209         }
67210
67211         d.lang = lang;
67212         dispatch$$1.call('change', this, t$$1);
67213     }
67214
67215
67216     function changeValue(d) {
67217         if (!d.lang) return;
67218         var t$$1 = {};
67219         t$$1[key(d.lang)] = utilGetSetValue(select(this)) || undefined;
67220         dispatch$$1.call('change', this, t$$1);
67221     }
67222
67223
67224     function fetcher(value, cb) {
67225         var v = value.toLowerCase();
67226
67227         cb(dataWikipedia.filter(function(d) {
67228             return d[0].toLowerCase().indexOf(v) >= 0 ||
67229             d[1].toLowerCase().indexOf(v) >= 0 ||
67230             d[2].toLowerCase().indexOf(v) >= 0;
67231         }).map(function(d) {
67232             return { value: d[1] };
67233         }));
67234     }
67235
67236
67237     function render(selection$$1, data$$1) {
67238         var wraps = selection$$1.selectAll('div.entry').
67239             data(data$$1, function(d) { return d.lang; });
67240
67241         wraps.exit()
67242             .transition()
67243             .duration(200)
67244             .style('max-height','0px')
67245             .style('opacity', '0')
67246             .style('top','-10px')
67247             .remove();
67248
67249         var innerWrap = wraps.enter()
67250             .insert('div', ':first-child');
67251
67252         innerWrap.attr('class', 'entry')
67253             .each(function() {
67254                 var wrap = select(this);
67255                 var langcombo = d3combobox()
67256                     .container(context.container())
67257                     .fetcher(fetcher)
67258                     .minItems(0);
67259
67260                 var label = wrap
67261                     .append('label')
67262                     .attr('class','form-label')
67263                     .text(t('translate.localized_translation_label'))
67264                     .attr('for','localized-lang');
67265
67266                 label
67267                     .append('button')
67268                     .attr('class', 'minor remove')
67269                     .on('click', function(d){
67270                         event.preventDefault();
67271                         var t$$1 = {};
67272                         t$$1[key(d.lang)] = undefined;
67273                         dispatch$$1.call('change', this, t$$1);
67274                         select(this.parentNode.parentNode)
67275                             .style('top','0')
67276                             .style('max-height','240px')
67277                             .transition()
67278                             .style('opacity', '0')
67279                             .style('max-height','0px')
67280                             .remove();
67281                     })
67282                     .call(svgIcon('#operation-delete'));
67283
67284                 wrap
67285                     .append('input')
67286                     .attr('class', 'localized-lang')
67287                     .attr('type', 'text')
67288                     .attr('placeholder',t('translate.localized_translation_language'))
67289                     .on('blur', changeLang)
67290                     .on('change', changeLang)
67291                     .call(langcombo);
67292
67293                 wrap
67294                     .append('input')
67295                     .on('blur', changeValue)
67296                     .on('change', changeValue)
67297                     .attr('type', 'text')
67298                     .attr('placeholder', t('translate.localized_translation_name'))
67299                     .attr('class', 'localized-value');
67300             });
67301
67302         innerWrap
67303             .style('margin-top', '0px')
67304             .style('max-height', '0px')
67305             .style('opacity', '0')
67306             .transition()
67307             .duration(200)
67308             .style('margin-top', '10px')
67309             .style('max-height', '240px')
67310             .style('opacity', '1')
67311             .on('end', function() {
67312                 select(this)
67313                     .style('max-height', '')
67314                     .style('overflow', 'visible');
67315             });
67316
67317
67318         var entry = selection$$1.selectAll('.entry');
67319
67320         utilGetSetValue(entry.select('.localized-lang'), function(d) {
67321                 var lang = lodash.find(dataWikipedia, function(lang) { return lang[2] === d.lang; });
67322                 return lang ? lang[1] : d.lang;
67323             });
67324
67325         utilGetSetValue(entry.select('.localized-value'),
67326             function(d) { return d.value; });
67327     }
67328
67329
67330     localized.tags = function(tags) {
67331         // Fetch translations from wikipedia
67332         if (tags.wikipedia && !wikiTitles) {
67333             wikiTitles = {};
67334             var wm = tags.wikipedia.match(/([^:]+):(.+)/);
67335             if (wm && wm[0] && wm[1]) {
67336                 wikipedia.translations(wm[1], wm[2], function(d) {
67337                     wikiTitles = d;
67338                 });
67339             }
67340         }
67341
67342         utilGetSetValue(input, tags[field.key] || '');
67343
67344         var postfixed = [], k, m;
67345         for (k in tags) {
67346             m = k.match(/^(.*):([a-zA-Z_-]+)$/);
67347             if (m && m[1] === field.key && m[2]) {
67348                 postfixed.push({ lang: m[2], value: tags[k] });
67349             }
67350         }
67351
67352         localizedInputs.call(render, postfixed.reverse());
67353     };
67354
67355
67356     localized.focus = function() {
67357         input.node().focus();
67358     };
67359
67360
67361     localized.entity = function(_) {
67362         if (!arguments.length) return entity;
67363         entity = _;
67364         return localized;
67365     };
67366
67367     return utilRebind(localized, dispatch$$1, 'on');
67368 }
67369
67370 function uiFieldMaxspeed(field, context) {
67371     var dispatch$$1 = dispatch('change'),
67372         entity,
67373         isImperial,
67374         unitInput = select(null),
67375         input = select(null),
67376         combobox;
67377
67378     var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
67379         imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
67380
67381
67382     function maxspeed(selection$$1) {
67383         combobox = d3combobox()
67384             .container(context.container());
67385
67386         var unitCombobox = d3combobox()
67387             .container(context.container())
67388             .data(['km/h', 'mph'].map(comboValues));
67389
67390         input = selection$$1.selectAll('#preset-input-' + field.id)
67391             .data([0]);
67392
67393         input = input.enter()
67394             .append('input')
67395             .attr('type', 'text')
67396             .attr('id', 'preset-input-' + field.id)
67397             .attr('placeholder', field.placeholder())
67398             .call(utilNoAuto)
67399             .call(combobox)
67400             .merge(input);
67401
67402         input
67403             .on('change', change)
67404             .on('blur', change);
67405
67406         var childNodes = context.graph().childNodes(context.entity(entity.id)),
67407             loc = childNodes[~~(childNodes.length/2)].loc;
67408
67409         isImperial = lodash.some(dataImperial.features, function(f) {
67410             return lodash.some(f.geometry.coordinates, function(d) {
67411                 return geoPointInPolygon(loc, d);
67412             });
67413         });
67414
67415         unitInput = selection$$1.selectAll('input.maxspeed-unit')
67416             .data([0]);
67417
67418         unitInput = unitInput.enter()
67419             .append('input')
67420             .attr('type', 'text')
67421             .attr('class', 'maxspeed-unit')
67422             .call(unitCombobox)
67423             .merge(unitInput);
67424
67425         unitInput
67426             .on('blur', changeUnits)
67427             .on('change', changeUnits);
67428
67429
67430         function changeUnits() {
67431             isImperial = utilGetSetValue(unitInput) === 'mph';
67432             utilGetSetValue(unitInput, isImperial ? 'mph' : 'km/h');
67433             setSuggestions();
67434             change();
67435         }
67436     }
67437
67438
67439     function setSuggestions() {
67440         combobox.data((isImperial ? imperialValues : metricValues).map(comboValues));
67441         utilGetSetValue(unitInput, isImperial ? 'mph' : 'km/h');
67442     }
67443
67444
67445     function comboValues(d) {
67446         return {
67447             value: d.toString(),
67448             title: d.toString()
67449         };
67450     }
67451
67452
67453     function change() {
67454         var tag = {},
67455             value = utilGetSetValue(input);
67456
67457         if (!value) {
67458             tag[field.key] = undefined;
67459         } else if (isNaN(value) || !isImperial) {
67460             tag[field.key] = value;
67461         } else {
67462             tag[field.key] = value + ' mph';
67463         }
67464
67465         dispatch$$1.call('change', this, tag);
67466     }
67467
67468
67469     maxspeed.tags = function(tags) {
67470         var value = tags[field.key];
67471
67472         if (value && value.indexOf('mph') >= 0) {
67473             value = parseInt(value, 10);
67474             isImperial = true;
67475         } else if (value) {
67476             isImperial = false;
67477         }
67478
67479         setSuggestions();
67480         utilGetSetValue(input, value || '');
67481     };
67482
67483
67484     maxspeed.focus = function() {
67485         input.node().focus();
67486     };
67487
67488
67489     maxspeed.entity = function(_) {
67490         entity = _;
67491     };
67492
67493
67494     return utilRebind(maxspeed, dispatch$$1, 'on');
67495 }
67496
67497 function uiFieldRadio(field, context) {
67498     var dispatch$$1 = dispatch('change'),
67499         taginfo = services.taginfo,
67500         placeholder = select(null),
67501         wrap = select(null),
67502         labels = select(null),
67503         radios = select(null),
67504         typeInput = select(null),
67505         layerInput = select(null),
67506         oldType = {},
67507         entity;
67508
67509
67510     function selectedKey() {
67511         var selector$$1 = '.form-field-structure .toggle-list label.active input',
67512             node = selectAll(selector$$1);
67513         return !node.empty() && node.datum();
67514     }
67515
67516     // returns the tag value for a display value
67517     function tagValue(dispVal) {
67518         dispVal = snake(clean(dispVal || ''));
67519         return dispVal.toLowerCase() || 'yes';
67520     }
67521
67522     // returns the display value for a tag value
67523     function displayValue(tagVal) {
67524         tagVal = tagVal || '';
67525         return tagVal.toLowerCase() === 'yes' ? '' : unsnake(tagVal);
67526     }
67527
67528     function snake(s) {
67529         return s.replace(/\s+/g, '_');
67530     }
67531
67532     function unsnake(s) {
67533         return s.replace(/_+/g, ' ');
67534     }
67535
67536     function clean(s) {
67537         return s.split(';')
67538             .map(function(s) { return s.trim(); })
67539             .join(';');
67540     }
67541
67542
67543     function radio(selection$$1) {
67544         selection$$1.classed('preset-radio', true);
67545
67546         wrap = selection$$1.selectAll('.preset-input-wrap')
67547             .data([0]);
67548
67549         var enter = wrap.enter()
67550             .append('div')
67551             .attr('class', 'preset-input-wrap toggle-list');
67552
67553         enter
67554             .append('span')
67555             .attr('class', 'placeholder');
67556
67557         wrap = wrap
67558             .merge(enter);
67559
67560
67561         placeholder = wrap.selectAll('.placeholder');
67562
67563         labels = wrap.selectAll('label')
67564             .data(field.options || field.keys);
67565
67566         enter = labels.enter()
67567             .append('label');
67568
67569         enter
67570             .append('input')
67571             .attr('type', 'radio')
67572             .attr('name', field.id)
67573             .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
67574             .attr('checked', false);
67575
67576         enter
67577             .append('span')
67578             .text(function(d) { return field.t('options.' + d, { 'default': d }); });
67579
67580         labels = labels
67581             .merge(enter);
67582
67583         radios = labels.selectAll('input')
67584             .on('change', changeRadio);
67585     }
67586
67587
67588     function structureExtras(selection$$1) {
67589         var selected = selectedKey();
67590
67591         var extrasWrap = selection$$1.selectAll('.structure-extras-wrap')
67592                 .data(selected ? [0] : []);
67593
67594         extrasWrap.exit()
67595             .remove();
67596
67597         extrasWrap = extrasWrap.enter()
67598             .append('div')
67599             .attr('class', 'structure-extras-wrap')
67600             .merge(extrasWrap);
67601
67602         var list = extrasWrap.selectAll('ul')
67603             .data([0]);
67604
67605         list = list.enter()
67606             .append('ul')
67607             .merge(list);
67608
67609
67610         // Type
67611         var typeItem = list.selectAll('.structure-type-item')
67612             .data([0]);
67613
67614         var typeEnter = typeItem.enter()
67615             .append('li')
67616             .attr('class', 'cf structure-type-item');
67617
67618         typeEnter
67619             .append('span')
67620             .attr('class', 'col6 label structure-label-type')
67621             .attr('for', 'structure-input-type')
67622             .text(t('inspector.radio.structure.type'));
67623
67624         typeEnter
67625             .append('div')
67626             .attr('class', 'col6 structure-input-type-wrap')
67627             .append('input')
67628             .attr('type', 'text')
67629             .attr('class', 'structure-input-type')
67630             .attr('placeholder', t('inspector.radio.structure.default'))
67631             .call(utilNoAuto);
67632
67633         typeItem = typeItem
67634             .merge(typeEnter);
67635
67636         typeInput = typeItem.selectAll('.structure-input-type');
67637
67638         if (taginfo) {
67639             typeInput
67640                 .call(d3combobox()
67641                     .container(context.container())
67642                     .fetcher(typeFetcher)
67643                 );
67644         }
67645
67646         typeInput
67647             .on('change', changeType)
67648             .on('blur', changeType);
67649
67650
67651         // Layer
67652         var showLayer = (selected === 'bridge' || selected === 'tunnel');
67653
67654         var layerItem = list.selectAll('.structure-layer-item')
67655             .data(showLayer ? [0] : []);
67656
67657         layerItem.exit()
67658             .remove();
67659
67660         var layerEnter = layerItem.enter()
67661             .append('li')
67662             .attr('class', 'cf structure-layer-item');
67663
67664         layerEnter
67665             .append('span')
67666             .attr('class', 'col6 label structure-label-layer')
67667             .attr('for', 'structure-input-layer')
67668             .text(t('inspector.radio.structure.layer'));
67669
67670         layerEnter
67671             .append('div')
67672             .attr('class', 'col6 structure-input-layer-wrap')
67673             .append('input')
67674             .attr('type', 'text')
67675             .attr('class', 'structure-input-layer')
67676             .attr('placeholder', '0')
67677             .call(utilNoAuto);
67678
67679         var spin = layerEnter
67680             .append('div')
67681             .attr('class', 'spin-control');
67682
67683         spin
67684             .append('button')
67685             .datum(-1)
67686             .attr('class', 'decrement')
67687             .attr('tabindex', -1);
67688
67689         spin
67690             .append('button')
67691             .datum(1)
67692             .attr('class', 'increment')
67693             .attr('tabindex', -1);
67694
67695         layerItem = layerItem
67696             .merge(layerEnter);
67697
67698         layerInput = layerItem.selectAll('.structure-input-layer')
67699             .on('change', changeLayer)
67700             .on('blur', changeLayer);
67701
67702         layerItem.selectAll('button')
67703             .on('click', function(d) {
67704                 event.preventDefault();
67705                 var num = parseInt(layerInput.node().value || 0, 10);
67706                 if (!isNaN(num)) layerInput.node().value = num + d;
67707                 changeLayer();
67708             });
67709
67710     }
67711
67712
67713     function typeFetcher(q, callback) {
67714         taginfo.values({
67715             debounce: true,
67716             key: selectedKey(),
67717             query: q
67718         }, function(err, data) {
67719             if (err) return;
67720             var comboData = data.map(function(d) {
67721                 return {
67722                     key: d.value,
67723                     value: unsnake(d.value),
67724                     title: d.title
67725                 };
67726             });
67727             if (callback) callback(comboData);
67728         });
67729     }
67730
67731
67732     function changeType() {
67733         var key = selectedKey(),
67734             t$$1 = {};
67735
67736         if (!key) return;
67737         var val = tagValue(utilGetSetValue(typeInput));
67738         t$$1[key] = val;
67739         if (val !== 'no') oldType[key] = val;
67740         dispatch$$1.call('change', this, t$$1);
67741     }
67742
67743
67744     function changeLayer() {
67745         // note: don't use utilGetSetValue here because we want 0 to be falsy.
67746         var t$$1 = { layer: layerInput.node().value || undefined };
67747         dispatch$$1.call('change', this, t$$1);
67748     }
67749
67750
67751     function changeRadio() {
67752         var t$$1 = {},
67753             activeKey;
67754
67755         if (field.key) {
67756             t$$1[field.key] = undefined;
67757         }
67758
67759         radios.each(function(d) {
67760             var active$$1 = select(this).property('checked');
67761             if (active$$1) activeKey = d;
67762
67763             if (field.key) {
67764                 if (active$$1) t$$1[field.key] = d;
67765             } else {
67766                 var val = oldType[activeKey] || 'yes';
67767                 t$$1[d] = active$$1 ? val : undefined;
67768             }
67769         });
67770
67771         if (field.type === 'structureRadio') {
67772             if (activeKey === 'bridge') {
67773                 t$$1.layer = '1';
67774             } else if (activeKey === 'tunnel') {
67775                 t$$1.layer = '-1';
67776             } else {
67777                 t$$1.layer = undefined;
67778             }
67779         }
67780
67781         dispatch$$1.call('change', this, t$$1);
67782     }
67783
67784
67785     radio.tags = function(tags) {
67786         function checked(d) {
67787             if (field.key) {
67788                 return tags[field.key] === d;
67789             } else {
67790                 return !!(tags[d] && tags[d].toLowerCase() !== 'no');
67791             }
67792         }
67793
67794         labels.classed('active', checked);
67795         radios.property('checked', checked);
67796
67797         var selection$$1 = radios.filter(function() { return this.checked; });
67798         var typeVal = '';
67799
67800         if (selection$$1.empty()) {
67801             placeholder.text(t('inspector.none'));
67802         } else {
67803             placeholder.text(selection$$1.attr('value'));
67804             typeVal = oldType[selection$$1.datum()] = tags[selection$$1.datum()];
67805         }
67806
67807         if (field.type === 'structureRadio') {
67808             wrap.call(structureExtras);
67809             utilGetSetValue(typeInput, displayValue(typeVal) || '');
67810             utilGetSetValue(layerInput, tags.layer || '');
67811         }
67812     };
67813
67814
67815     radio.focus = function() {
67816         radios.node().focus();
67817     };
67818
67819
67820     radio.entity = function(_) {
67821         if (!arguments.length) return entity;
67822         entity = _;
67823         oldType = {};
67824         return radio;
67825     };
67826
67827
67828     return utilRebind(radio, dispatch$$1, 'on');
67829 }
67830
67831 function uiFieldRestrictions(field, context) {
67832     var dispatch$$1 = dispatch('change'),
67833         breathe = behaviorBreathe(context),
67834         hover = behaviorHover(context),
67835         initialized = false,
67836         vertexID,
67837         fromNodeID;
67838
67839
67840     function restrictions(selection$$1) {
67841         // if form field is hidden or has detached from dom, clean up.
67842         if (!select('.inspector-wrap.inspector-hidden').empty() || !selection$$1.node().parentNode) {
67843             selection$$1.call(restrictions.off);
67844             return;
67845         }
67846
67847         var wrap = selection$$1.selectAll('.preset-input-wrap')
67848             .data([0]);
67849
67850         var enter = wrap.enter()
67851             .append('div')
67852             .attr('class', 'preset-input-wrap');
67853
67854         enter
67855             .append('div')
67856             .attr('class', 'restriction-help');
67857
67858
67859         var intersection = osmIntersection(context.graph(), vertexID),
67860             graph = intersection.graph,
67861             vertex = graph.entity(vertexID),
67862             filter = utilFunctor(true),
67863             extent$$1 = geoExtent$$1(),
67864             projection = geoRawMercator();
67865
67866         var d = utilGetDimensions(wrap.merge(enter)),
67867             c = [d[0] / 2, d[1] / 2],
67868             z = 24;
67869
67870         projection
67871             .scale(256 * Math.pow(2, z) / (2 * Math.PI));
67872
67873         var s = projection(vertex.loc);
67874
67875         projection
67876             .translate([c[0] - s[0], c[1] - s[1]])
67877             .clipExtent([[0, 0], d]);
67878
67879         var drawLayers = svgLayers(projection, context).only('osm').dimensions(d),
67880             drawVertices = svgVertices$$1(projection, context),
67881             drawLines = svgLines$$1(projection, context),
67882             drawTurns = svgTurns(projection, context);
67883
67884         enter
67885             .call(drawLayers);
67886
67887         wrap = wrap
67888             .merge(enter);
67889
67890         var surface = wrap.selectAll('.surface');
67891
67892         if (!enter.empty()) {
67893             initialized = true;
67894             surface
67895                 .call(breathe)
67896                 .call(hover);
67897         }
67898
67899         surface
67900             .call(utilSetDimensions, d)
67901             .call(drawVertices, graph, [vertex], filter, extent$$1, z)
67902             .call(drawLines, graph, intersection.ways, filter)
67903             .call(drawTurns, graph, intersection.turns(fromNodeID));
67904
67905         surface
67906             .on('click.restrictions', click)
67907             .on('mouseover.restrictions', mouseover)
67908             .on('mouseout.restrictions', mouseout);
67909
67910         surface
67911             .selectAll('.selected')
67912             .classed('selected', false);
67913
67914         if (fromNodeID) {
67915             surface
67916                 .selectAll('.' + intersection.highways[fromNodeID].id)
67917                 .classed('selected', true);
67918         }
67919
67920         mouseout();
67921
67922         context.history()
67923             .on('change.restrictions', render);
67924
67925         select(window)
67926             .on('resize.restrictions', function() {
67927                 utilSetDimensions(wrap, null);
67928                 render();
67929             });
67930
67931
67932         function click() {
67933             surface
67934                 .call(breathe.off)
67935                 .call(breathe);
67936
67937             var datum = event.target.__data__;
67938             if (datum instanceof osmEntity$$1) {
67939                 fromNodeID = intersection.adjacentNodeId(datum.id);
67940                 render();
67941             } else if (datum instanceof osmTurn) {
67942                 if (datum.restriction) {
67943                     context.perform(
67944                         actionUnrestrictTurn(datum, projection),
67945                         t('operations.restriction.annotation.delete')
67946                     );
67947                 } else {
67948                     context.perform(
67949                         actionRestrictTurn(datum, projection),
67950                         t('operations.restriction.annotation.create')
67951                     );
67952                 }
67953             }
67954         }
67955
67956
67957         function mouseover() {
67958             var datum = event.target.__data__;
67959             if (datum instanceof osmTurn) {
67960                 var graph = context.graph(),
67961                     presets = context.presets(),
67962                     preset;
67963
67964                 if (datum.restriction) {
67965                     preset = presets.match(graph.entity(datum.restriction), graph);
67966                 } else {
67967                     preset = presets.item('type/restriction/' +
67968                         osmInferRestriction(
67969                             graph,
67970                             datum.from,
67971                             datum.via,
67972                             datum.to,
67973                             projection
67974                         )
67975                     );
67976                 }
67977
67978                 wrap.selectAll('.restriction-help')
67979                     .text(t('operations.restriction.help.' +
67980                         (datum.restriction ? 'toggle_off' : 'toggle_on'),
67981                         { restriction: preset.name() })
67982                     );
67983             }
67984         }
67985
67986
67987         function mouseout() {
67988             wrap.selectAll('.restriction-help')
67989                 .text(t('operations.restriction.help.' +
67990                     (fromNodeID ? 'toggle' : 'select'))
67991                 );
67992         }
67993
67994
67995         function render() {
67996             if (context.hasEntity(vertexID)) {
67997                 restrictions(selection$$1);
67998             }
67999         }
68000     }
68001
68002
68003     restrictions.entity = function(_) {
68004         if (!vertexID || vertexID !== _.id) {
68005             fromNodeID = null;
68006             vertexID = _.id;
68007         }
68008     };
68009
68010
68011     restrictions.tags = function() {};
68012     restrictions.focus = function() {};
68013
68014
68015     restrictions.off = function(selection$$1) {
68016         if (!initialized) return;
68017
68018         selection$$1.selectAll('.surface')
68019             .call(hover.off)
68020             .call(breathe.off)
68021             .on('click.restrictions', null)
68022             .on('mouseover.restrictions', null)
68023             .on('mouseout.restrictions', null);
68024
68025         context.history()
68026             .on('change.restrictions', null);
68027
68028         select(window)
68029             .on('resize.restrictions', null);
68030     };
68031
68032
68033     return utilRebind(restrictions, dispatch$$1, 'on');
68034 }
68035
68036 function uiFieldTextarea(field) {
68037     var dispatch$$1 = dispatch('change'),
68038         input = select(null);
68039
68040
68041     function textarea(selection$$1) {
68042         input = selection$$1.selectAll('textarea')
68043             .data([0]);
68044
68045         input = input.enter()
68046             .append('textarea')
68047             .attr('id', 'preset-input-' + field.id)
68048             .attr('placeholder', field.placeholder() || t('inspector.unknown'))
68049             .attr('maxlength', 255)
68050             .call(utilNoAuto)
68051             .on('input', change(true))
68052             .on('blur', change())
68053             .on('change', change())
68054             .merge(input);
68055     }
68056
68057
68058     function change(onInput) {
68059         return function() {
68060             var t$$1 = {};
68061             t$$1[field.key] = utilGetSetValue(input) || undefined;
68062             dispatch$$1.call('change', this, t$$1, onInput);
68063         };
68064     }
68065
68066
68067     textarea.tags = function(tags) {
68068         utilGetSetValue(input, tags[field.key] || '');
68069     };
68070
68071
68072     textarea.focus = function() {
68073         input.node().focus();
68074     };
68075
68076
68077     return utilRebind(textarea, dispatch$$1, 'on');
68078 }
68079
68080 function uiFieldWikipedia(field, context) {
68081     var dispatch$$1 = dispatch('change'),
68082         wikipedia = services.wikipedia,
68083         wikidata = services.wikidata,
68084         link = select(null),
68085         lang = select(null),
68086         title = select(null),
68087         wikiURL = '',
68088         entity;
68089
68090
68091     function wiki(selection$$1) {
68092         var langcombo = d3combobox()
68093             .container(context.container())
68094             .fetcher(function(value, cb) {
68095                 var v = value.toLowerCase();
68096
68097                 cb(dataWikipedia.filter(function(d) {
68098                     return d[0].toLowerCase().indexOf(v) >= 0 ||
68099                         d[1].toLowerCase().indexOf(v) >= 0 ||
68100                         d[2].toLowerCase().indexOf(v) >= 0;
68101                 }).map(function(d) {
68102                     return { value: d[1] };
68103                 }));
68104             });
68105
68106         var titlecombo = d3combobox()
68107             .container(context.container())
68108             .fetcher(function(value, cb) {
68109                 if (!value) {
68110                     value = context.entity(entity.id).tags.name || '';
68111                 }
68112
68113                 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
68114                 searchfn(language()[2], value, function(query, data$$1) {
68115                     cb(data$$1.map(function(d) {
68116                         return { value: d };
68117                     }));
68118                 });
68119             });
68120
68121
68122         lang = selection$$1.selectAll('input.wiki-lang')
68123             .data([0]);
68124
68125         lang = lang.enter()
68126             .append('input')
68127             .attr('type', 'text')
68128             .attr('class', 'wiki-lang')
68129             .attr('placeholder', t('translate.localized_translation_language'))
68130             .call(utilNoAuto)
68131             .merge(lang);
68132
68133         utilGetSetValue(lang, language()[1]);
68134
68135         lang
68136             .call(langcombo)
68137             .on('blur', changeLang)
68138             .on('change', changeLang);
68139
68140
68141         title = selection$$1.selectAll('input.wiki-title')
68142             .data([0]);
68143
68144         title = title.enter()
68145             .append('input')
68146             .attr('type', 'text')
68147             .attr('class', 'wiki-title')
68148             .attr('id', 'preset-input-' + field.id)
68149             .call(utilNoAuto)
68150             .merge(title);
68151
68152         title
68153             .call(titlecombo)
68154             .on('blur', blur)
68155             .on('change', change);
68156
68157
68158         link = selection$$1.selectAll('.wiki-link')
68159             .data([0]);
68160
68161         link = link.enter()
68162             .append('button')
68163             .attr('class', 'button-input-action wiki-link minor')
68164             .attr('tabindex', -1)
68165             .call(svgIcon('#icon-out-link'))
68166             .merge(link);
68167
68168         link
68169             .on('click', function() {
68170                 event.preventDefault();
68171                 if (wikiURL) window.open(wikiURL, '_blank');
68172             });
68173     }
68174
68175
68176     function language() {
68177         var value = utilGetSetValue(lang).toLowerCase();
68178         var locale = utilDetect().locale.toLowerCase();
68179         var localeLanguage;
68180         return lodash.find(dataWikipedia, function(d) {
68181             if (d[2] === locale) localeLanguage = d;
68182             return d[0].toLowerCase() === value ||
68183                 d[1].toLowerCase() === value ||
68184                 d[2] === value;
68185         }) || localeLanguage || ['English', 'English', 'en'];
68186     }
68187
68188
68189     function changeLang() {
68190         utilGetSetValue(lang, language()[1]);
68191         change(true);
68192     }
68193
68194
68195     function blur() {
68196         change(true);
68197     }
68198
68199
68200     function change(skipWikidata) {
68201         var value = utilGetSetValue(title),
68202             m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
68203             l = m && lodash.find(dataWikipedia, function(d) { return m[1] === d[2]; }),
68204             anchor,
68205             syncTags = {};
68206
68207         if (l) {
68208             // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
68209             value = decodeURIComponent(m[2]).replace(/_/g, ' ');
68210             if (m[3]) {
68211                 try {
68212                     // Best-effort `anchordecode:` implementation
68213                     anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
68214                 } catch (e) {
68215                     anchor = decodeURIComponent(m[3]);
68216                 }
68217                 value += '#' + anchor.replace(/_/g, ' ');
68218             }
68219             value = value.slice(0, 1).toUpperCase() + value.slice(1);
68220             utilGetSetValue(lang, l[1]);
68221             utilGetSetValue(title, value);
68222         }
68223
68224         syncTags.wikipedia = value ? language()[2] + ':' + value : undefined;
68225         if (!skipWikidata) {
68226             syncTags.wikidata = undefined;
68227         }
68228
68229         dispatch$$1.call('change', this, syncTags);
68230
68231
68232         if (skipWikidata || !value || !language()[2]) return;
68233
68234         // attempt asynchronous update of wikidata tag..
68235         var initEntityId = entity.id,
68236             initWikipedia = context.entity(initEntityId).tags.wikipedia;
68237
68238         wikidata.itemsByTitle(language()[2], value, function(title, data$$1) {
68239             if (!data$$1 || !Object.keys(data$$1).length) return;
68240             var qids = Object.keys(data$$1);
68241
68242             // 1. most recent change was a tag change
68243             var annotation = t('operations.change_tags.annotation'),
68244                 currAnnotation = context.history().undoAnnotation();
68245             if (currAnnotation !== annotation) return;
68246
68247             // 2. same entity exists and still selected
68248             var selectedIds = context.selectedIDs(),
68249                 currEntityId = selectedIds.length > 0 && selectedIds[0];
68250             if (currEntityId !== initEntityId) return;
68251
68252             // 3. wikipedia value has not changed
68253             var currTags = lodash.clone(context.entity(currEntityId).tags);
68254             if (initWikipedia !== currTags.wikipedia) return;
68255
68256             // ok to coalesce the update of wikidata tag into the previous tag change
68257             currTags.wikidata = qids && lodash.find(qids, function(id) {
68258                 return id.match(/^Q\d+$/);
68259             });
68260
68261             context.overwrite(actionChangeTags(currEntityId, currTags), annotation);
68262             dispatch$$1.call('change', this, currTags);
68263         });
68264     }
68265
68266
68267     wiki.tags = function(tags) {
68268         var value = tags[field.key] || '',
68269             m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
68270             l = m && lodash.find(dataWikipedia, function(d) { return m[1] === d[2]; }),
68271             anchor = m && m[3];
68272
68273         // value in correct format
68274         if (l) {
68275             utilGetSetValue(lang, l[1]);
68276             utilGetSetValue(title, m[2] + (anchor ? ('#' + anchor) : ''));
68277             if (anchor) {
68278                 try {
68279                     // Best-effort `anchorencode:` implementation
68280                     anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
68281                 } catch (e) {
68282                     anchor = anchor.replace(/ /g, '_');
68283                 }
68284             }
68285             wikiURL = 'https://' + m[1] + '.wikipedia.org/wiki/' +
68286                 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : '');
68287
68288         // unrecognized value format
68289         } else {
68290             utilGetSetValue(title, value);
68291             if (value && value !== '') {
68292                 utilGetSetValue(lang, '');
68293                 wikiURL = 'https://en.wikipedia.org/wiki/Special:Search?search=' + value;
68294             } else {
68295                 wikiURL = '';
68296             }
68297         }
68298     };
68299
68300
68301     wiki.entity = function(_) {
68302         if (!arguments.length) return entity;
68303         entity = _;
68304         return wiki;
68305     };
68306
68307
68308     wiki.focus = function() {
68309         title.node().focus();
68310     };
68311
68312
68313     return utilRebind(wiki, dispatch$$1, 'on');
68314 }
68315
68316 var uiFields = {
68317     access: uiFieldAccess,
68318     address: uiFieldAddress,
68319     check: uiFieldCheck,
68320     combo: uiFieldCombo,
68321     cycleway: uiFieldCycleway,
68322     defaultCheck: uiFieldCheck,
68323     email: uiFieldText,
68324     lanes: uiFieldLanes,
68325     localized: uiFieldLocalized,
68326     maxspeed: uiFieldMaxspeed,
68327     multiCombo: uiFieldCombo,
68328     networkCombo: uiFieldCombo,
68329     number: uiFieldText,
68330     onewayCheck: uiFieldCheck,
68331     radio: uiFieldRadio,
68332     restrictions: uiFieldRestrictions,
68333     semiCombo: uiFieldCombo,
68334     structureRadio: uiFieldRadio,
68335     tel: uiFieldText,
68336     text: uiFieldText,
68337     textarea: uiFieldTextarea,
68338     typeCombo: uiFieldCombo,
68339     url: uiFieldText,
68340     wikipedia: uiFieldWikipedia
68341 };
68342
68343 function uiPreset(context) {
68344     var dispatch$$1 = dispatch('change'),
68345         state,
68346         fieldsArr,
68347         preset,
68348         tags,
68349         id;
68350
68351
68352     // Field Constructor
68353     function UIField(field, entity, show) {
68354         field = lodash.clone(field);
68355
68356         field.input = uiFields[field.type](field, context)
68357             .on('change', function(t$$1, onInput) {
68358                 dispatch$$1.call('change', field, t$$1, onInput);
68359             });
68360
68361         if (field.input.entity) field.input.entity(entity);
68362
68363         field.keys = field.keys || [field.key];
68364
68365         field.show = show;
68366
68367         field.shown = function() {
68368             return field.id === 'name' || field.show || lodash.some(field.keys, function(key) { return !!tags[key]; });
68369         };
68370
68371         field.modified = function() {
68372             var original = context.graph().base().entities[entity.id];
68373             return lodash.some(field.keys, function(key) {
68374                 return original ? tags[key] !== original.tags[key] : tags[key];
68375             });
68376         };
68377
68378         field.revert = function() {
68379             var original = context.graph().base().entities[entity.id],
68380                 t$$1 = {};
68381             field.keys.forEach(function(key) {
68382                 t$$1[key] = original ? original.tags[key] : undefined;
68383             });
68384             return t$$1;
68385         };
68386
68387         field.present = function() {
68388             return lodash.some(field.keys, function(key) {
68389                 return tags[key];
68390             });
68391         };
68392
68393         field.remove = function() {
68394             var t$$1 = {};
68395             field.keys.forEach(function(key) {
68396                 t$$1[key] = undefined;
68397             });
68398             return t$$1;
68399         };
68400
68401         return field;
68402     }
68403
68404
68405     function fieldKey(field) {
68406         return field.id;
68407     }
68408
68409
68410     function presets(selection$$1) {
68411         selection$$1.call(uiDisclosure()
68412             .title(t('inspector.all_fields'))
68413             .expanded(context.storage('preset_fields.expanded') !== 'false')
68414             .on('toggled', toggled)
68415             .content(content)
68416         );
68417
68418         function toggled(expanded) {
68419             context.storage('preset_fields.expanded', expanded);
68420         }
68421     }
68422
68423
68424     function content(selection$$1) {
68425         if (!fieldsArr) {
68426             var entity = context.entity(id),
68427                 geometry = context.geometry(id),
68428                 presets = context.presets();
68429
68430             fieldsArr = [];
68431
68432             if (presets.field('name')) {
68433                 fieldsArr.push(UIField(presets.field('name'), entity));
68434             }
68435
68436             preset.fields.forEach(function(field) {
68437                 if (field.matchGeometry(geometry)) {
68438                     fieldsArr.push(UIField(field, entity, true));
68439                 }
68440             });
68441
68442             if (entity.isHighwayIntersection(context.graph()) && presets.field('restrictions')) {
68443                 fieldsArr.push(UIField(presets.field('restrictions'), entity, true));
68444             }
68445
68446             presets.universal().forEach(function(field) {
68447                 if (preset.fields.indexOf(field) < 0) {
68448                     fieldsArr.push(UIField(field, entity));
68449                 }
68450             });
68451         }
68452
68453         var shown = fieldsArr.filter(function(field) { return field.shown(); }),
68454             notShown = fieldsArr.filter(function(field) { return !field.shown(); });
68455
68456
68457         var form = selection$$1.selectAll('.preset-form')
68458             .data([0]);
68459
68460         form = form.enter()
68461             .append('div')
68462             .attr('class', 'preset-form inspector-inner fillL3')
68463             .merge(form);
68464
68465
68466         var fields = form.selectAll('.form-field')
68467             .data(shown, fieldKey);
68468
68469         fields.exit()
68470             .remove();
68471
68472         // Enter
68473         var enter = fields.enter()
68474             .append('div')
68475             .attr('class', function(field) {
68476                 return 'form-field form-field-' + field.id;
68477             });
68478
68479         var label = enter
68480             .append('label')
68481             .attr('class', 'form-label')
68482             .attr('for', function(field) { return 'preset-input-' + field.id; })
68483             .text(function(field) { return field.label(); });
68484
68485         var wrap = label
68486             .append('div')
68487             .attr('class', 'form-label-button-wrap');
68488
68489         wrap.append('button')
68490             .attr('class', 'remove-icon')
68491             .attr('tabindex', -1)
68492             .call(svgIcon('#operation-delete'));
68493
68494         wrap.append('button')
68495             .attr('class', 'modified-icon')
68496             .attr('tabindex', -1)
68497             .call(
68498                 (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
68499             );
68500
68501
68502         // Update
68503         fields = fields
68504             .merge(enter);
68505
68506         fields.selectAll('.form-label-button-wrap .remove-icon')
68507             .on('click', remove);
68508
68509         fields.selectAll('.modified-icon')
68510             .on('click', revert);
68511
68512         fields
68513             .order()
68514             .classed('modified', function(field) { return field.modified(); })
68515             .classed('present', function(field) { return field.present(); })
68516             .each(function(field) {
68517                 var reference = uiTagReference(field.reference || { key: field.key }, context);
68518
68519                 if (state === 'hover') {
68520                     reference.showing(false);
68521                 }
68522
68523                 select(this)
68524                     .call(field.input)
68525                     .selectAll('input')
68526                     .on('keydown', function() {
68527                         // if user presses enter, and combobox is not active, accept edits..
68528                         if (event.keyCode === 13 && select('.combobox').empty()) {
68529                             context.enter(modeBrowse(context));
68530                         }
68531                     });
68532
68533                 select(this)
68534                     .call(reference.body)
68535                     .select('.form-label-button-wrap')
68536                     .call(reference.button);
68537
68538                 field.input.tags(tags);
68539             });
68540
68541         notShown = notShown.map(function(field) {
68542             return {
68543                 title: field.label(),
68544                 value: field.label(),
68545                 field: field
68546             };
68547         });
68548
68549
68550         var more = selection$$1.selectAll('.more-fields')
68551             .data((notShown.length > 0) ? [0] : []);
68552
68553         more.exit()
68554             .remove();
68555
68556         more = more.enter()
68557             .append('div')
68558             .attr('class', 'more-fields')
68559             .append('label')
68560             .text(t('inspector.add_fields'))
68561             .merge(more);
68562
68563
68564         var input = more.selectAll('.value')
68565             .data([0]);
68566
68567         input.exit()
68568             .remove();
68569
68570         input = input.enter()
68571             .append('input')
68572             .attr('class', 'value')
68573             .attr('type', 'text')
68574             .call(utilNoAuto)
68575             .merge(input);
68576
68577         input
68578             .call(utilGetSetValue, '')
68579             .attr('placeholder', function() {
68580                 var placeholder = [];
68581                 for (var field in notShown) {
68582                     placeholder.push(notShown[field].title);
68583                 }
68584                 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
68585             })
68586             .call(d3combobox()
68587                 .container(context.container())
68588                 .data(notShown)
68589                 .minItems(1)
68590                 .on('accept', show)
68591             );
68592
68593
68594         function show(field) {
68595             field = field.field;
68596             field.show = true;
68597             content(selection$$1);
68598             field.input.focus();
68599         }
68600
68601
68602         function revert(field) {
68603             event.stopPropagation();
68604             event.preventDefault();
68605             dispatch$$1.call('change', field, field.revert());
68606         }
68607
68608
68609         function remove(field) {
68610             event.stopPropagation();
68611             event.preventDefault();
68612             dispatch$$1.call('change', field, field.remove());
68613         }
68614     }
68615
68616
68617     presets.preset = function(_) {
68618         if (!arguments.length) return preset;
68619         if (preset && preset.id === _.id) return presets;
68620         preset = _;
68621         fieldsArr = null;
68622         return presets;
68623     };
68624
68625
68626     presets.state = function(_) {
68627         if (!arguments.length) return state;
68628         state = _;
68629         return presets;
68630     };
68631
68632
68633     presets.tags = function(_) {
68634         if (!arguments.length) return tags;
68635         tags = _;
68636         // Don't reset fieldsArr here.
68637         return presets;
68638     };
68639
68640
68641     presets.entityID = function(_) {
68642         if (!arguments.length) return id;
68643         if (id === _) return presets;
68644         id = _;
68645         fieldsArr = null;
68646         return presets;
68647     };
68648
68649
68650     return utilRebind(presets, dispatch$$1, 'on');
68651 }
68652
68653 function uiEntityEditor(context) {
68654     var dispatch$$1 = dispatch('choose'),
68655         state = 'select',
68656         coalesceChanges = false,
68657         modified = false,
68658         base,
68659         id,
68660         activePreset,
68661         reference;
68662
68663     var presetEditor = uiPreset(context)
68664         .on('change', changeTags);
68665     var rawTagEditor = uiRawTagEditor(context)
68666         .on('change', changeTags);
68667
68668
68669     function entityEditor(selection$$1) {
68670         var entity = context.entity(id),
68671             tags = lodash.clone(entity.tags);
68672
68673         // Header
68674         var header = selection$$1.selectAll('.header')
68675             .data([0]);
68676
68677         // Enter
68678         var enter = header.enter()
68679             .append('div')
68680             .attr('class', 'header fillL cf');
68681
68682         enter
68683             .append('button')
68684             .attr('class', 'fl preset-reset preset-choose')
68685             .call(svgIcon((textDirection === 'rtl') ? '#icon-forward' : '#icon-backward'));
68686
68687         enter
68688             .append('button')
68689             .attr('class', 'fr preset-close')
68690             .on('click', function() { context.enter(modeBrowse(context)); })
68691             .call(svgIcon(modified ? '#icon-apply' : '#icon-close'));
68692
68693         enter
68694             .append('h3')
68695             .text(t('inspector.edit'));
68696
68697         // Update
68698         header = header
68699             .merge(enter);
68700
68701         header.selectAll('.preset-reset')
68702             .on('click', function() { dispatch$$1.call('choose', this, activePreset); });
68703
68704
68705         // Body
68706         var body = selection$$1.selectAll('.inspector-body')
68707             .data([0]);
68708
68709         // Enter
68710         enter = body.enter()
68711             .append('div')
68712             .attr('class', 'inspector-body');
68713
68714         enter
68715             .append('div')
68716             .attr('class', 'preset-list-item inspector-inner')
68717             .append('div')
68718             .attr('class', 'preset-list-button-wrap')
68719             .append('button')
68720             .attr('class', 'preset-list-button preset-reset')
68721             .call(tooltip().title(t('inspector.back_tooltip')).placement('bottom'))
68722             .append('div')
68723             .attr('class', 'label');
68724
68725         enter
68726             .append('div')
68727             .attr('class', 'inspector-border inspector-preset');
68728
68729         enter
68730             .append('div')
68731             .attr('class', 'inspector-border raw-tag-editor inspector-inner');
68732
68733         enter
68734             .append('div')
68735             .attr('class', 'inspector-border raw-member-editor inspector-inner');
68736
68737         enter
68738             .append('div')
68739             .attr('class', 'raw-membership-editor inspector-inner');
68740
68741         // Update
68742         body = body
68743             .merge(enter);
68744
68745         body.selectAll('.preset-list-button-wrap')
68746             .call(reference.button);
68747
68748         body.selectAll('.preset-list-item')
68749             .call(reference.body);
68750
68751         body.selectAll('.preset-reset')
68752             .on('click', function() { dispatch$$1.call('choose', this, activePreset); });
68753
68754         body.select('.preset-list-item button')
68755             .call(uiPresetIcon()
68756                 .geometry(context.geometry(id))
68757                 .preset(activePreset));
68758
68759         body.select('.preset-list-item .label')
68760             .text(activePreset.name());
68761
68762         body.select('.inspector-preset')
68763             .call(presetEditor
68764                 .preset(activePreset)
68765                 .entityID(id)
68766                 .tags(tags)
68767                 .state(state));
68768
68769         body.select('.raw-tag-editor')
68770             .call(rawTagEditor
68771                 .preset(activePreset)
68772                 .entityID(id)
68773                 .tags(tags)
68774                 .state(state));
68775
68776         if (entity.type === 'relation') {
68777             body.select('.raw-member-editor')
68778                 .style('display', 'block')
68779                 .call(uiRawMemberEditor(context)
68780                     .entityID(id));
68781         } else {
68782             body.select('.raw-member-editor')
68783                 .style('display', 'none');
68784         }
68785
68786         body.select('.raw-membership-editor')
68787             .call(uiRawMembershipEditor(context)
68788                 .entityID(id));
68789
68790
68791         context.history()
68792             .on('change.entity-editor', historyChanged);
68793
68794
68795         function historyChanged() {
68796             if (state === 'hide') return;
68797
68798             var entity = context.hasEntity(id),
68799                 graph = context.graph();
68800             if (!entity) return;
68801
68802             entityEditor.preset(context.presets().match(entity, graph));
68803             entityEditor.modified(base !== graph);
68804             entityEditor(selection$$1);
68805         }
68806     }
68807
68808
68809     function clean(o) {
68810
68811         function cleanVal(k, v) {
68812             function keepSpaces(k) {
68813                 return k.match(/_hours|_times/) !== null;
68814             }
68815
68816             var blacklist = ['description', 'note', 'fixme'];
68817             if (lodash.some(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
68818
68819             var cleaned = v.split(';')
68820                 .map(function(s) { return s.trim(); })
68821                 .join(keepSpaces(k) ? '; ' : ';');
68822
68823             // The code below is not intended to validate websites and emails.
68824             // It is only intended to prevent obvious copy-paste errors. (#2323)
68825             // clean website- and email-like tags
68826             if (k.indexOf('website') !== -1 ||
68827                 k.indexOf('email') !== -1 ||
68828                 cleaned.indexOf('http') === 0) {
68829                 cleaned = cleaned
68830                     .replace(/[\u200B-\u200F\uFEFF]/g, '');  // strip LRM and other zero width chars
68831
68832             }
68833
68834             return cleaned;
68835         }
68836
68837         var out = {}, k, v;
68838         for (k in o) {
68839             if (k && (v = o[k]) !== undefined) {
68840                 out[k] = cleanVal(k, v);
68841             }
68842         }
68843         return out;
68844     }
68845
68846
68847     // Tag changes that fire on input can all get coalesced into a single
68848     // history operation when the user leaves the field.  #2342
68849     function changeTags(changed, onInput) {
68850         var entity = context.entity(id),
68851             annotation = t('operations.change_tags.annotation'),
68852             tags = lodash.clone(entity.tags);
68853
68854         lodash.forEach(changed, function(v, k) {
68855             if (v !== undefined || tags.hasOwnProperty(k)) {
68856                 tags[k] = v;
68857             }
68858         });
68859
68860         if (!onInput) {
68861             tags = clean(tags);
68862         }
68863
68864         if (!lodash.isEqual(entity.tags, tags)) {
68865             if (coalesceChanges) {
68866                 context.overwrite(actionChangeTags(id, tags), annotation);
68867             } else {
68868                 context.perform(actionChangeTags(id, tags), annotation);
68869                 coalesceChanges = !!onInput;
68870             }
68871         }
68872     }
68873
68874
68875     entityEditor.modified = function(_) {
68876         if (!arguments.length) return modified;
68877         modified = _;
68878         selectAll('button.preset-close use')
68879             .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
68880     };
68881
68882
68883     entityEditor.state = function(_) {
68884         if (!arguments.length) return state;
68885         state = _;
68886         return entityEditor;
68887     };
68888
68889
68890     entityEditor.entityID = function(_) {
68891         if (!arguments.length) return id;
68892         id = _;
68893         base = context.graph();
68894         entityEditor.preset(context.presets().match(context.entity(id), base));
68895         entityEditor.modified(false);
68896         coalesceChanges = false;
68897         return entityEditor;
68898     };
68899
68900
68901     entityEditor.preset = function(_) {
68902         if (!arguments.length) return activePreset;
68903         if (_ !== activePreset) {
68904             activePreset = _;
68905             reference = uiTagReference(activePreset.reference(context.geometry(id)), context)
68906                 .showing(false);
68907         }
68908         return entityEditor;
68909     };
68910
68911
68912     return utilRebind(entityEditor, dispatch$$1, 'on');
68913 }
68914
68915 function uiPresetList(context) {
68916     var dispatch$$1 = dispatch('choose'),
68917         id,
68918         currentPreset,
68919         autofocus = false;
68920
68921
68922     function presetList(selection$$1) {
68923         var entity = context.entity(id),
68924             geometry = context.geometry(id);
68925
68926         // Treat entities on addr:interpolation lines as points, not vertices (#3241)
68927         if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
68928             geometry = 'point';
68929         }
68930
68931         var presets = context.presets().matchGeometry(geometry);
68932
68933         selection$$1.html('');
68934
68935         var messagewrap = selection$$1
68936             .append('div')
68937             .attr('class', 'header fillL cf');
68938
68939         var message = messagewrap
68940             .append('h3')
68941             .text(t('inspector.choose'));
68942
68943         if (context.entity(id).isUsed(context.graph())) {
68944             messagewrap
68945                 .append('button')
68946                 .attr('class', 'preset-choose')
68947                 .on('click', function() { dispatch$$1.call('choose', this, currentPreset); })
68948                 .call(svgIcon((textDirection === 'rtl') ? '#icon-backward' : '#icon-forward'));
68949         } else {
68950             messagewrap
68951                 .append('button')
68952                 .attr('class', 'close')
68953                 .on('click', function() {
68954                     context.enter(modeBrowse(context));
68955                 })
68956                 .call(svgIcon('#icon-close'));
68957         }
68958
68959         function keydown() {
68960             // hack to let delete shortcut work when search is autofocused
68961             if (search.property('value').length === 0 &&
68962                 (event.keyCode === d3keybinding.keyCodes['⌫'] ||
68963                  event.keyCode === d3keybinding.keyCodes['⌦'])) {
68964                 event.preventDefault();
68965                 event.stopPropagation();
68966                 operationDelete([id], context)();
68967             } else if (search.property('value').length === 0 &&
68968                 (event.ctrlKey || event.metaKey) &&
68969                 event.keyCode === d3keybinding.keyCodes.z) {
68970                 event.preventDefault();
68971                 event.stopPropagation();
68972                 context.undo();
68973             } else if (!event.ctrlKey && !event.metaKey) {
68974                 select(this).on('keydown', null);
68975             }
68976         }
68977
68978         function keypress() {
68979             // enter
68980             var value = search.property('value');
68981             if (event.keyCode === 13 && value.length) {
68982                 list.selectAll('.preset-list-item:first-child').datum().choose();
68983             }
68984         }
68985
68986         function inputevent() {
68987             var value = search.property('value');
68988             list.classed('filtered', value.length);
68989             if (value.length) {
68990                 var results = presets.search(value, geometry);
68991                 message.text(t('inspector.results', {
68992                     n: results.collection.length,
68993                     search: value
68994                 }));
68995                 list.call(drawList, results);
68996             } else {
68997                 list.call(drawList, context.presets().defaults(geometry, 36));
68998                 message.text(t('inspector.choose'));
68999             }
69000         }
69001
69002         var searchWrap = selection$$1
69003             .append('div')
69004             .attr('class', 'search-header');
69005
69006         var search = searchWrap
69007             .append('input')
69008             .attr('class', 'preset-search-input')
69009             .attr('placeholder', t('inspector.search'))
69010             .attr('type', 'search')
69011             .call(utilNoAuto)
69012             .on('keydown', keydown)
69013             .on('keypress', keypress)
69014             .on('input', inputevent);
69015
69016         searchWrap
69017             .call(svgIcon('#icon-search', 'pre-text'));
69018
69019         if (autofocus) {
69020             search.node().focus();
69021         }
69022
69023         var listWrap = selection$$1
69024             .append('div')
69025             .attr('class', 'inspector-body');
69026
69027         var list = listWrap
69028             .append('div')
69029             .attr('class', 'preset-list fillL cf')
69030             .call(drawList, context.presets().defaults(geometry, 36));
69031     }
69032
69033
69034     function drawList(list, presets) {
69035         var collection = presets.collection.map(function(preset) {
69036             return preset.members ? CategoryItem(preset) : PresetItem(preset);
69037         });
69038
69039         var items = list.selectAll('.preset-list-item')
69040             .data(collection, function(d) { return d.preset.id; });
69041
69042         items.order();
69043
69044         items.exit()
69045             .remove();
69046
69047         items.enter()
69048             .append('div')
69049             .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
69050             .classed('current', function(item) { return item.preset === currentPreset; })
69051             .each(function(item) { select(this).call(item); })
69052             .style('opacity', 0)
69053             .transition()
69054             .style('opacity', 1);
69055     }
69056
69057
69058     function CategoryItem(preset) {
69059         var box, sublist, shown = false;
69060
69061         function item(selection$$1) {
69062             var wrap = selection$$1.append('div')
69063                 .attr('class', 'preset-list-button-wrap category col12');
69064
69065             var button = wrap
69066                 .append('button')
69067                 .attr('class', 'preset-list-button')
69068                 .classed('expanded', false)
69069                 .call(uiPresetIcon()
69070                     .geometry(context.geometry(id))
69071                     .preset(preset))
69072                 .on('click', function() {
69073                     var isExpanded = select(this).classed('expanded');
69074                     var iconName = isExpanded ?
69075                         (textDirection === 'rtl' ? '#icon-backward' : '#icon-forward') : '#icon-down';
69076                     select(this)
69077                         .classed('expanded', !isExpanded);
69078                     select(this).selectAll('div.label svg.icon use')
69079                         .attr('href', iconName);
69080                     item.choose();
69081                 });
69082
69083             var label = button
69084                 .append('div')
69085                 .attr('class', 'label');
69086
69087             label
69088                 .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'))
69089                 .append('span')
69090                 .html(function() { return preset.name() + '&hellip;'; });
69091
69092             box = selection$$1.append('div')
69093                 .attr('class', 'subgrid col12')
69094                 .style('max-height', '0px')
69095                 .style('opacity', 0);
69096
69097             box.append('div')
69098                 .attr('class', 'arrow');
69099
69100             sublist = box.append('div')
69101                 .attr('class', 'preset-list fillL3 cf fl');
69102         }
69103
69104
69105         item.choose = function() {
69106             if (!box || !sublist) return;
69107
69108             if (shown) {
69109                 shown = false;
69110                 box.transition()
69111                     .duration(200)
69112                     .style('opacity', '0')
69113                     .style('max-height', '0px')
69114                     .style('padding-bottom', '0px');
69115             } else {
69116                 shown = true;
69117                 sublist.call(drawList, preset.members);
69118                 box.transition()
69119                     .duration(200)
69120                     .style('opacity', '1')
69121                     .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
69122                     .style('padding-bottom', '20px');
69123             }
69124         };
69125
69126         item.preset = preset;
69127
69128         return item;
69129     }
69130
69131
69132     function PresetItem(preset) {
69133         function item(selection$$1) {
69134             var wrap = selection$$1.append('div')
69135                 .attr('class', 'preset-list-button-wrap col12');
69136
69137             wrap.append('button')
69138                 .attr('class', 'preset-list-button')
69139                 .call(uiPresetIcon()
69140                     .geometry(context.geometry(id))
69141                     .preset(preset))
69142                 .on('click', item.choose)
69143                 .append('div')
69144                 .attr('class', 'label')
69145                 .text(preset.name());
69146
69147             wrap.call(item.reference.button);
69148             selection$$1.call(item.reference.body);
69149         }
69150
69151         item.choose = function() {
69152             context.presets().choose(preset);
69153
69154             context.perform(
69155                 actionChangePreset(id, currentPreset, preset),
69156                 t('operations.change_tags.annotation')
69157             );
69158
69159             dispatch$$1.call('choose', this, preset);
69160         };
69161
69162         item.help = function() {
69163             event.stopPropagation();
69164             item.reference.toggle();
69165         };
69166
69167         item.preset = preset;
69168         item.reference = uiTagReference(preset.reference(context.geometry(id)), context);
69169
69170         return item;
69171     }
69172
69173
69174     presetList.autofocus = function(_) {
69175         if (!arguments.length) return autofocus;
69176         autofocus = _;
69177         return presetList;
69178     };
69179
69180
69181     presetList.entityID = function(_) {
69182         if (!arguments.length) return id;
69183         id = _;
69184         presetList.preset(context.presets().match(context.entity(id), context.graph()));
69185         return presetList;
69186     };
69187
69188
69189     presetList.preset = function(_) {
69190         if (!arguments.length) return currentPreset;
69191         currentPreset = _;
69192         return presetList;
69193     };
69194
69195
69196     return utilRebind(presetList, dispatch$$1, 'on');
69197 }
69198
69199 function uiViewOnOSM(context) {
69200     var id;
69201
69202     function viewOnOSM(selection) {
69203         var entity = context.entity(id);
69204
69205         selection.style('display', entity.isNew() ? 'none' : null);
69206
69207         var link = selection.selectAll('.view-on-osm')
69208             .data([0]);
69209
69210         var enter = link.enter()
69211             .append('a')
69212             .attr('class', 'view-on-osm')
69213             .attr('target', '_blank')
69214             .call(svgIcon('#icon-out-link', 'inline'));
69215
69216         enter
69217             .append('span')
69218             .text(t('inspector.view_on_osm'));
69219
69220         link
69221             .merge(enter)
69222             .attr('href', context.connection().entityURL(entity));
69223     }
69224
69225
69226     viewOnOSM.entityID = function(_) {
69227         if (!arguments.length) return id;
69228         id = _;
69229         return viewOnOSM;
69230     };
69231
69232     return viewOnOSM;
69233 }
69234
69235 function uiInspector(context) {
69236     var presetList = uiPresetList(context),
69237         entityEditor = uiEntityEditor(context),
69238         state = 'select',
69239         entityID,
69240         newFeature = false;
69241
69242
69243     function inspector(selection$$1) {
69244         presetList
69245             .entityID(entityID)
69246             .autofocus(newFeature)
69247             .on('choose', setPreset);
69248
69249         entityEditor
69250             .state(state)
69251             .entityID(entityID)
69252             .on('choose', showList);
69253
69254         var wrap = selection$$1.selectAll('.panewrap')
69255             .data([0]);
69256
69257         var enter = wrap.enter()
69258             .append('div')
69259             .attr('class', 'panewrap');
69260
69261         enter
69262             .append('div')
69263             .attr('class', 'preset-list-pane pane');
69264
69265         enter
69266             .append('div')
69267             .attr('class', 'entity-editor-pane pane');
69268
69269         wrap = wrap.merge(enter);
69270         var presetPane = wrap.selectAll('.preset-list-pane');
69271         var editorPane = wrap.selectAll('.entity-editor-pane');
69272
69273         var graph = context.graph(),
69274             entity = context.entity(entityID),
69275             showEditor = state === 'hover' ||
69276                 entity.isUsed(graph) ||
69277                 entity.isHighwayIntersection(graph);
69278
69279         if (showEditor) {
69280             wrap.style('right', '0%');
69281             editorPane.call(entityEditor);
69282         } else {
69283             wrap.style('right', '-100%');
69284             presetPane.call(presetList);
69285         }
69286
69287         var footer = selection$$1.selectAll('.footer')
69288             .data([0]);
69289
69290         footer = footer.enter()
69291             .append('div')
69292             .attr('class', 'footer')
69293             .merge(footer);
69294
69295         footer
69296             .call(uiViewOnOSM(context).entityID(entityID));
69297
69298
69299         function showList(preset) {
69300             wrap.transition()
69301                 .styleTween('right', function() { return interpolateValue('0%', '-100%'); });
69302
69303             presetPane
69304                 .call(presetList.preset(preset).autofocus(true));
69305         }
69306
69307
69308         function setPreset(preset) {
69309             wrap.transition()
69310                 .styleTween('right', function() { return interpolateValue('-100%', '0%'); });
69311
69312             editorPane
69313                 .call(entityEditor.preset(preset));
69314         }
69315     }
69316
69317
69318     inspector.state = function(_) {
69319         if (!arguments.length) return state;
69320         state = _;
69321         entityEditor.state(state);
69322         return inspector;
69323     };
69324
69325
69326     inspector.entityID = function(_) {
69327         if (!arguments.length) return entityID;
69328         entityID = _;
69329         return inspector;
69330     };
69331
69332
69333     inspector.newFeature = function(_) {
69334         if (!arguments.length) return newFeature;
69335         newFeature = _;
69336         return inspector;
69337     };
69338
69339
69340     return inspector;
69341 }
69342
69343 function uiNotice(context) {
69344
69345     return function(selection) {
69346         var div = selection
69347             .append('div')
69348             .attr('class', 'notice');
69349
69350         var button = div
69351             .append('button')
69352             .attr('class', 'zoom-to notice')
69353             .on('click', function() { context.map().zoom(context.minEditableZoom()); });
69354
69355         button
69356             .call(svgIcon('#icon-plus', 'pre-text'))
69357             .append('span')
69358             .attr('class', 'label')
69359             .text(t('zoom_in_edit'));
69360
69361
69362         function disableTooHigh() {
69363             div.style('display', context.editable() ? 'none' : 'block');
69364         }
69365
69366         context.map()
69367             .on('move.notice', lodash.debounce(disableTooHigh, 500));
69368
69369         disableTooHigh();
69370     };
69371 }
69372
69373 function uiSidebar(context) {
69374     var inspector = uiInspector(context),
69375         current;
69376
69377
69378     function sidebar(selection) {
69379         var featureListWrap = selection
69380             .append('div')
69381             .attr('class', 'feature-list-pane')
69382             .call(uiFeatureList(context));
69383
69384         selection
69385             .call(uiNotice(context));
69386
69387         var inspectorWrap = selection
69388             .append('div')
69389             .attr('class', 'inspector-hidden inspector-wrap fr');
69390
69391
69392         function hover(id) {
69393             if (!current && context.hasEntity(id)) {
69394                 featureListWrap
69395                     .classed('inspector-hidden', true);
69396
69397                 inspectorWrap
69398                     .classed('inspector-hidden', false)
69399                     .classed('inspector-hover', true);
69400
69401                 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
69402                     inspector
69403                         .state('hover')
69404                         .entityID(id);
69405
69406                     inspectorWrap
69407                         .call(inspector);
69408                 }
69409
69410             } else if (!current) {
69411                 featureListWrap
69412                     .classed('inspector-hidden', false);
69413                 inspectorWrap
69414                     .classed('inspector-hidden', true);
69415                 inspector
69416                     .state('hide');
69417             }
69418         }
69419
69420
69421         sidebar.hover = lodash.throttle(hover, 200);
69422
69423
69424         sidebar.select = function(id, newFeature) {
69425             if (!current && id) {
69426                 featureListWrap
69427                     .classed('inspector-hidden', true);
69428
69429                 inspectorWrap
69430                     .classed('inspector-hidden', false)
69431                     .classed('inspector-hover', false);
69432
69433                 if (inspector.entityID() !== id || inspector.state() !== 'select') {
69434                     inspector
69435                         .state('select')
69436                         .entityID(id)
69437                         .newFeature(newFeature);
69438
69439                     inspectorWrap
69440                         .call(inspector);
69441                 }
69442
69443             } else if (!current) {
69444                 featureListWrap
69445                     .classed('inspector-hidden', false);
69446                 inspectorWrap
69447                     .classed('inspector-hidden', true);
69448                 inspector
69449                     .state('hide');
69450             }
69451         };
69452
69453
69454         sidebar.show = function(component) {
69455             featureListWrap
69456                 .classed('inspector-hidden', true);
69457             inspectorWrap
69458                 .classed('inspector-hidden', true);
69459
69460             if (current) current.remove();
69461             current = selection
69462                 .append('div')
69463                 .attr('class', 'sidebar-component')
69464                 .call(component);
69465         };
69466
69467
69468         sidebar.hide = function() {
69469             featureListWrap
69470                 .classed('inspector-hidden', false);
69471             inspectorWrap
69472                 .classed('inspector-hidden', true);
69473
69474             if (current) current.remove();
69475             current = null;
69476         };
69477     }
69478
69479
69480     sidebar.hover = function() {};
69481     sidebar.hover.cancel = function() {};
69482     sidebar.select = function() {};
69483     sidebar.show = function() {};
69484     sidebar.hide = function() {};
69485
69486     return sidebar;
69487 }
69488
69489 function uiSpinner(context) {
69490     var connection = context.connection();
69491
69492
69493     return function(selection) {
69494         var img = selection
69495             .append('img')
69496             .attr('src', context.imagePath('loader-black.gif'))
69497             .style('opacity', 0);
69498
69499         connection
69500             .on('loading.spinner', function() {
69501                 img.transition()
69502                     .style('opacity', 1);
69503             });
69504
69505         connection
69506             .on('loaded.spinner', function() {
69507                 img.transition()
69508                     .style('opacity', 0);
69509             });
69510     };
69511 }
69512
69513 function uiSplash(context) {
69514
69515     return function(selection) {
69516         if (context.storage('sawSplash'))
69517              return;
69518
69519         context.storage('sawSplash', true);
69520
69521         var modalSelection = uiModal(selection);
69522
69523         modalSelection.select('.modal')
69524             .attr('class', 'modal-splash modal col6');
69525
69526         var introModal = modalSelection.select('.content')
69527             .append('div')
69528             .attr('class', 'fillL');
69529
69530         introModal
69531             .append('div')
69532             .attr('class','modal-section cf')
69533             .append('h3').text(t('splash.welcome'));
69534
69535         introModal
69536             .append('div')
69537             .attr('class','modal-section')
69538             .append('p')
69539             .html(t('splash.text', {
69540                 version: context.version,
69541                 website: '<a href="http://ideditor.com/">ideditor.com</a>',
69542                 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
69543             }));
69544
69545         var buttonWrap = introModal
69546             .append('div')
69547             .attr('class', 'modal-actions cf');
69548
69549         var walkthrough = buttonWrap
69550             .append('button')
69551             .attr('class', 'walkthrough col6')
69552             .on('click', function() {
69553                 context.container().call(uiIntro(context));
69554                 modalSelection.close();
69555             });
69556
69557         walkthrough
69558             .append('svg')
69559             .attr('class', 'logo logo-walkthrough')
69560             .append('use')
69561             .attr('xlink:href', '#logo-walkthrough');
69562
69563         walkthrough
69564             .append('div')
69565             .text(t('splash.walkthrough'));
69566
69567         var startEditing = buttonWrap
69568             .append('button')
69569             .attr('class', 'start-editing col6')
69570             .on('click', modalSelection.close);
69571
69572         startEditing
69573             .append('svg')
69574             .attr('class', 'logo logo-features')
69575             .append('use')
69576             .attr('xlink:href', '#logo-features');
69577
69578         startEditing
69579             .append('div')
69580             .text(t('splash.start'));
69581
69582
69583         modalSelection.select('button.close')
69584             .attr('class','hide');
69585
69586     };
69587 }
69588
69589 function uiStatus(context) {
69590     var connection = context.connection();
69591
69592     return function(selection$$1) {
69593
69594         function update() {
69595             connection.status(function(err, apiStatus) {
69596                 selection$$1.html('');
69597
69598                 if (err) {
69599                     if (apiStatus === 'rateLimited') {
69600                         selection$$1
69601                             .text(t('status.rateLimit'))
69602                             .append('a')
69603                             .attr('class', 'api-status-login')
69604                             .attr('target', '_blank')
69605                             .call(svgIcon('#icon-out-link', 'inline'))
69606                             .append('span')
69607                             .text(t('login'))
69608                             .on('click.login', function() {
69609                                 event.preventDefault();
69610                                 connection.authenticate();
69611                             });
69612                     } else {
69613                         // TODO: nice messages for different error types
69614                         selection$$1.text(t('status.error'));
69615                     }
69616
69617                 } else if (apiStatus === 'readonly') {
69618                     selection$$1.text(t('status.readonly'));
69619                 } else if (apiStatus === 'offline') {
69620                     selection$$1.text(t('status.offline'));
69621                 }
69622
69623                 selection$$1.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
69624             });
69625         }
69626
69627         connection
69628             .on('change', function() { update(selection$$1); });
69629
69630         window.setInterval(update, 90000);
69631         update(selection$$1);
69632     };
69633 }
69634
69635 function uiUndoRedo(context) {
69636     var commands = [{
69637         id: 'undo',
69638         cmd: uiCmd('⌘Z'),
69639         action: function() { if (!saving()) context.undo(); },
69640         annotation: function() { return context.history().undoAnnotation(); }
69641     }, {
69642         id: 'redo',
69643         cmd: uiCmd('⌘⇧Z'),
69644         action: function() { if (!saving()) context.redo(); },
69645         annotation: function() { return context.history().redoAnnotation(); }
69646     }];
69647
69648
69649     function saving() {
69650         return context.mode().id === 'save';
69651     }
69652
69653
69654     return function(selection$$1) {
69655         var tooltipBehavior = tooltip()
69656             .placement('bottom')
69657             .html(true)
69658             .title(function (d) {
69659                 return uiTooltipHtml(d.annotation() ?
69660                     t(d.id + '.tooltip', {action: d.annotation()}) :
69661                     t(d.id + '.nothing'), d.cmd);
69662             });
69663
69664         var buttons = selection$$1.selectAll('button')
69665             .data(commands)
69666             .enter()
69667             .append('button')
69668             .attr('class', function(d) { return 'col6 disabled ' + d.id + '-button'; })
69669             .on('click', function(d) { return d.action(); })
69670             .call(tooltipBehavior);
69671
69672         buttons.each(function(d) {
69673             var iconName = d.id;
69674             if (textDirection === 'rtl') {
69675                 if (iconName === 'undo') {
69676                     iconName = 'redo';
69677                 } else if (iconName === 'redo') {
69678                     iconName = 'undo';
69679                 }
69680             }
69681             select(this)
69682                 .call(svgIcon('#icon-' + iconName));
69683         });
69684
69685         var keybinding = d3keybinding('undo')
69686             .on(commands[0].cmd, function() { event.preventDefault(); commands[0].action(); })
69687             .on(commands[1].cmd, function() { event.preventDefault(); commands[1].action(); });
69688
69689         select(document)
69690             .call(keybinding);
69691
69692         context.history()
69693             .on('change.undo_redo', update);
69694
69695         context
69696             .on('enter.undo_redo', update);
69697
69698         function update() {
69699             buttons
69700                 .property('disabled', saving())
69701                 .classed('disabled', function(d) { return !d.annotation(); })
69702                 .each(function() {
69703                     var selection$$1 = select(this);
69704                     if (selection$$1.property('tooltipVisible')) {
69705                         selection$$1.call(tooltipBehavior.show);
69706                     }
69707                 });
69708         }
69709     };
69710 }
69711
69712 // these are module variables so they are preserved through a ui.restart()
69713 var sawVersion = null;
69714 var isNewVersion = false;
69715 var isNewUser = false;
69716
69717
69718 function uiVersion(context) {
69719
69720     var currVersion = context.version,
69721         matchedVersion = currVersion.match(/\d\.\d\.\d.*/);
69722
69723     if (sawVersion === null && matchedVersion !== null) {
69724         isNewVersion = (context.storage('sawVersion') !== currVersion);
69725         isNewUser = !context.storage('sawSplash');
69726         context.storage('sawVersion', currVersion);
69727         sawVersion = currVersion;
69728     }
69729
69730     return function(selection) {
69731         selection
69732             .append('a')
69733             .attr('target', '_blank')
69734             .attr('tabindex', -1)
69735             .attr('href', 'https://github.com/openstreetmap/iD')
69736             .text(currVersion);
69737
69738         // only show new version indicator to users that have used iD before
69739         if (isNewVersion && !isNewUser) {
69740             selection
69741                 .append('div')
69742                 .attr('class', 'badge')
69743                 .append('a')
69744                 .attr('target', '_blank')
69745                 .attr('tabindex', -1)
69746                 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CHANGELOG.md#whats-new')
69747                 .call(svgIcon('#gift-11'))
69748                 .call(tooltip()
69749                     .title(t('version.whats_new', { version: currVersion }))
69750                     .placement('top')
69751                 );
69752         }
69753     };
69754 }
69755
69756 function uiZoom(context) {
69757     var zooms = [{
69758         id: 'zoom-in',
69759         icon: 'plus',
69760         title: t('zoom.in'),
69761         action: context.zoomIn,
69762         key: '+'
69763     }, {
69764         id: 'zoom-out',
69765         icon: 'minus',
69766         title: t('zoom.out'),
69767         action: context.zoomOut,
69768         key: '-'
69769     }];
69770
69771
69772     function zoomIn() {
69773         event.preventDefault();
69774         context.zoomIn();
69775     }
69776
69777
69778     function zoomOut() {
69779         event.preventDefault();
69780         context.zoomOut();
69781     }
69782
69783
69784     function zoomInFurther() {
69785         event.preventDefault();
69786         context.zoomInFurther();
69787     }
69788
69789
69790     function zoomOutFurther() {
69791         event.preventDefault();
69792         context.zoomOutFurther();
69793     }
69794
69795
69796     return function(selection$$1) {
69797         var button = selection$$1.selectAll('button')
69798             .data(zooms)
69799             .enter()
69800             .append('button')
69801             .attr('tabindex', -1)
69802             .attr('class', function(d) { return d.id; })
69803             .on('click.editor', function(d) { d.action(); })
69804             .call(tooltip()
69805                 .placement((textDirection === 'rtl') ? 'right' : 'left')
69806                 .html(true)
69807                 .title(function(d) {
69808                     return uiTooltipHtml(d.title, d.key);
69809                 })
69810             );
69811
69812         button.each(function(d) {
69813             select(this)
69814                 .call(svgIcon('#icon-' + d.icon, 'light'));
69815         });
69816
69817         var keybinding = d3keybinding('zoom');
69818
69819         lodash.each(['=','ffequals','plus','ffplus'], function(key) {
69820             keybinding.on([key, '⇧' + key], zoomIn);
69821             keybinding.on([uiCmd('⌘' + key), uiCmd('⌘⇧' + key)], zoomInFurther);
69822         });
69823         lodash.each(['-','ffminus','dash'], function(key) {
69824             keybinding.on([key, '⇧' + key], zoomOut);
69825             keybinding.on([uiCmd('⌘' + key), uiCmd('⌘⇧' + key)], zoomOutFurther);
69826         });
69827
69828         select(document)
69829             .call(keybinding);
69830     };
69831 }
69832
69833 function uiInit(context) {
69834     var uiInitCounter = 0;
69835
69836
69837     function render(container) {
69838         container
69839             .attr('dir', textDirection);
69840
69841         var map$$1 = context.map();
69842
69843         var hash = behaviorHash(context);
69844         hash();
69845
69846         if (!hash.hadHash) {
69847             map$$1.centerZoom([0, 0], 2);
69848         }
69849
69850         container
69851             .append('svg')
69852             .attr('id', 'defs')
69853             .call(svgDefs(context));
69854
69855         container
69856             .append('div')
69857             .attr('id', 'sidebar')
69858             .attr('class', 'col4')
69859             .call(ui.sidebar);
69860
69861         var content = container
69862             .append('div')
69863             .attr('id', 'content')
69864             .attr('class', 'active');
69865
69866         var bar = content
69867             .append('div')
69868             .attr('id', 'bar')
69869             .attr('class', 'fillD');
69870
69871         content
69872             .append('div')
69873             .attr('id', 'map')
69874             .attr('dir', 'ltr')
69875             .call(map$$1);
69876
69877         content
69878             .call(uiMapInMap(context));
69879
69880         content
69881             .append('div')
69882             .call(uiInfo(context));
69883
69884         bar
69885             .append('div')
69886             .attr('class', 'spacer col4');
69887
69888         var limiter = bar.append('div')
69889             .attr('class', 'limiter');
69890
69891         limiter
69892             .append('div')
69893             .attr('class', 'button-wrap joined col3')
69894             .call(uiModes(context), limiter);
69895
69896         limiter
69897             .append('div')
69898             .attr('class', 'button-wrap joined col1')
69899             .call(uiUndoRedo(context));
69900
69901         limiter
69902             .append('div')
69903             .attr('class', 'button-wrap col1')
69904             .call(uiSave(context));
69905
69906         bar
69907             .append('div')
69908             .attr('class', 'full-screen')
69909             .call(uiFullScreen(context));
69910
69911         bar
69912             .append('div')
69913             .attr('class', 'spinner')
69914             .call(uiSpinner(context));
69915
69916
69917         var controls = bar
69918             .append('div')
69919             .attr('class', 'map-controls');
69920
69921         controls
69922             .append('div')
69923             .attr('class', 'map-control zoombuttons')
69924             .call(uiZoom(context));
69925
69926         controls
69927             .append('div')
69928             .attr('class', 'map-control geolocate-control')
69929             .call(uiGeolocate(context));
69930
69931         controls
69932             .append('div')
69933             .attr('class', 'map-control background-control')
69934             .call(uiBackground(context));
69935
69936         controls
69937             .append('div')
69938             .attr('class', 'map-control map-data-control')
69939             .call(uiMapData(context));
69940
69941         controls
69942             .append('div')
69943             .attr('class', 'map-control help-control')
69944             .call(uiHelp(context));
69945
69946
69947         var about = content
69948             .append('div')
69949             .attr('id', 'about');
69950
69951         about
69952             .append('div')
69953             .attr('id', 'attrib')
69954             .attr('dir', 'ltr')
69955             .call(uiAttribution(context));
69956
69957         about
69958             .append('div')
69959             .attr('class', 'api-status')
69960             .call(uiStatus(context));
69961
69962
69963         var footer = about
69964             .append('div')
69965             .attr('id', 'footer')
69966             .attr('class', 'fillD');
69967
69968         footer
69969             .append('div')
69970             .attr('id', 'flash-wrap')
69971             .attr('class', 'footer-hide');
69972
69973         var footerWrap = footer
69974             .append('div')
69975             .attr('id', 'footer-wrap')
69976             .attr('class', 'footer-show');
69977
69978         footerWrap
69979             .append('div')
69980             .attr('id', 'scale-block')
69981             .call(uiScale(context));
69982
69983         var aboutList = footerWrap
69984             .append('div')
69985             .attr('id', 'info-block')
69986             .append('ul')
69987             .attr('id', 'about-list');
69988
69989         if (!context.embed()) {
69990             aboutList
69991                 .call(uiAccount(context));
69992         }
69993
69994         aboutList
69995             .append('li')
69996             .attr('class', 'version')
69997             .call(uiVersion(context));
69998
69999         var issueLinks = aboutList
70000             .append('li');
70001
70002         issueLinks
70003             .append('a')
70004             .attr('target', '_blank')
70005             .attr('tabindex', -1)
70006             .attr('href', 'https://github.com/openstreetmap/iD/issues')
70007             .call(svgIcon('#icon-bug', 'light'))
70008             .call(tooltip().title(t('report_a_bug')).placement('top'));
70009
70010         issueLinks
70011             .append('a')
70012             .attr('target', '_blank')
70013             .attr('tabindex', -1)
70014             .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
70015             .call(svgIcon('#icon-translate', 'light'))
70016             .call(tooltip().title(t('help_translate')).placement('top'));
70017
70018         aboutList
70019             .append('li')
70020             .attr('class', 'feature-warning')
70021             .attr('tabindex', -1)
70022             .call(uiFeatureInfo(context));
70023
70024         aboutList
70025             .append('li')
70026             .attr('class', 'user-list')
70027             .attr('tabindex', -1)
70028             .call(uiContributors(context));
70029
70030
70031         window.onbeforeunload = function() {
70032             return context.save();
70033         };
70034
70035         window.onunload = function() {
70036             context.history().unlock();
70037         };
70038
70039         var mapDimensions = map$$1.dimensions();
70040
70041
70042         function onResize() {
70043             mapDimensions = utilGetDimensions(content, true);
70044             map$$1.dimensions(mapDimensions);
70045         }
70046
70047         select(window)
70048             .on('resize.editor', onResize);
70049
70050         onResize();
70051
70052         function pan(d) {
70053             return function() {
70054                 event.preventDefault();
70055                 context.pan(d, 100);
70056             };
70057         }
70058
70059
70060         // pan amount
70061         var pa = 10;
70062
70063         var keybinding = d3keybinding('main')
70064             .on('⌫', function() { event.preventDefault(); })
70065             .on('←', pan([pa, 0]))
70066             .on('↑', pan([0, pa]))
70067             .on('→', pan([-pa, 0]))
70068             .on('↓', pan([0, -pa]))
70069             .on(['⇧←', uiCmd('⌘←')], pan([mapDimensions[0], 0]))
70070             .on(['⇧↑', uiCmd('⌘↑')], pan([0, mapDimensions[1]]))
70071             .on(['⇧→', uiCmd('⌘→')], pan([-mapDimensions[0], 0]))
70072             .on(['⇧↓', uiCmd('⌘↓')], pan([0, -mapDimensions[1]]));
70073
70074         select(document)
70075             .call(keybinding);
70076
70077         context.enter(modeBrowse(context));
70078
70079         if (!uiInitCounter++) {
70080             context.container()
70081                 .call(uiSplash(context))
70082                 .call(uiRestore(context));
70083         }
70084
70085         var authenticating = uiLoading(context)
70086             .message(t('loading_auth'))
70087             .blocking(true);
70088
70089         context.connection()
70090             .on('authLoading.ui', function() {
70091                 context.container()
70092                     .call(authenticating);
70093             })
70094             .on('authDone.ui', function() {
70095                 authenticating.close();
70096             });
70097
70098         uiInitCounter++;
70099     }
70100
70101
70102     var renderCallback;
70103
70104     function ui(node, callback) {
70105         renderCallback = callback;
70106         var container = select(node);
70107         context.container(container);
70108         context.loadLocale(function(err) {
70109             if (!err) {
70110                 render(container);
70111             }
70112             if (callback) {
70113                 callback(err);
70114             }
70115         });
70116     }
70117
70118
70119     ui.restart = function(arg) {
70120         context.locale(arg);
70121         context.loadLocale(function(err) {
70122             if (!err) {
70123                 context.container().selectAll('*').remove();
70124                 render(context.container());
70125                 if (renderCallback) renderCallback();
70126             }
70127         });
70128     };
70129
70130
70131     ui.sidebar = uiSidebar(context);
70132
70133     return ui;
70134 }
70135
70136 var changeset;
70137 var readOnlyTags = ['created_by', 'imagery_used', 'host', 'locale'];
70138
70139
70140 function uiCommit(context) {
70141     var dispatch$$1 = dispatch('cancel', 'save');
70142
70143
70144     function commit(selection$$1) {
70145         if (!changeset) {
70146             var detected = utilDetect(),
70147                 tags = {
70148                     created_by: ('iD ' + context.version).substr(0, 255),
70149                     imagery_used: context.history().imageryUsed().join(';').substr(0, 255),
70150                     host: detected.host.substr(0, 255),
70151                     locale: detected.locale.substr(0, 255)
70152                 };
70153
70154             changeset = new osmChangeset({ tags: tags });
70155         }
70156
70157
70158         var changes = context.history().changes(),
70159             summary = context.history().difference().summary(),
70160             rawTagEditor = uiRawTagEditor(context).on('change', changeTags),
70161             comment = context.storage('comment') || '',
70162             commentDate = +context.storage('commentDate') || 0,
70163             currDate = Date.now(),
70164             cutoff = 2 * 86400 * 1000;   // 2 days
70165
70166         // expire the stored comment if it is too old - #3947
70167         if (commentDate > currDate || currDate - commentDate > cutoff) {
70168             comment = '';
70169         }
70170
70171         selection$$1
70172             .append('div')
70173             .attr('class', 'header fillL')
70174             .append('h3')
70175             .text(t('commit.title'));
70176
70177         var body = selection$$1
70178             .append('div')
70179             .attr('class', 'body');
70180
70181         var commentSection = body
70182             .append('div')
70183             .attr('class', 'modal-section form-field commit-form');
70184
70185         commentSection
70186             .append('label')
70187             .attr('class', 'form-label')
70188             .text(t('commit.message_label'));
70189
70190         var commentField = commentSection
70191             .append('textarea')
70192             .attr('class', 'commit-form-comment')
70193             .attr('placeholder', t('commit.description_placeholder'))
70194             .attr('maxlength', 255)
70195             .property('value', comment)
70196             .on('input.save', change(true))
70197             .on('change.save', change())
70198             .on('blur.save', function() {
70199                 context.storage('comment', this.value);
70200                 context.storage('commentDate', Date.now());
70201             });
70202
70203
70204         commentField.node().select();
70205
70206         context.connection().userChangesets(function (err, changesets) {
70207             if (err) return;
70208
70209             var comments = changesets.map(function(changeset) {
70210                 return {
70211                     title: changeset.tags.comment,
70212                     value: changeset.tags.comment
70213                 };
70214             });
70215
70216             commentField
70217                 .call(d3combobox()
70218                     .container(context.container())
70219                     .caseSensitive(true)
70220                     .data(lodash.uniqBy(comments, 'title'))
70221                 );
70222         });
70223
70224         var clippyArea = commentSection.append('div')
70225             .attr('class', 'clippy-area');
70226
70227         var changeSetInfo = commentSection.append('div')
70228             .attr('class', 'changeset-info');
70229
70230         changeSetInfo.append('a')
70231             .attr('target', '_blank')
70232             .attr('tabindex', -1)
70233             .call(svgIcon('#icon-out-link', 'inline'))
70234             .attr('href', t('commit.about_changeset_comments_link'))
70235             .append('span')
70236             .text(t('commit.about_changeset_comments'));
70237
70238
70239         // Warnings
70240         var warnings = body.selectAll('div.warning-section')
70241             .data([context.history().validate(changes)]);
70242
70243         warnings = warnings.enter()
70244             .append('div')
70245             .attr('class', 'modal-section warning-section fillL2')
70246             .style('display', function(d) { return lodash.isEmpty(d) ? 'none' : null; })
70247             .style('background', '#ffb')
70248             .merge(warnings);
70249
70250         warnings
70251             .append('h3')
70252             .text(t('commit.warnings'));
70253
70254         warnings
70255             .append('ul')
70256             .attr('class', 'changeset-list');
70257
70258         var warningLi = warnings.select('ul').selectAll('li')
70259             .data(function(d) { return d; });
70260
70261         warningLi = warningLi.enter()
70262             .append('li')
70263             .on('mouseover', mouseover)
70264             .on('mouseout', mouseout)
70265             .on('click', warningClick)
70266             .merge(warningLi);
70267
70268         warningLi
70269             .call(svgIcon('#icon-alert', 'pre-text'));
70270
70271         warningLi
70272             .append('strong')
70273             .text(function(d) { return d.message; });
70274
70275         warningLi.filter(function(d) { return d.tooltip; })
70276             .call(tooltip()
70277                 .title(function(d) { return d.tooltip; })
70278                 .placement('top')
70279             );
70280
70281
70282         // Upload Explanation
70283         var saveSection = body
70284             .append('div')
70285             .attr('class','modal-section save-section fillL cf');
70286
70287         var prose = saveSection
70288             .append('p')
70289             .attr('class', 'commit-info')
70290             .html(t('commit.upload_explanation'));
70291
70292
70293         context.connection().userDetails(function(err, user) {
70294             if (err) return;
70295
70296             var userLink = select(document.createElement('div'));
70297
70298             if (user.image_url) {
70299                 userLink
70300                     .append('img')
70301                     .attr('src', user.image_url)
70302                     .attr('class', 'icon pre-text user-icon');
70303             }
70304
70305             userLink
70306                 .append('a')
70307                 .attr('class','user-info')
70308                 .text(user.display_name)
70309                 .attr('href', context.connection().userURL(user.display_name))
70310                 .attr('tabindex', -1)
70311                 .attr('target', '_blank');
70312
70313             prose
70314                 .html(t('commit.upload_explanation_with_user', { user: userLink.html() }));
70315         });
70316
70317
70318         // Buttons
70319         var buttonSection = saveSection
70320             .append('div')
70321             .attr('class', 'buttons fillL cf');
70322
70323         var cancelButton = buttonSection
70324             .append('button')
70325             .attr('class', 'secondary-action col5 button cancel-button')
70326             .on('click.cancel', function() {
70327                 dispatch$$1.call('cancel');
70328             });
70329
70330         cancelButton
70331             .append('span')
70332             .attr('class', 'label')
70333             .text(t('commit.cancel'));
70334
70335         var saveButton = buttonSection
70336             .append('button')
70337             .attr('class', 'action col5 button save-button')
70338             .attr('disabled', function() {
70339                 var n = select('.commit-form textarea').node();
70340                 return (n && n.value.length) ? null : true;
70341             })
70342             .on('click.save', function() {
70343                 dispatch$$1.call('save', this, changeset);
70344             });
70345
70346         saveButton
70347             .append('span')
70348             .attr('class', 'label')
70349             .text(t('commit.save'));
70350
70351
70352         // Raw Tag Editor
70353         var tagSection = body
70354             .append('div')
70355             .attr('class', 'modal-section tag-section raw-tag-editor');
70356
70357
70358         // Changes
70359         var changeSection = body
70360             .append('div')
70361             .attr('class', 'commit-section modal-section fillL2');
70362
70363         changeSection.append('h3')
70364             .text(t('commit.changes', { count: summary.length }));
70365
70366         var li = changeSection
70367             .append('ul')
70368             .attr('class', 'changeset-list')
70369             .selectAll('li')
70370             .data(summary);
70371
70372         li = li.enter()
70373             .append('li')
70374             .on('mouseover', mouseover)
70375             .on('mouseout', mouseout)
70376             .on('click', zoomToEntity)
70377             .merge(li);
70378
70379         li.each(function(d) {
70380             select(this)
70381                 .call(svgIcon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
70382         });
70383
70384         li.append('span')
70385             .attr('class', 'change-type')
70386             .text(function(d) { return t('commit.' + d.changeType) + ' '; });
70387
70388         li.append('strong')
70389             .attr('class', 'entity-type')
70390             .text(function(d) {
70391                 var matched = context.presets().match(d.entity, d.graph);
70392                 return (matched && matched.name()) || utilDisplayType(d.entity.id);
70393             });
70394
70395         li.append('span')
70396             .attr('class', 'entity-name')
70397             .text(function(d) {
70398                 var name = utilDisplayName(d.entity) || '',
70399                     string = '';
70400                 if (name !== '') string += ':';
70401                 return string += ' ' + name;
70402             });
70403
70404         li.style('opacity', 0)
70405             .transition()
70406             .style('opacity', 1);
70407
70408
70409         // Call change() off the bat, in case a changeset
70410         // comment is recovered from localStorage
70411         utilTriggerEvent(commentField, 'input');
70412
70413
70414         function mouseover(d) {
70415             if (d.entity) {
70416                 context.surface().selectAll(
70417                     utilEntityOrMemberSelector([d.entity.id], context.graph())
70418                 ).classed('hover', true);
70419             }
70420         }
70421
70422
70423         function mouseout() {
70424             context.surface().selectAll('.hover')
70425                 .classed('hover', false);
70426         }
70427
70428
70429         function warningClick(d) {
70430             if (d.entity) {
70431                 context.map().zoomTo(d.entity);
70432                 context.enter(modeSelect(context, [d.entity.id]));
70433             }
70434         }
70435
70436
70437         function zoomToEntity(change) {
70438             var entity = change.entity;
70439             if (change.changeType !== 'deleted' &&
70440                 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
70441                 context.map().zoomTo(entity);
70442                 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph()))
70443                     .classed('hover', true);
70444             }
70445         }
70446
70447
70448         function checkComment(comment) {
70449             // Save button disabled if there is no comment..
70450             selectAll('.save-section .save-button')
70451                 .attr('disabled', (comment.length ? null : true));
70452
70453             // Warn if comment mentions Google..
70454             var googleWarning = clippyArea
70455                .html('')
70456                .selectAll('a')
70457                .data(comment.match(/google/i) ? [true] : []);
70458
70459             googleWarning.exit()
70460                 .remove();
70461
70462             googleWarning.enter()
70463                .append('a')
70464                .attr('target', '_blank')
70465                .attr('tabindex', -1)
70466                .call(svgIcon('#icon-alert', 'inline'))
70467                .attr('href', t('commit.google_warning_link'))
70468                .append('span')
70469                .text(t('commit.google_warning'));
70470         }
70471
70472
70473         function change(onInput) {
70474             return function() {
70475                 var comment = commentField.property('value').trim();
70476                 if (!onInput) {
70477                     commentField.property('value', comment);
70478                 }
70479
70480                 checkComment(comment);
70481
70482                 var changeset = updateChangeset({ comment: comment });
70483                 var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();
70484
70485                 tagSection
70486                     .call(rawTagEditor
70487                         .expanded(expanded)
70488                         .readOnlyTags(readOnlyTags)
70489                         .tags(lodash.clone(changeset.tags))
70490                     );
70491             };
70492         }
70493
70494
70495         function changeTags(changed) {
70496             if (changed.hasOwnProperty('comment')) {
70497                 if (changed.comment === undefined) {
70498                     changed.comment = '';
70499                 }
70500                 changed.comment = changed.comment.trim();
70501                 commentField.property('value', changed.comment);
70502             }
70503             updateChangeset(changed);
70504             utilTriggerEvent(commentField, 'input');
70505         }
70506
70507
70508         function updateChangeset(changed) {
70509             var tags = lodash.clone(changeset.tags);
70510
70511             lodash.forEach(changed, function(v, k) {
70512                 k = k.trim().substr(0, 255);
70513                 if (readOnlyTags.indexOf(k) !== -1) return;
70514
70515                 if (k !== '' && v !== undefined) {
70516                     tags[k] = v.trim().substr(0, 255);
70517                 } else {
70518                     delete tags[k];
70519                 }
70520             });
70521
70522             if (!lodash.isEqual(changeset.tags, tags)) {
70523                 changeset = changeset.update({ tags: tags });
70524             }
70525
70526             return changeset;
70527         }
70528
70529     }
70530
70531
70532     commit.reset = function() {
70533         changeset = null;
70534     };
70535
70536
70537     return utilRebind(commit, dispatch$$1, 'on');
70538 }
70539
70540 function uiConfirm(selection) {
70541     var modalSelection = uiModal(selection);
70542
70543     modalSelection.select('.modal')
70544         .classed('modal-alert', true);
70545
70546     var section = modalSelection.select('.content');
70547
70548     section.append('div')
70549         .attr('class', 'modal-section header');
70550
70551     section.append('div')
70552         .attr('class', 'modal-section message-text');
70553
70554     var buttons = section.append('div')
70555         .attr('class', 'modal-section buttons cf');
70556
70557
70558     modalSelection.okButton = function() {
70559         buttons
70560             .append('button')
70561             .attr('class', 'action col4')
70562             .on('click.confirm', function() {
70563                 modalSelection.remove();
70564             })
70565             .text(t('confirm.okay'));
70566
70567         return modalSelection;
70568     };
70569
70570
70571     return modalSelection;
70572 }
70573
70574 function uiConflicts(context) {
70575     var dispatch$$1 = dispatch('download', 'cancel', 'save'),
70576         list;
70577
70578
70579     function conflicts(selection$$1) {
70580         var header = selection$$1
70581             .append('div')
70582             .attr('class', 'header fillL');
70583
70584         header
70585             .append('button')
70586             .attr('class', 'fr')
70587             .on('click', function() { dispatch$$1.call('cancel'); })
70588             .call(svgIcon('#icon-close'));
70589
70590         header
70591             .append('h3')
70592             .text(t('save.conflict.header'));
70593
70594         var body = selection$$1
70595             .append('div')
70596             .attr('class', 'body fillL');
70597
70598         body
70599             .append('div')
70600             .attr('class', 'conflicts-help')
70601             .text(t('save.conflict.help'))
70602             .append('a')
70603             .attr('class', 'conflicts-download')
70604             .text(t('save.conflict.download_changes'))
70605             .on('click.download', function() { dispatch$$1.call('download'); });
70606
70607         body
70608             .append('div')
70609             .attr('class', 'conflict-container fillL3')
70610             .call(showConflict, 0);
70611
70612         body
70613             .append('div')
70614             .attr('class', 'conflicts-done')
70615             .attr('opacity', 0)
70616             .style('display', 'none')
70617             .text(t('save.conflict.done'));
70618
70619         var buttons = body
70620             .append('div')
70621             .attr('class','buttons col12 joined conflicts-buttons');
70622
70623         buttons
70624             .append('button')
70625             .attr('disabled', list.length > 1)
70626             .attr('class', 'action conflicts-button col6')
70627             .text(t('save.title'))
70628             .on('click.try_again', function() { dispatch$$1.call('save'); });
70629
70630         buttons
70631             .append('button')
70632             .attr('class', 'secondary-action conflicts-button col6')
70633             .text(t('confirm.cancel'))
70634             .on('click.cancel', function() { dispatch$$1.call('cancel'); });
70635     }
70636
70637
70638     function showConflict(selection$$1, index) {
70639         if (index < 0 || index >= list.length) return;
70640
70641         var parent = select(selection$$1.node().parentNode);
70642
70643         // enable save button if this is the last conflict being reviewed..
70644         if (index === list.length - 1) {
70645             window.setTimeout(function() {
70646                 parent.select('.conflicts-button')
70647                     .attr('disabled', null);
70648
70649                 parent.select('.conflicts-done')
70650                     .transition()
70651                     .attr('opacity', 1)
70652                     .style('display', 'block');
70653             }, 250);
70654         }
70655
70656         var item = selection$$1
70657             .selectAll('.conflict')
70658             .data([list[index]]);
70659
70660         var enter = item.enter()
70661             .append('div')
70662             .attr('class', 'conflict');
70663
70664         enter
70665             .append('h4')
70666             .attr('class', 'conflict-count')
70667             .text(t('save.conflict.count', { num: index + 1, total: list.length }));
70668
70669         enter
70670             .append('a')
70671             .attr('class', 'conflict-description')
70672             .attr('href', '#')
70673             .text(function(d) { return d.name; })
70674             .on('click', function(d) {
70675                 zoomToEntity(d.id);
70676                 event.preventDefault();
70677             });
70678
70679         var details = enter
70680             .append('div')
70681             .attr('class', 'conflict-detail-container');
70682
70683         details
70684             .append('ul')
70685             .attr('class', 'conflict-detail-list')
70686             .selectAll('li')
70687             .data(function(d) { return d.details || []; })
70688             .enter()
70689             .append('li')
70690             .attr('class', 'conflict-detail-item')
70691             .html(function(d) { return d; });
70692
70693         details
70694             .append('div')
70695             .attr('class', 'conflict-choices')
70696             .call(addChoices);
70697
70698         details
70699             .append('div')
70700             .attr('class', 'conflict-nav-buttons joined cf')
70701             .selectAll('button')
70702             .data(['previous', 'next'])
70703             .enter()
70704             .append('button')
70705             .text(function(d) { return t('save.conflict.' + d); })
70706             .attr('class', 'conflict-nav-button action col6')
70707             .attr('disabled', function(d, i) {
70708                 return (i === 0 && index === 0) ||
70709                     (i === 1 && index === list.length - 1) || null;
70710             })
70711             .on('click', function(d, i) {
70712                 var container = parent.select('.conflict-container'),
70713                 sign = (i === 0 ? -1 : 1);
70714
70715                 container
70716                     .selectAll('.conflict')
70717                     .remove();
70718
70719                 container
70720                     .call(showConflict, index + sign);
70721
70722                 event.preventDefault();
70723             });
70724
70725         item.exit()
70726             .remove();
70727     }
70728
70729
70730     function addChoices(selection$$1) {
70731         var choices = selection$$1
70732             .append('ul')
70733             .attr('class', 'layer-list')
70734             .selectAll('li')
70735             .data(function(d) { return d.choices || []; });
70736
70737         var enter = choices.enter()
70738             .append('li')
70739             .attr('class', 'layer');
70740
70741         var label = enter
70742             .append('label');
70743
70744         label
70745             .append('input')
70746             .attr('type', 'radio')
70747             .attr('name', function(d) { return d.id; })
70748             .on('change', function(d, i) {
70749                 var ul = this.parentNode.parentNode.parentNode;
70750                 ul.__data__.chosen = i;
70751                 choose(ul, d);
70752             });
70753
70754         label
70755             .append('span')
70756             .text(function(d) { return d.text; });
70757
70758         choices
70759             .each(function(d, i) {
70760                 var ul = this.parentNode;
70761                 if (ul.__data__.chosen === i) choose(ul, d);
70762             });
70763     }
70764
70765
70766     function choose(ul, datum) {
70767         if (event) event.preventDefault();
70768
70769         select(ul)
70770             .selectAll('li')
70771             .classed('active', function(d) { return d === datum; })
70772             .selectAll('input')
70773             .property('checked', function(d) { return d === datum; });
70774
70775         var extent$$1 = geoExtent$$1(),
70776             entity;
70777
70778         entity = context.graph().hasEntity(datum.id);
70779         if (entity) extent$$1._extend(entity.extent(context.graph()));
70780
70781         datum.action();
70782
70783         entity = context.graph().hasEntity(datum.id);
70784         if (entity) extent$$1._extend(entity.extent(context.graph()));
70785
70786         zoomToEntity(datum.id, extent$$1);
70787     }
70788
70789
70790     function zoomToEntity(id, extent$$1) {
70791         context.surface().selectAll('.hover')
70792             .classed('hover', false);
70793
70794         var entity = context.graph().hasEntity(id);
70795         if (entity) {
70796             if (extent$$1) {
70797                 context.map().trimmedExtent(extent$$1);
70798             } else {
70799                 context.map().zoomTo(entity);
70800             }
70801             context.surface().selectAll(
70802                 utilEntityOrMemberSelector([entity.id], context.graph()))
70803                 .classed('hover', true);
70804         }
70805     }
70806
70807
70808     // The conflict list should be an array of objects like:
70809     // {
70810     //     id: id,
70811     //     name: entityName(local),
70812     //     details: merge.conflicts(),
70813     //     chosen: 1,
70814     //     choices: [
70815     //         choice(id, keepMine, forceLocal),
70816     //         choice(id, keepTheirs, forceRemote)
70817     //     ]
70818     // }
70819     conflicts.list = function(_) {
70820         if (!arguments.length) return list;
70821         list = _;
70822         return conflicts;
70823     };
70824
70825
70826     return utilRebind(conflicts, dispatch$$1, 'on');
70827 }
70828
70829 function uiEditMenu(context, operations) {
70830     var menu,
70831         center = [0, 0],
70832         offset = [0, 0],
70833         tooltip;
70834
70835     var p = 8,               // top padding
70836         m = 4,               // top margin
70837         h = 15,              // height of icon
70838         vpBottomMargin = 45, // viewport bottom margin
70839         vpSideMargin = 35,   // viewport side margin
70840         buttonWidth = 44,
70841         buttonHeight = (2 * p + h),
70842         menuWidth = buttonWidth,
70843         menuHeight = (2 * m) + operations.length * buttonHeight,
70844         menuSideMargin = 10,
70845         tooltipWidth = 200,
70846         tooltipHeight = 200;  // a reasonable guess, real height depends on tooltip contents
70847
70848
70849     var editMenu = function (selection$$1) {
70850         if (!operations.length) return;
70851
70852         selection$$1.node().parentNode.focus();
70853
70854         var isRTL = textDirection === 'rtl',
70855             viewport = context.surfaceRect();
70856
70857         if (!isRTL && (center[0] + menuSideMargin + menuWidth) > (viewport.width - vpSideMargin)) {
70858             // menu is going left-to-right and near right viewport edge, go left instead
70859             isRTL = true;
70860         } else if (isRTL && (center[0] - menuSideMargin - menuWidth) < vpSideMargin) {
70861             // menu is going right-to-left and near left viewport edge, go right instead
70862             isRTL = false;
70863         }
70864
70865         offset[0] = (isRTL ? -1 * (menuSideMargin + menuWidth) : menuSideMargin);
70866
70867         if (center[1] + menuHeight > (viewport.height - vpBottomMargin)) {
70868             // menu is near bottom viewport edge, shift upwards
70869             offset[1] = -1 * (center[1] + menuHeight - viewport.height + vpBottomMargin);
70870         }
70871
70872         var origin = [ center[0] + offset[0], center[1] + offset[1] ];
70873
70874         menu = selection$$1
70875             .append('g')
70876             .attr('class', 'edit-menu')
70877             .attr('transform', 'translate(' + origin + ')')
70878             .attr('opacity', 0);
70879
70880         menu
70881             .transition()
70882             .attr('opacity', 1);
70883
70884         menu
70885             .append('rect')
70886             .attr('class', 'edit-menu-background')
70887             .attr('x', 4)
70888             .attr('rx', 4)
70889             .attr('ry', 4)
70890             .attr('width', menuWidth)
70891             .attr('height', menuHeight)
70892             .attr('stroke-linecap', 'round');
70893
70894
70895         var button = menu.selectAll('.edit-menu-item')
70896             .data(operations)
70897             .enter()
70898             .append('g')
70899             .attr('class', function (d) { return 'edit-menu-item edit-menu-item-' + d.id; })
70900             .classed('disabled', function (d) { return d.disabled(); })
70901             .attr('transform', function (d, i) {
70902                 return 'translate(' + geoRoundCoords([
70903                     0,
70904                     m + i * buttonHeight
70905                 ]).join(',') + ')';
70906             });
70907
70908         button
70909             .append('rect')
70910             .attr('x', 4)
70911             .attr('width', buttonWidth)
70912             .attr('height', buttonHeight)
70913             .on('click', click)
70914             .on('mousedown', mousedown)
70915             .on('mouseover', mouseover)
70916             .on('mouseout', mouseout);
70917
70918         button
70919             .append('use')
70920             .attr('width', '20')
70921             .attr('height', '20')
70922             .attr('transform', function () {
70923                 return 'translate(' + [2 * p, 5] + ')';
70924             })
70925             .attr('xlink:href', function (d) { return '#operation-' + d.id; });
70926
70927         tooltip = select(document.body)
70928             .append('div')
70929             .attr('class', 'tooltip-inner edit-menu-tooltip');
70930
70931
70932         function click(operation) {
70933             event.stopPropagation();
70934             if (operation.disabled()) return;
70935             operation();
70936             editMenu.close();
70937         }
70938
70939         function mousedown() {
70940             event.stopPropagation();  // https://github.com/openstreetmap/iD/issues/1869
70941         }
70942
70943         function mouseover(d, i) {
70944             var tipX, tipY;
70945
70946             if (!isRTL) {
70947                 tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
70948             } else {
70949                 tipX = viewport.left + origin[0] - 4 - tooltipWidth;
70950             }
70951
70952             if (tipX + tooltipWidth > viewport.right) {
70953                 // tip is going left-to-right and near right viewport edge, go left instead
70954                 tipX = viewport.left + origin[0] - 4 - tooltipWidth;
70955             } else if (tipX < viewport.left) {
70956                 // tip is going right-to-left and near left viewport edge, go right instead
70957                 tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
70958             }
70959
70960             tipY = viewport.top + origin[1] + (i * buttonHeight);
70961             if (tipY + tooltipHeight > viewport.bottom) {
70962                 // tip is near bottom viewport edge, shift upwards
70963                 tipY -= tipY + tooltipHeight - viewport.bottom;
70964             }
70965
70966             tooltip
70967                 .style('left', tipX + 'px')
70968                 .style('top', tipY + 'px')
70969                 .style('display', 'block')
70970                 .html(uiTooltipHtml(d.tooltip(), d.keys[0], d.title));
70971         }
70972
70973         function mouseout() {
70974             tooltip.style('display', 'none');
70975         }
70976     };
70977
70978
70979     editMenu.close = function () {
70980         if (menu) {
70981             menu
70982                 .style('pointer-events', 'none')
70983                 .transition()
70984                 .attr('opacity', 0)
70985                 .remove();
70986         }
70987
70988         if (tooltip) {
70989             tooltip.remove();
70990         }
70991     };
70992
70993
70994     editMenu.center = function (_) {
70995         if (!arguments.length) return center;
70996         center = _;
70997         return editMenu;
70998     };
70999
71000
71001     return editMenu;
71002 }
71003
71004 var timer$1;
71005
71006 function uiFlash(showDuration) {
71007     showDuration = showDuration || 1500;
71008
71009     if (timer$1) {
71010         timer$1.stop();
71011     }
71012
71013     select('#footer-wrap')
71014         .attr('class', 'footer-hide');
71015     select('#flash-wrap')
71016         .attr('class', 'footer-show');
71017
71018     var content = select('#flash-wrap').selectAll('.content')
71019         .data([0]);
71020
71021     content = content.enter()
71022         .append('div')
71023         .attr('class', 'content')
71024         .merge(content);
71025
71026     timer$1 = timeout$1(function() {
71027         timer$1 = null;
71028         select('#footer-wrap')
71029             .attr('class', 'footer-show');
71030         select('#flash-wrap')
71031             .attr('class', 'footer-hide');
71032     }, showDuration);
71033
71034
71035     return content;
71036 }
71037
71038 function uiLasso(context) {
71039     var group, polygon;
71040
71041     lasso.coordinates = [];
71042
71043     function lasso(selection$$1) {
71044         context.container()
71045             .classed('lasso', true);
71046
71047         group = selection$$1
71048             .append('g')
71049             .attr('class', 'lasso hide');
71050
71051         polygon = group
71052             .append('path')
71053             .attr('class', 'lasso-path');
71054
71055         group
71056             .call(uiToggle(true));
71057     }
71058
71059
71060     function draw() {
71061         if (polygon) {
71062             polygon.data([lasso.coordinates])
71063                 .attr('d', function(d) { return 'M' + d.join(' L') + ' Z'; });
71064         }
71065     }
71066
71067
71068     lasso.extent = function () {
71069         return lasso.coordinates.reduce(function(extent$$1, point) {
71070             return extent$$1.extend(geoExtent$$1(point));
71071         }, geoExtent$$1());
71072     };
71073
71074
71075     lasso.p = function(_) {
71076         if (!arguments.length) return lasso;
71077         lasso.coordinates.push(_);
71078         draw();
71079         return lasso;
71080     };
71081
71082
71083     lasso.close = function() {
71084         if (group) {
71085             group.call(uiToggle(false, function() {
71086                 select(this).remove();
71087             }));
71088         }
71089         context.container().classed('lasso', false);
71090     };
71091
71092
71093     return lasso;
71094 }
71095
71096 function uiRadialMenu(context, operations) {
71097     var menu,
71098         center = [0, 0],
71099         tooltip;
71100
71101
71102     var radialMenu = function(selection$$1) {
71103         if (!operations.length) return;
71104
71105         selection$$1.node().parentNode.focus();
71106
71107         function click(operation) {
71108             event.stopPropagation();
71109             if (operation.disabled()) return;
71110             operation();
71111             radialMenu.close();
71112         }
71113
71114         menu = selection$$1
71115             .append('g')
71116             .attr('class', 'radial-menu')
71117             .attr('transform', 'translate(' + center + ')')
71118             .attr('opacity', 0);
71119
71120         menu
71121             .transition()
71122             .attr('opacity', 1);
71123
71124         var r = 50,
71125             a = Math.PI / 4,
71126             a0 = -Math.PI / 4,
71127             a1 = a0 + (operations.length - 1) * a;
71128
71129         menu
71130             .append('path')
71131             .attr('class', 'radial-menu-background')
71132             .attr('d', 'M' + r * Math.sin(a0) + ',' +
71133                              r * Math.cos(a0) +
71134                       ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
71135                              (r * Math.sin(a1) + 1e-3) + ',' +
71136                              (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
71137             .attr('stroke-width', 50)
71138             .attr('stroke-linecap', 'round');
71139
71140         var button = menu.selectAll()
71141             .data(operations)
71142             .enter()
71143             .append('g')
71144             .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
71145             .classed('disabled', function(d) { return d.disabled(); })
71146             .attr('transform', function(d, i) {
71147                 return 'translate(' + geoRoundCoords([
71148                         r * Math.sin(a0 + i * a),
71149                         r * Math.cos(a0 + i * a)]).join(',') + ')';
71150             });
71151
71152         button
71153             .append('circle')
71154             .attr('r', 15)
71155             .on('click', click)
71156             .on('mousedown', mousedown)
71157             .on('mouseover', mouseover)
71158             .on('mouseout', mouseout);
71159
71160         button
71161             .append('use')
71162             .attr('transform', 'translate(-10,-10)')
71163             .attr('width', '20')
71164             .attr('height', '20')
71165             .attr('xlink:href', function(d) { return '#operation-' + d.id; });
71166
71167         tooltip = select(document.body)
71168             .append('div')
71169             .attr('class', 'tooltip-inner radial-menu-tooltip');
71170
71171         function mousedown() {
71172             event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
71173         }
71174
71175         function mouseover(d, i) {
71176             var rect = context.surfaceRect(),
71177                 angle = a0 + i * a,
71178                 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
71179                 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
71180                 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
71181                 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
71182
71183             tooltip
71184                 .style('top', null)
71185                 .style('left', null)
71186                 .style('bottom', null)
71187                 .style('right', null)
71188                 .style('display', 'block')
71189                 .html(uiTooltipHtml(d.tooltip(), d.keys[0]));
71190
71191             if (i === 0) {
71192                 tooltip
71193                     .style('right', right)
71194                     .style('top', top);
71195             } else if (i >= 4) {
71196                 tooltip
71197                     .style('left', left)
71198                     .style('bottom', bottom);
71199             } else {
71200                 tooltip
71201                     .style('left', left)
71202                     .style('top', top);
71203             }
71204         }
71205
71206         function mouseout() {
71207             tooltip.style('display', 'none');
71208         }
71209     };
71210
71211
71212     radialMenu.close = function() {
71213         if (menu) {
71214             menu
71215                 .style('pointer-events', 'none')
71216                 .transition()
71217                 .attr('opacity', 0)
71218                 .remove();
71219         }
71220
71221         if (tooltip) {
71222             tooltip.remove();
71223         }
71224     };
71225
71226
71227     radialMenu.center = function(_) {
71228         if (!arguments.length) return center;
71229         center = _;
71230         return radialMenu;
71231     };
71232
71233
71234     return radialMenu;
71235 }
71236
71237 function uiSelectionList(context, selectedIDs) {
71238
71239     function selectEntity(entity) {
71240         context.enter(modeSelect(context, [entity.id]));
71241     }
71242
71243
71244     function deselectEntity(entity) {
71245         event.stopPropagation();
71246         var index = selectedIDs.indexOf(entity.id);
71247         if (index > -1) {
71248             selectedIDs.splice(index, 1);
71249         }
71250         context.enter(modeSelect(context, selectedIDs));
71251     }
71252
71253
71254     function selectionList(selection$$1) {
71255         selection$$1.classed('selection-list-pane', true);
71256
71257         var header = selection$$1
71258             .append('div')
71259             .attr('class', 'header fillL cf');
71260
71261         header
71262             .append('h3')
71263             .text(t('inspector.multiselect'));
71264
71265         var listWrap = selection$$1
71266             .append('div')
71267             .attr('class', 'inspector-body');
71268
71269         var list = listWrap
71270             .append('div')
71271             .attr('class', 'feature-list cf');
71272
71273         context.history().on('change.selection-list', drawList);
71274         drawList();
71275
71276
71277         function drawList() {
71278             var entities = selectedIDs
71279                 .map(function(id) { return context.hasEntity(id); })
71280                 .filter(function(entity) { return entity; });
71281
71282             var items = list.selectAll('.feature-list-item')
71283                 .data(entities, osmEntity$$1.key);
71284
71285             items.exit()
71286                 .remove();
71287
71288             // Enter
71289             var enter = items.enter()
71290                 .append('div')
71291                 .attr('class', 'feature-list-item')
71292                 .on('click', selectEntity);
71293
71294             var label = enter
71295                 .append('button')
71296                 .attr('class', 'label');
71297
71298             enter
71299                 .append('button')
71300                 .attr('class', 'close')
71301                 .on('click', deselectEntity)
71302                 .call(svgIcon('#icon-close'));
71303
71304             label
71305                 .append('span')
71306                 .attr('class', 'entity-geom-icon')
71307                 .call(svgIcon('', 'pre-text'));
71308
71309             label
71310                 .append('span')
71311                 .attr('class', 'entity-type');
71312
71313             label
71314                 .append('span')
71315                 .attr('class', 'entity-name');
71316
71317             // Update
71318             items = items.merge(enter);
71319
71320             items.selectAll('.entity-geom-icon use')
71321                 .attr('href', function() {
71322                     var entity = this.parentNode.parentNode.__data__;
71323                     return '#icon-' + context.geometry(entity.id);
71324                 });
71325
71326             items.selectAll('.entity-type')
71327                 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
71328
71329             items.selectAll('.entity-name')
71330                 .text(function(entity) { return utilDisplayName(entity); });
71331         }
71332     }
71333
71334     return selectionList;
71335 }
71336
71337 function uiSourceSwitch(context) {
71338     var keys$$1;
71339
71340
71341     function click() {
71342         event.preventDefault();
71343
71344         if (context.history().hasChanges() &&
71345             !window.confirm(t('source_switch.lose_changes'))) return;
71346
71347         var live = select(this)
71348             .classed('live');
71349
71350         context.connection()
71351             .switch(live ? keys$$1[1] : keys$$1[0]);
71352
71353         context.enter(modeBrowse(context));
71354         context.flush();
71355
71356         select(this)
71357             .text(live ? t('source_switch.dev') : t('source_switch.live'))
71358             .classed('live', !live);
71359     }
71360
71361     var sourceSwitch = function(selection$$1) {
71362         selection$$1
71363             .append('a')
71364             .attr('href', '#')
71365             .text(t('source_switch.live'))
71366             .classed('live', true)
71367             .attr('tabindex', -1)
71368             .on('click', click);
71369     };
71370
71371
71372     sourceSwitch.keys = function(_) {
71373         if (!arguments.length) return keys$$1;
71374         keys$$1 = _;
71375         return sourceSwitch;
71376     };
71377
71378
71379     return sourceSwitch;
71380 }
71381
71382 function uiSuccess(context) {
71383     var dispatch$$1 = dispatch('cancel'),
71384         changeset;
71385
71386
71387     function success(selection$$1) {
71388         var header = selection$$1
71389             .append('div')
71390             .attr('class', 'header fillL');
71391
71392         header
71393             .append('button')
71394             .attr('class', 'fr')
71395             .on('click', function() { dispatch$$1.call('cancel'); })
71396             .call(svgIcon('#icon-close'));
71397
71398         header
71399             .append('h3')
71400             .text(t('success.just_edited'));
71401
71402         var body = selection$$1
71403             .append('div')
71404             .attr('class', 'body save-success fillL');
71405
71406         body
71407             .append('p')
71408             .html(t('success.help_html'));
71409
71410         body
71411             .append('a')
71412             .attr('class', 'details')
71413             .attr('target', '_blank')
71414             .attr('tabindex', -1)
71415             .call(svgIcon('#icon-out-link', 'inline'))
71416             .attr('href', t('success.help_link_url'))
71417             .append('span')
71418             .text(t('success.help_link_text'));
71419
71420         var changesetURL = context.connection().changesetURL(changeset.id);
71421
71422
71423         var viewOnOsm = body
71424             .append('a')
71425             .attr('class', 'button col12 osm')
71426             .attr('target', '_blank')
71427             .attr('href', changesetURL);
71428
71429         viewOnOsm
71430             .append('svg')
71431             .attr('class', 'logo logo-osm')
71432             .append('use')
71433             .attr('xlink:href', '#logo-osm');
71434
71435         viewOnOsm
71436             .append('div')
71437             .text(t('success.view_on_osm'));
71438
71439
71440         var message = (changeset.tags.comment || t('success.edited_osm')).substring(0, 130) +
71441             ' ' + context.connection().changesetURL(changeset.id);
71442
71443         var sharing = {
71444             facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
71445             twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
71446             google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
71447         };
71448
71449         body.selectAll('.button.social')
71450             .data(entries(sharing))
71451             .enter()
71452             .append('a')
71453             .attr('class', 'button social col4')
71454             .attr('target', '_blank')
71455             .attr('href', function(d) { return d.value; })
71456             .call(tooltip()
71457                 .title(function(d) { return t('success.' + d.key); })
71458                 .placement('bottom'))
71459             .each(function(d) { select(this).call(svgIcon('#logo-' + d.key, 'social')); });
71460     }
71461
71462
71463     success.changeset = function(_) {
71464         if (!arguments.length) return changeset;
71465         changeset = _;
71466         return success;
71467     };
71468
71469
71470     return utilRebind(success, dispatch$$1, 'on');
71471 }
71472
71473 function coreHistory(context) {
71474     var imageryUsed = ['Bing'],
71475         dispatch$$1 = dispatch('change', 'undone', 'redone'),
71476         lock = utilSessionMutex('lock'),
71477         duration = 150,
71478         checkpoints = {},
71479         stack$$1, index, tree$$1;
71480
71481
71482     // internal _act, accepts list of actions and eased time
71483     function _act(actions, t) {
71484         actions = Array.prototype.slice.call(actions);
71485
71486         var annotation;
71487
71488         if (!lodash.isFunction(lodash.last(actions))) {
71489             annotation = actions.pop();
71490         }
71491
71492         stack$$1[index].transform = context.projection.transform();
71493         stack$$1[index].selectedIDs = context.selectedIDs();
71494
71495         var graph = stack$$1[index].graph;
71496         for (var i = 0; i < actions.length; i++) {
71497             graph = actions[i](graph, t);
71498         }
71499
71500         return {
71501             graph: graph,
71502             annotation: annotation,
71503             imageryUsed: imageryUsed
71504         };
71505     }
71506
71507
71508     // internal _perform with eased time
71509     function _perform(args, t) {
71510         var previous = stack$$1[index].graph;
71511         stack$$1 = stack$$1.slice(0, index + 1);
71512         stack$$1.push(_act(args, t));
71513         index++;
71514         return change(previous);
71515     }
71516
71517
71518     // internal _replace with eased time
71519     function _replace(args, t) {
71520         var previous = stack$$1[index].graph;
71521         // assert(index == stack.length - 1)
71522         stack$$1[index] = _act(args, t);
71523         return change(previous);
71524     }
71525
71526
71527     // internal _overwrite with eased time
71528     function _overwrite(args, t) {
71529         var previous = stack$$1[index].graph;
71530         if (index > 0) {
71531             index--;
71532             stack$$1.pop();
71533         }
71534         stack$$1 = stack$$1.slice(0, index + 1);
71535         stack$$1.push(_act(args, t));
71536         index++;
71537         return change(previous);
71538     }
71539
71540
71541     // determine diffrence and dispatch a change event
71542     function change(previous) {
71543         var difference = coreDifference(previous, history.graph());
71544         dispatch$$1.call('change', this, difference);
71545         return difference;
71546     }
71547
71548
71549     // iD uses namespaced keys so multiple installations do not conflict
71550     function getKey(n) {
71551         return 'iD_' + window.location.origin + '_' + n;
71552     }
71553
71554
71555     var history = {
71556
71557         graph: function() {
71558             return stack$$1[index].graph;
71559         },
71560
71561
71562         base: function() {
71563             return stack$$1[0].graph;
71564         },
71565
71566
71567         merge: function(entities, extent$$1) {
71568             stack$$1[0].graph.rebase(entities, lodash.map(stack$$1, 'graph'), false);
71569             tree$$1.rebase(entities, false);
71570
71571             dispatch$$1.call('change', this, undefined, extent$$1);
71572         },
71573
71574
71575         perform: function() {
71576             // complete any transition already in progress
71577             select(document).interrupt('history.perform');
71578
71579             var transitionable = false,
71580                 action0 = arguments[0];
71581
71582             if (arguments.length === 1 ||
71583                 arguments.length === 2 && !lodash.isFunction(arguments[1])) {
71584                 transitionable = !!action0.transitionable;
71585             }
71586
71587             if (transitionable) {
71588                 var origArguments = arguments;
71589                 select(document)
71590                     .transition('history.perform')
71591                     .duration(duration)
71592                     .ease(linear$1)
71593                     .tween('history.tween', function() {
71594                         return function(t) {
71595                             if (t < 1) _overwrite([action0], t);
71596                         };
71597                     })
71598                     .on('start', function() {
71599                         _perform([action0], 0);
71600                     })
71601                     .on('end interrupt', function() {
71602                         _overwrite(origArguments, 1);
71603                     });
71604
71605             } else {
71606                 return _perform(arguments);
71607             }
71608         },
71609
71610
71611         replace: function() {
71612             select(document).interrupt('history.perform');
71613             return _replace(arguments, 1);
71614         },
71615
71616
71617         // Same as calling pop and then perform
71618         overwrite: function() {
71619             select(document).interrupt('history.perform');
71620             return _overwrite(arguments, 1);
71621         },
71622
71623
71624         pop: function(n) {
71625             select(document).interrupt('history.perform');
71626
71627             var previous = stack$$1[index].graph;
71628             if (isNaN(+n) || +n < 0) {
71629                 n = 1;
71630             }
71631             while (n-- > 0 && index > 0) {
71632                 index--;
71633                 stack$$1.pop();
71634             }
71635             return change(previous);
71636         },
71637
71638
71639         // Back to the previous annotated state or index = 0.
71640         undo: function() {
71641             select(document).interrupt('history.perform');
71642
71643             var previous = stack$$1[index].graph;
71644             while (index > 0) {
71645                 index--;
71646                 if (stack$$1[index].annotation) break;
71647             }
71648
71649             dispatch$$1.call('undone', this, stack$$1[index]);
71650             return change(previous);
71651         },
71652
71653
71654         // Forward to the next annotated state.
71655         redo: function() {
71656             select(document).interrupt('history.perform');
71657
71658             var previous = stack$$1[index].graph;
71659             var tryIndex = index;
71660             while (tryIndex < stack$$1.length - 1) {
71661                 tryIndex++;
71662                 if (stack$$1[tryIndex].annotation) {
71663                     index = tryIndex;
71664                     dispatch$$1.call('redone', this, stack$$1[index]);
71665                     break;
71666                 }
71667             }
71668
71669             return change(previous);
71670         },
71671
71672
71673         undoAnnotation: function() {
71674             var i = index;
71675             while (i >= 0) {
71676                 if (stack$$1[i].annotation) return stack$$1[i].annotation;
71677                 i--;
71678             }
71679         },
71680
71681
71682         redoAnnotation: function() {
71683             var i = index + 1;
71684             while (i <= stack$$1.length - 1) {
71685                 if (stack$$1[i].annotation) return stack$$1[i].annotation;
71686                 i++;
71687             }
71688         },
71689
71690
71691         intersects: function(extent$$1) {
71692             return tree$$1.intersects(extent$$1, stack$$1[index].graph);
71693         },
71694
71695
71696         difference: function() {
71697             var base = stack$$1[0].graph,
71698                 head = stack$$1[index].graph;
71699             return coreDifference(base, head);
71700         },
71701
71702
71703         changes: function(action) {
71704             var base = stack$$1[0].graph,
71705                 head = stack$$1[index].graph;
71706
71707             if (action) {
71708                 head = action(head);
71709             }
71710
71711             var difference = coreDifference(base, head);
71712
71713             return {
71714                 modified: difference.modified(),
71715                 created: difference.created(),
71716                 deleted: difference.deleted()
71717             };
71718         },
71719
71720
71721         validate: function(changes) {
71722             return lodash(Validations)
71723                 .map(function(fn) { return fn()(changes, stack$$1[index].graph); })
71724                 .flatten()
71725                 .value();
71726         },
71727
71728
71729         hasChanges: function() {
71730             return this.difference().length() > 0;
71731         },
71732
71733
71734         imageryUsed: function(sources) {
71735             if (sources) {
71736                 imageryUsed = sources;
71737                 return history;
71738             } else {
71739                 return lodash(stack$$1.slice(1, index + 1))
71740                     .map('imageryUsed')
71741                     .flatten()
71742                     .uniq()
71743                     .without(undefined, 'Custom')
71744                     .value();
71745             }
71746         },
71747
71748
71749         // save the current history state
71750         checkpoint: function(key) {
71751             checkpoints[key] = {
71752                 stack: lodash.cloneDeep(stack$$1),
71753                 index: index
71754             };
71755             return history;
71756         },
71757
71758
71759         // restore history state to a given checkpoint or reset completely
71760         reset: function(key) {
71761             if (key !== undefined && checkpoints.hasOwnProperty(key)) {
71762                 stack$$1 = lodash.cloneDeep(checkpoints[key].stack);
71763                 index = checkpoints[key].index;
71764             } else {
71765                 stack$$1 = [{graph: coreGraph$$1()}];
71766                 index = 0;
71767                 tree$$1 = coreTree(stack$$1[0].graph);
71768                 checkpoints = {};
71769             }
71770             dispatch$$1.call('change');
71771             return history;
71772         },
71773
71774
71775         toIntroGraph: function() {
71776             var nextId = { n: 0, r: 0, w: 0 },
71777                 permIds = {},
71778                 graph = this.graph(),
71779                 baseEntities = {};
71780
71781             // clone base entities..
71782             lodash.forEach(graph.base().entities, function(entity) {
71783                 var copy = lodash.cloneDeepWith(entity, customizer);
71784                 baseEntities[copy.id] = copy;
71785             });
71786
71787             // replace base entities with head entities..
71788             lodash.forEach(graph.entities, function(entity, id) {
71789                 if (entity) {
71790                     var copy = lodash.cloneDeepWith(entity, customizer);
71791                     baseEntities[copy.id] = copy;
71792                 } else {
71793                     delete baseEntities[id];
71794                 }
71795             });
71796
71797             // swap temporary for permanent ids..
71798             lodash.forEach(baseEntities, function(entity) {
71799                 if (Array.isArray(entity.nodes)) {
71800                     entity.nodes = entity.nodes.map(function(node) {
71801                         return permIds[node] || node;
71802                     });
71803                 }
71804                 if (Array.isArray(entity.members)) {
71805                     entity.members = entity.members.map(function(member) {
71806                         member.id = permIds[member.id] || member.id;
71807                         return member;
71808                     });
71809                 }
71810             });
71811
71812             return JSON.stringify({ dataIntroGraph: baseEntities });
71813
71814
71815             function customizer(src) {
71816                 var copy = lodash.omit(lodash.cloneDeep(src), ['type', 'user', 'v', 'version', 'visible']);
71817                 if (lodash.isEmpty(copy.tags)) {
71818                     delete copy.tags;
71819                 }
71820
71821                 if (Array.isArray(copy.loc)) {
71822                     copy.loc[0] = +copy.loc[0].toFixed(6);
71823                     copy.loc[1] = +copy.loc[1].toFixed(6);
71824                 }
71825
71826                 var match = src.id.match(/([nrw])-\d*/);  // temporary id
71827                 if (match !== null) {
71828                     var nrw = match[1], permId;
71829                     do { permId = nrw + (++nextId[nrw]); }
71830                     while (baseEntities.hasOwnProperty(permId));
71831
71832                     copy.id = permIds[src.id] = permId;
71833                 }
71834                 return copy;
71835             }
71836         },
71837
71838
71839         toJSON: function() {
71840             if (!this.hasChanges()) return;
71841
71842             var allEntities = {},
71843                 baseEntities = {},
71844                 base = stack$$1[0];
71845
71846             var s = stack$$1.map(function(i) {
71847                 var modified = [], deleted = [];
71848
71849                 lodash.forEach(i.graph.entities, function(entity, id) {
71850                     if (entity) {
71851                         var key = osmEntity$$1.key(entity);
71852                         allEntities[key] = entity;
71853                         modified.push(key);
71854                     } else {
71855                         deleted.push(id);
71856                     }
71857
71858                     // make sure that the originals of changed or deleted entities get merged
71859                     // into the base of the stack after restoring the data from JSON.
71860                     if (id in base.graph.entities) {
71861                         baseEntities[id] = base.graph.entities[id];
71862                     }
71863                     // get originals of parent entities too
71864                     lodash.forEach(base.graph._parentWays[id], function(parentId) {
71865                         if (parentId in base.graph.entities) {
71866                             baseEntities[parentId] = base.graph.entities[parentId];
71867                         }
71868                     });
71869                 });
71870
71871                 var x = {};
71872
71873                 if (modified.length) x.modified = modified;
71874                 if (deleted.length) x.deleted = deleted;
71875                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
71876                 if (i.annotation) x.annotation = i.annotation;
71877
71878                 return x;
71879             });
71880
71881             return JSON.stringify({
71882                 version: 3,
71883                 entities: lodash.values(allEntities),
71884                 baseEntities: lodash.values(baseEntities),
71885                 stack: s,
71886                 nextIDs: osmEntity$$1.id.next,
71887                 index: index
71888             });
71889         },
71890
71891
71892         fromJSON: function(json$$1, loadChildNodes) {
71893             var h = JSON.parse(json$$1),
71894                 loadComplete = true;
71895
71896             osmEntity$$1.id.next = h.nextIDs;
71897             index = h.index;
71898
71899             if (h.version === 2 || h.version === 3) {
71900                 var allEntities = {};
71901
71902                 h.entities.forEach(function(entity) {
71903                     allEntities[osmEntity$$1.key(entity)] = osmEntity$$1(entity);
71904                 });
71905
71906                 if (h.version === 3) {
71907                     // This merges originals for changed entities into the base of
71908                     // the stack even if the current stack doesn't have them (for
71909                     // example when iD has been restarted in a different region)
71910                     var baseEntities = h.baseEntities.map(function(d) { return osmEntity$$1(d); });
71911                     stack$$1[0].graph.rebase(baseEntities, lodash.map(stack$$1, 'graph'), true);
71912                     tree$$1.rebase(baseEntities, true);
71913
71914                     // When we restore a modified way, we also need to fetch any missing
71915                     // childnodes that would normally have been downloaded with it.. #2142
71916                     if (loadChildNodes) {
71917                         var missing =  lodash(baseEntities)
71918                                 .filter({ type: 'way' })
71919                                 .map('nodes')
71920                                 .flatten()
71921                                 .uniq()
71922                                 .reject(function(n) { return stack$$1[0].graph.hasEntity(n); })
71923                                 .value();
71924
71925                         if (!lodash.isEmpty(missing)) {
71926                             loadComplete = false;
71927                             context.redrawEnable(false);
71928
71929                             var loading = uiLoading(context).blocking(true);
71930                             context.container().call(loading);
71931
71932                             var childNodesLoaded = function(err, result) {
71933                                 if (!err) {
71934                                     var visible = lodash.groupBy(result.data, 'visible');
71935                                     if (!lodash.isEmpty(visible.true)) {
71936                                         missing = lodash.difference(missing, lodash.map(visible.true, 'id'));
71937                                         stack$$1[0].graph.rebase(visible.true, lodash.map(stack$$1, 'graph'), true);
71938                                         tree$$1.rebase(visible.true, true);
71939                                     }
71940
71941                                     // fetch older versions of nodes that were deleted..
71942                                     lodash.each(visible.false, function(entity) {
71943                                         context.connection()
71944                                             .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
71945                                     });
71946                                 }
71947
71948                                 if (err || lodash.isEmpty(missing)) {
71949                                     loading.close();
71950                                     context.redrawEnable(true);
71951                                     dispatch$$1.call('change');
71952                                 }
71953                             };
71954
71955                             context.connection().loadMultiple(missing, childNodesLoaded);
71956                         }
71957                     }
71958                 }
71959
71960                 stack$$1 = h.stack.map(function(d) {
71961                     var entities = {}, entity;
71962
71963                     if (d.modified) {
71964                         d.modified.forEach(function(key) {
71965                             entity = allEntities[key];
71966                             entities[entity.id] = entity;
71967                         });
71968                     }
71969
71970                     if (d.deleted) {
71971                         d.deleted.forEach(function(id) {
71972                             entities[id] = undefined;
71973                         });
71974                     }
71975
71976                     return {
71977                         graph: coreGraph$$1(stack$$1[0].graph).load(entities),
71978                         annotation: d.annotation,
71979                         imageryUsed: d.imageryUsed
71980                     };
71981                 });
71982
71983             } else { // original version
71984                 stack$$1 = h.stack.map(function(d) {
71985                     var entities = {};
71986
71987                     for (var i in d.entities) {
71988                         var entity = d.entities[i];
71989                         entities[i] = entity === 'undefined' ? undefined : osmEntity$$1(entity);
71990                     }
71991
71992                     d.graph = coreGraph$$1(stack$$1[0].graph).load(entities);
71993                     return d;
71994                 });
71995             }
71996
71997             if (loadComplete) {
71998                 dispatch$$1.call('change');
71999             }
72000
72001             return history;
72002         },
72003
72004
72005         save: function() {
72006             if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
72007             return history;
72008         },
72009
72010
72011         clearSaved: function() {
72012             context.debouncedSave.cancel();
72013             if (lock.locked()) context.storage(getKey('saved_history'), null);
72014             return history;
72015         },
72016
72017
72018         lock: function() {
72019             return lock.lock();
72020         },
72021
72022
72023         unlock: function() {
72024             lock.unlock();
72025         },
72026
72027
72028         // is iD not open in another window and it detects that
72029         // there's a history stored in localStorage that's recoverable?
72030         restorableChanges: function() {
72031             return lock.locked() && !!context.storage(getKey('saved_history'));
72032         },
72033
72034
72035         // load history from a version stored in localStorage
72036         restore: function() {
72037             if (!lock.locked()) return;
72038
72039             var json$$1 = context.storage(getKey('saved_history'));
72040             if (json$$1) history.fromJSON(json$$1, true);
72041         },
72042
72043
72044         _getKey: getKey
72045
72046     };
72047
72048
72049     history.reset();
72050
72051     return utilRebind(history, dispatch$$1, 'on');
72052 }
72053
72054 function presetCollection(collection) {
72055     var maxSearchResults = 50,
72056         maxSuggestionResults = 10;
72057
72058     var presets = {
72059
72060         collection: collection,
72061
72062
72063         item: function(id) {
72064             return lodash.find(this.collection, function(d) {
72065                 return d.id === id;
72066             });
72067         },
72068
72069
72070         matchGeometry: function(geometry) {
72071             return presetCollection(this.collection.filter(function(d) {
72072                 return d.matchGeometry(geometry);
72073             }));
72074         },
72075
72076
72077         search: function(value, geometry) {
72078             if (!value) return this;
72079
72080             function leading(a) {
72081                 var index = a.indexOf(value);
72082                 return index === 0 || a[index - 1] === ' ';
72083             }
72084
72085             function suggestionName(name) {
72086                 var nameArray = name.split(' - ');
72087                 if (nameArray.length > 1) {
72088                     name = nameArray.slice(0, nameArray.length - 1).join(' - ');
72089                 }
72090                 return name.toLowerCase();
72091             }
72092
72093
72094             value = value.toLowerCase();
72095
72096             var searchable = lodash.filter(this.collection, function(a) {
72097                     return a.searchable !== false && a.suggestion !== true;
72098                 }),
72099                 suggestions = lodash.filter(this.collection, function(a) {
72100                     return a.suggestion === true;
72101                 });
72102
72103
72104             // matches value to preset.name
72105             var leading_name = lodash.filter(searchable, function(a) {
72106                     return leading(a.name().toLowerCase());
72107                 }).sort(function(a, b) {
72108                     var i;
72109                     i = b.originalScore - a.originalScore;
72110                     if (i !== 0) return i;
72111
72112                     i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
72113                     if (i !== 0) return i;
72114
72115                     return a.name().length - b.name().length;
72116                 });
72117
72118             // matches value to preset.terms values
72119             var leading_terms = lodash.filter(searchable, function(a) {
72120                     return lodash.some(a.terms() || [], leading);
72121                 });
72122
72123             // matches value to preset.tags values
72124             var leading_tag_values = lodash.filter(searchable, function(a) {
72125                     return lodash.some(lodash.without(lodash.values(a.tags || {}), '*'), leading);
72126                 });
72127
72128
72129             // finds close matches to value in preset.name
72130             var similar_name = searchable.map(function(a) {
72131                     return {
72132                         preset: a,
72133                         dist: utilEditDistance(value, a.name())
72134                     };
72135                 }).filter(function(a) {
72136                     return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
72137                 }).sort(function(a, b) {
72138                     return a.dist - b.dist;
72139                 }).map(function(a) {
72140                     return a.preset;
72141                 });
72142
72143             // finds close matches to value in preset.terms
72144             var similar_terms = lodash.filter(searchable, function(a) {
72145                     return lodash.some(a.terms() || [], function(b) {
72146                         return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
72147                     });
72148                 });
72149
72150             var leading_suggestions = lodash.filter(suggestions, function(a) {
72151                     return leading(suggestionName(a.name()));
72152                 }).sort(function(a, b) {
72153                     a = suggestionName(a.name());
72154                     b = suggestionName(b.name());
72155                     var i = a.indexOf(value) - b.indexOf(value);
72156                     if (i === 0) return a.length - b.length;
72157                     else return i;
72158                 });
72159
72160             var similar_suggestions = suggestions.map(function(a) {
72161                     return {
72162                         preset: a,
72163                         dist: utilEditDistance(value, suggestionName(a.name()))
72164                     };
72165                 }).filter(function(a) {
72166                     return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
72167                 }).sort(function(a, b) {
72168                     return a.dist - b.dist;
72169                 }).map(function(a) {
72170                     return a.preset;
72171                 });
72172
72173             var other = presets.item(geometry);
72174
72175             var results = leading_name.concat(
72176                     leading_terms,
72177                     leading_tag_values,
72178                     leading_suggestions.slice(0, maxSuggestionResults + 5),
72179                     similar_name,
72180                     similar_terms,
72181                     similar_suggestions.slice(0, maxSuggestionResults)
72182                 ).slice(0, maxSearchResults - 1);
72183
72184             return presetCollection(lodash.uniq(results.concat(other)));
72185         }
72186     };
72187
72188
72189     return presets;
72190 }
72191
72192 function presetCategory(id, category, all) {
72193     category = lodash.clone(category);
72194
72195     category.id = id;
72196
72197
72198     category.members = presetCollection(category.members.map(function(id) {
72199         return all.item(id);
72200     }));
72201
72202
72203     category.matchGeometry = function(geometry) {
72204         return category.geometry.indexOf(geometry) >= 0;
72205     };
72206
72207
72208     category.matchScore = function() {
72209         return -1;
72210     };
72211
72212
72213     category.name = function() {
72214         return t('presets.categories.' + id + '.name', {'default': id});
72215     };
72216
72217
72218     category.terms = function() {
72219         return [];
72220     };
72221
72222
72223     return category;
72224 }
72225
72226 function presetField(id, field) {
72227     field = lodash.clone(field);
72228
72229     field.id = id;
72230
72231
72232     field.matchGeometry = function(geometry) {
72233         return !field.geometry || field.geometry === geometry;
72234     };
72235
72236
72237     field.t = function(scope, options) {
72238         return t('presets.fields.' + id + '.' + scope, options);
72239     };
72240
72241
72242     field.label = function() {
72243         return field.t('label', {'default': id});
72244     };
72245
72246
72247     var placeholder = field.placeholder;
72248     field.placeholder = function() {
72249         return field.t('placeholder', {'default': placeholder});
72250     };
72251
72252
72253     return field;
72254 }
72255
72256 function presetPreset(id, preset, fields) {
72257     preset = lodash.clone(preset);
72258
72259     preset.id = id;
72260     preset.fields = (preset.fields || []).map(getFields);
72261     preset.geometry = (preset.geometry || []);
72262
72263
72264     function getFields(f) {
72265         return fields[f];
72266     }
72267
72268
72269     preset.matchGeometry = function(geometry) {
72270         return preset.geometry.indexOf(geometry) >= 0;
72271     };
72272
72273
72274     preset.originalScore = preset.matchScore || 1;
72275
72276
72277     preset.matchScore = function(entity) {
72278         var tags = preset.tags,
72279             score = 0;
72280
72281         for (var t$$1 in tags) {
72282             if (entity.tags[t$$1] === tags[t$$1]) {
72283                 score += preset.originalScore;
72284             } else if (tags[t$$1] === '*' && t$$1 in entity.tags) {
72285                 score += preset.originalScore / 2;
72286             } else {
72287                 return -1;
72288             }
72289         }
72290
72291         return score;
72292     };
72293
72294
72295     preset.t = function(scope, options) {
72296         return t('presets.presets.' + id + '.' + scope, options);
72297     };
72298
72299
72300     var name = preset.name || '';
72301     preset.name = function() {
72302         if (preset.suggestion) {
72303             id = id.split('/');
72304             id = id[0] + '/' + id[1];
72305             return name + ' - ' + t('presets.presets.' + id + '.name');
72306         }
72307         return preset.t('name', {'default': name});
72308     };
72309
72310
72311     preset.terms = function() {
72312         return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
72313     };
72314
72315
72316     preset.isFallback = function() {
72317         var tagCount = Object.keys(preset.tags).length;
72318         return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
72319     };
72320
72321
72322     var reference = preset.reference || {};
72323     preset.reference = function(geometry) {
72324         var key = reference.key || Object.keys(preset.tags)[0],
72325             value = reference.value || preset.tags[key];
72326
72327         if (geometry === 'relation' && key === 'type') {
72328             if (value in preset.tags) {
72329                 key = value;
72330                 value = preset.tags[key];
72331             } else {
72332                 return { rtype: value };
72333             }
72334         }
72335
72336         if (value === '*') {
72337             return { key: key };
72338         } else {
72339             return { key: key, value: value };
72340         }
72341     };
72342
72343
72344     var removeTags = preset.removeTags || preset.tags;
72345     preset.removeTags = function(tags, geometry) {
72346         tags = lodash.omit(tags, lodash.keys(removeTags));
72347
72348         for (var f in preset.fields) {
72349             var field = preset.fields[f];
72350             if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
72351                 delete tags[field.key];
72352             }
72353         }
72354
72355         delete tags.area;
72356         return tags;
72357     };
72358
72359
72360     var applyTags = preset.addTags || preset.tags;
72361     preset.applyTags = function(tags, geometry) {
72362         var k;
72363
72364         tags = lodash.clone(tags);
72365
72366         for (k in applyTags) {
72367             if (applyTags[k] === '*') {
72368                 tags[k] = 'yes';
72369             } else {
72370                 tags[k] = applyTags[k];
72371             }
72372         }
72373
72374         // Add area=yes if necessary.
72375         // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
72376         // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
72377         // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
72378         if (geometry === 'area') {
72379             var needsAreaTag = true;
72380             if (preset.geometry.indexOf('line') === -1) {
72381                 for (k in applyTags) {
72382                     if (k in areaKeys) {
72383                         needsAreaTag = false;
72384                         break;
72385                     }
72386                 }
72387             }
72388             if (needsAreaTag) {
72389                 tags.area = 'yes';
72390             }
72391         }
72392
72393         for (var f in preset.fields) {
72394             var field = preset.fields[f];
72395             if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
72396                 tags[field.key] = field.default;
72397             }
72398         }
72399
72400         return tags;
72401     };
72402
72403
72404     return preset;
72405 }
72406
72407 function presetIndex() {
72408     // a presetCollection with methods for
72409     // loading new data and returning defaults
72410
72411     var all = presetCollection([]),
72412         defaults = { area: all, line: all, point: all, vertex: all, relation: all },
72413         fields = {},
72414         universal = [],
72415         recent = presetCollection([]);
72416
72417     // Index of presets by (geometry, tag key).
72418     var index = {
72419         point: {},
72420         vertex: {},
72421         line: {},
72422         area: {},
72423         relation: {}
72424     };
72425
72426     all.match = function(entity, resolver) {
72427         var geometry = entity.geometry(resolver);
72428
72429         // Treat entities on addr:interpolation lines as points, not vertices (#3241)
72430         if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
72431             geometry = 'point';
72432         }
72433
72434         var geometryMatches = index[geometry],
72435             best = -1,
72436             match;
72437
72438         for (var k in entity.tags) {
72439             var keyMatches = geometryMatches[k];
72440             if (!keyMatches) continue;
72441
72442             for (var i = 0; i < keyMatches.length; i++) {
72443                 var score = keyMatches[i].matchScore(entity);
72444                 if (score > best) {
72445                     best = score;
72446                     match = keyMatches[i];
72447                 }
72448             }
72449         }
72450
72451         return match || all.item(geometry);
72452     };
72453
72454
72455     // Because of the open nature of tagging, iD will never have a complete
72456     // list of tags used in OSM, so we want it to have logic like "assume
72457     // that a closed way with an amenity tag is an area, unless the amenity
72458     // is one of these specific types". This function computes a structure
72459     // that allows testing of such conditions, based on the presets designated
72460     // as as supporting (or not supporting) the area geometry.
72461     //
72462     // The returned object L is a whitelist/blacklist of tags. A closed way
72463     // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
72464     // (see `Way#isArea()`). In other words, the keys of L form the whitelist,
72465     // and the subkeys form the blacklist.
72466     all.areaKeys = function() {
72467         var areaKeys = {},
72468             ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],  // probably a line..
72469             presets = lodash.reject(all.collection, 'suggestion');
72470
72471         // whitelist
72472         presets.forEach(function(d) {
72473             for (var key in d.tags) break;
72474             if (!key) return;
72475             if (ignore.indexOf(key) !== -1) return;
72476
72477             if (d.geometry.indexOf('area') !== -1) {    // probably an area..
72478                 areaKeys[key] = areaKeys[key] || {};
72479             }
72480         });
72481
72482         // blacklist
72483         presets.forEach(function(d) {
72484             for (var key in d.tags) break;
72485             if (!key) return;
72486             if (ignore.indexOf(key) !== -1) return;
72487
72488             var value = d.tags[key];
72489             if (key in areaKeys &&                      // probably an area...
72490                 d.geometry.indexOf('line') !== -1 &&    // but sometimes a line
72491                 value !== '*') {
72492                 areaKeys[key][value] = true;
72493             }
72494         });
72495
72496         return areaKeys;
72497     };
72498
72499
72500     all.init = function() {
72501         var d = data.presets;
72502
72503         all.collection = [];
72504         recent.collection = [];
72505         fields = {};
72506         universal = [];
72507         index = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
72508
72509         if (d.fields) {
72510             lodash.forEach(d.fields, function(d, id) {
72511                 fields[id] = presetField(id, d);
72512                 if (d.universal) universal.push(fields[id]);
72513             });
72514         }
72515
72516         if (d.presets) {
72517             lodash.forEach(d.presets, function(d, id) {
72518                 all.collection.push(presetPreset(id, d, fields));
72519             });
72520         }
72521
72522         if (d.categories) {
72523             lodash.forEach(d.categories, function(d, id) {
72524                 all.collection.push(presetCategory(id, d, all));
72525             });
72526         }
72527
72528         if (d.defaults) {
72529             var getItem = lodash.bind(all.item, all);
72530             defaults = {
72531                 area: presetCollection(d.defaults.area.map(getItem)),
72532                 line: presetCollection(d.defaults.line.map(getItem)),
72533                 point: presetCollection(d.defaults.point.map(getItem)),
72534                 vertex: presetCollection(d.defaults.vertex.map(getItem)),
72535                 relation: presetCollection(d.defaults.relation.map(getItem))
72536             };
72537         }
72538
72539         for (var i = 0; i < all.collection.length; i++) {
72540             var preset = all.collection[i],
72541                 geometry = preset.geometry;
72542
72543             for (var j = 0; j < geometry.length; j++) {
72544                 var g = index[geometry[j]];
72545                 for (var k in preset.tags) {
72546                     (g[k] = g[k] || []).push(preset);
72547                 }
72548             }
72549         }
72550
72551         return all;
72552     };
72553
72554     all.field = function(id) {
72555         return fields[id];
72556     };
72557
72558     all.universal = function() {
72559         return universal;
72560     };
72561
72562     all.defaults = function(geometry, n) {
72563         var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
72564             def = lodash.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
72565         return presetCollection(lodash.uniq(rec.concat(def).concat(all.item(geometry))));
72566     };
72567
72568     all.choose = function(preset) {
72569         if (!preset.isFallback()) {
72570             recent = presetCollection(lodash.uniq([preset].concat(recent.collection)));
72571         }
72572         return all;
72573     };
72574
72575     return all;
72576 }
72577
72578 var areaKeys = {};
72579
72580 function setAreaKeys(value) {
72581     areaKeys = value;
72582 }
72583
72584
72585 function coreContext() {
72586
72587     // create a special translation that contains the keys in place of the strings
72588     var tkeys = lodash.cloneDeep(en);
72589     var parents = [];
72590
72591     function traverser(v, k, obj) {
72592         parents.push(k);
72593         if (lodash.isObject(v)) {
72594             lodash.forOwn(v, traverser);
72595         } else if (lodash.isString(v)) {
72596             obj[k] = parents.join('.');
72597         }
72598         parents.pop();
72599     }
72600
72601     lodash.forOwn(tkeys, traverser);
72602     addTranslation('_tkeys_', tkeys);
72603
72604     addTranslation('en', en);
72605     setLocale('en');
72606
72607     var dispatch$$1 = dispatch('enter', 'exit', 'change'),
72608         context = {};
72609
72610     // https://github.com/openstreetmap/iD/issues/772
72611     // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
72612     var storage;
72613     try { storage = localStorage; } catch (e) {}  // eslint-disable-line no-empty
72614     storage = storage || (function() {
72615         var s = {};
72616         return {
72617             getItem: function(k) { return s[k]; },
72618             setItem: function(k, v) { s[k] = v; },
72619             removeItem: function(k) { delete s[k]; }
72620         };
72621     })();
72622
72623     context.storage = function(k, v) {
72624         try {
72625             if (arguments.length === 1) return storage.getItem(k);
72626             else if (v === null) storage.removeItem(k);
72627             else storage.setItem(k, v);
72628         } catch (e) {
72629             // localstorage quota exceeded
72630             /* eslint-disable no-console */
72631             if (typeof console !== 'undefined') console.error('localStorage quota exceeded');
72632             /* eslint-enable no-console */
72633         }
72634     };
72635
72636
72637     /* Straight accessors. Avoid using these if you can. */
72638     var ui, connection, history;
72639     context.ui = function() { return ui; };
72640     context.connection = function() { return connection; };
72641     context.history = function() { return history; };
72642
72643
72644     /* Connection */
72645     function entitiesLoaded(err, result) {
72646         if (!err) history.merge(result.data, result.extent);
72647     }
72648
72649     context.preauth = function(options) {
72650         connection.switch(options);
72651         return context;
72652     };
72653
72654     context.loadTiles = function(projection, dimensions, callback) {
72655         function done(err, result) {
72656             entitiesLoaded(err, result);
72657             if (callback) callback(err, result);
72658         }
72659         connection.loadTiles(projection, dimensions, done);
72660     };
72661
72662     context.loadEntity = function(id, callback) {
72663         function done(err, result) {
72664             entitiesLoaded(err, result);
72665             if (callback) callback(err, result);
72666         }
72667         connection.loadEntity(id, done);
72668     };
72669
72670     context.zoomToEntity = function(id, zoomTo) {
72671         if (zoomTo !== false) {
72672             this.loadEntity(id, function(err, result) {
72673                 if (err) return;
72674                 var entity = lodash.find(result.data, function(e) { return e.id === id; });
72675                 if (entity) { map$$1.zoomTo(entity); }
72676             });
72677         }
72678
72679         map$$1.on('drawn.zoomToEntity', function() {
72680             if (!context.hasEntity(id)) return;
72681             map$$1.on('drawn.zoomToEntity', null);
72682             context.on('enter.zoomToEntity', null);
72683             context.enter(modeSelect(context, [id]));
72684         });
72685
72686         context.on('enter.zoomToEntity', function() {
72687             if (mode.id !== 'browse') {
72688                 map$$1.on('drawn.zoomToEntity', null);
72689                 context.on('enter.zoomToEntity', null);
72690             }
72691         });
72692     };
72693
72694     var minEditableZoom = 16;
72695     context.minEditableZoom = function(_) {
72696         if (!arguments.length) return minEditableZoom;
72697         minEditableZoom = _;
72698         connection.tileZoom(_);
72699         return context;
72700     };
72701
72702
72703     /* History */
72704     var inIntro = false;
72705     context.inIntro = function(_) {
72706         if (!arguments.length) return inIntro;
72707         inIntro = _;
72708         return context;
72709     };
72710
72711     context.save = function() {
72712         // no history save, no message onbeforeunload
72713         if (inIntro || select('.modal').size()) return;
72714
72715         var canSave;
72716         if (mode && mode.id === 'save') {
72717             canSave = false;
72718         } else {
72719             canSave = context.selectedIDs().every(function(id) {
72720                 var entity = context.hasEntity(id);
72721                 return entity && !entity.isDegenerate();
72722             });
72723         }
72724
72725         if (canSave) {
72726             history.save();
72727         }
72728         if (history.hasChanges()) {
72729             return t('save.unsaved_changes');
72730         }
72731     };
72732
72733
72734     /* Graph */
72735     context.hasEntity = function(id) {
72736         return history.graph().hasEntity(id);
72737     };
72738     context.entity = function(id) {
72739         return history.graph().entity(id);
72740     };
72741     context.childNodes = function(way) {
72742         return history.graph().childNodes(way);
72743     };
72744     context.geometry = function(id) {
72745         return context.entity(id).geometry(history.graph());
72746     };
72747
72748
72749     /* Modes */
72750     var mode;
72751     context.mode = function() {
72752         return mode;
72753     };
72754     context.enter = function(newMode) {
72755         if (mode) {
72756             mode.exit();
72757             dispatch$$1.call('exit', this, mode);
72758         }
72759
72760         mode = newMode;
72761         mode.enter();
72762         dispatch$$1.call('enter', this, mode);
72763     };
72764
72765     context.selectedIDs = function() {
72766         if (mode && mode.selectedIDs) {
72767             return mode.selectedIDs();
72768         } else {
72769             return [];
72770         }
72771     };
72772
72773
72774     /* Behaviors */
72775     context.install = function(behavior) {
72776         context.surface().call(behavior);
72777     };
72778     context.uninstall = function(behavior) {
72779         context.surface().call(behavior.off);
72780     };
72781
72782
72783     /* Copy/Paste */
72784     var copyIDs = [], copyGraph;
72785     context.copyGraph = function() { return copyGraph; };
72786     context.copyIDs = function(_) {
72787         if (!arguments.length) return copyIDs;
72788         copyIDs = _;
72789         copyGraph = history.graph();
72790         return context;
72791     };
72792
72793
72794     /* Background */
72795     var background;
72796     context.background = function() { return background; };
72797
72798
72799     /* Features */
72800     var features;
72801     context.features = function() { return features; };
72802     context.hasHiddenConnections = function(id) {
72803         var graph = history.graph(),
72804             entity = graph.entity(id);
72805         return features.hasHiddenConnections(entity, graph);
72806     };
72807
72808
72809     /* Presets */
72810     var presets;
72811     context.presets = function() { return presets; };
72812
72813
72814     /* Map */
72815     var map$$1;
72816     context.map = function() { return map$$1; };
72817     context.layers = function() { return map$$1.layers; };
72818     context.surface = function() { return map$$1.surface; };
72819     context.editable = function() { return map$$1.editable(); };
72820     context.surfaceRect = function() {
72821         return map$$1.surface.node().getBoundingClientRect();
72822     };
72823
72824
72825     /* Debug */
72826     var debugFlags = {
72827         tile: false,
72828         collision: false,
72829         imagery: false,
72830         imperial: false,
72831         driveLeft: false
72832     };
72833     context.debugFlags = function() {
72834         return debugFlags;
72835     };
72836     context.setDebug = function(flag, val) {
72837         if (arguments.length === 1) val = true;
72838         debugFlags[flag] = val;
72839         dispatch$$1.call('change');
72840         return context;
72841     };
72842     context.getDebug = function(flag) {
72843         return flag && debugFlags[flag];
72844     };
72845
72846
72847     /* Container */
72848     var container = select(document.body);
72849     context.container = function(_) {
72850         if (!arguments.length) return container;
72851         container = _;
72852         container.classed('id-container', true);
72853         return context;
72854     };
72855     var embed;
72856     context.embed = function(_) {
72857         if (!arguments.length) return embed;
72858         embed = _;
72859         return context;
72860     };
72861
72862
72863     /* Assets */
72864     var assetPath = '';
72865     context.assetPath = function(_) {
72866         if (!arguments.length) return assetPath;
72867         assetPath = _;
72868         return context;
72869     };
72870
72871     var assetMap = {};
72872     context.assetMap = function(_) {
72873         if (!arguments.length) return assetMap;
72874         assetMap = _;
72875         return context;
72876     };
72877
72878     context.asset = function(_) {
72879         var filename = assetPath + _;
72880         return assetMap[filename] || filename;
72881     };
72882
72883     context.imagePath = function(_) {
72884         return context.asset('img/' + _);
72885     };
72886
72887
72888     /* locales */
72889     // `locale` variable contains a "requested locale".
72890     // It won't become the `currentLocale` until after loadLocale() is called.
72891     var locale, localePath;
72892
72893     context.locale = function(loc, path$$1) {
72894         if (!arguments.length) return currentLocale;
72895         locale = loc;
72896         localePath = path$$1;
72897         return context;
72898     };
72899
72900     context.loadLocale = function(callback) {
72901         if (locale && locale !== 'en' && dataLocales.hasOwnProperty(locale)) {
72902             localePath = localePath || context.asset('locales/' + locale + '.json');
72903             json(localePath, function(err, result) {
72904                 if (!err) {
72905                     addTranslation(locale, result[locale]);
72906                     setLocale(locale);
72907                     utilDetect(true);
72908                 }
72909                 if (callback) {
72910                     callback(err);
72911                 }
72912             });
72913         } else {
72914             if (locale) {
72915                 setLocale(locale);
72916                 utilDetect(true);
72917             }
72918             if (callback) {
72919                 callback();
72920             }
72921         }
72922     };
72923
72924
72925     /* reset (aka flush) */
72926     context.reset = context.flush = function() {
72927         context.debouncedSave.cancel();
72928         lodash.each(services, function(service) {
72929             if (service && typeof service.reset === 'function') {
72930                 service.reset(context);
72931             }
72932         });
72933         features.reset();
72934         history.reset();
72935         return context;
72936     };
72937
72938
72939     /* Init */
72940     context.version = '2.2.1';
72941
72942     context.projection = geoRawMercator();
72943     context.curtainProjection = geoRawMercator();
72944
72945     locale = utilDetect().locale;
72946     if (locale && !dataLocales.hasOwnProperty(locale)) {
72947         locale = locale.split('-')[0];
72948     }
72949
72950     history = coreHistory(context);
72951     context.graph = history.graph;
72952     context.changes = history.changes;
72953     context.intersects = history.intersects;
72954
72955     // Debounce save, since it's a synchronous localStorage write,
72956     // and history changes can happen frequently (e.g. when dragging).
72957     context.debouncedSave = lodash.debounce(context.save, 350);
72958     function withDebouncedSave(fn) {
72959         return function() {
72960             var result = fn.apply(history, arguments);
72961             context.debouncedSave();
72962             return result;
72963         };
72964     }
72965
72966     context.perform = withDebouncedSave(history.perform);
72967     context.replace = withDebouncedSave(history.replace);
72968     context.pop = withDebouncedSave(history.pop);
72969     context.overwrite = withDebouncedSave(history.overwrite);
72970     context.undo = withDebouncedSave(history.undo);
72971     context.redo = withDebouncedSave(history.redo);
72972
72973     ui = uiInit(context);
72974
72975     connection = services.osm;
72976     background = rendererBackground(context);
72977     features = rendererFeatures(context);
72978     presets = presetIndex();
72979
72980     map$$1 = rendererMap(context);
72981     context.mouse = map$$1.mouse;
72982     context.extent = map$$1.extent;
72983     context.pan = map$$1.pan;
72984     context.zoomIn = map$$1.zoomIn;
72985     context.zoomOut = map$$1.zoomOut;
72986     context.zoomInFurther = map$$1.zoomInFurther;
72987     context.zoomOutFurther = map$$1.zoomOutFurther;
72988     context.redrawEnable = map$$1.redrawEnable;
72989
72990     lodash.each(services, function(service) {
72991         if (service && typeof service.init === 'function') {
72992             service.init(context);
72993         }
72994     });
72995
72996     background.init();
72997     presets.init();
72998     areaKeys = presets.areaKeys();
72999
73000
73001     return utilRebind(context, dispatch$$1, 'on');
73002 }
73003
73004 function osmWay() {
73005     if (!(this instanceof osmWay)) {
73006         return (new osmWay()).initialize(arguments);
73007     } else if (arguments.length) {
73008         this.initialize(arguments);
73009     }
73010 }
73011
73012
73013 osmEntity$$1.way = osmWay;
73014
73015 osmWay.prototype = Object.create(osmEntity$$1.prototype);
73016
73017
73018 lodash.extend(osmWay.prototype, {
73019     type: 'way',
73020     nodes: [],
73021
73022
73023     copy: function(resolver, copies) {
73024         if (copies[this.id])
73025             return copies[this.id];
73026
73027         var copy = osmEntity$$1.prototype.copy.call(this, resolver, copies);
73028
73029         var nodes = this.nodes.map(function(id) {
73030             return resolver.entity(id).copy(resolver, copies).id;
73031         });
73032
73033         copy = copy.update({ nodes: nodes });
73034         copies[this.id] = copy;
73035
73036         return copy;
73037     },
73038
73039
73040     extent: function(resolver) {
73041         return resolver.transient(this, 'extent', function() {
73042             var extent$$1 = geoExtent$$1();
73043             for (var i = 0; i < this.nodes.length; i++) {
73044                 var node = resolver.hasEntity(this.nodes[i]);
73045                 if (node) {
73046                     extent$$1._extend(node.extent());
73047                 }
73048             }
73049             return extent$$1;
73050         });
73051     },
73052
73053
73054     first: function() {
73055         return this.nodes[0];
73056     },
73057
73058
73059     last: function() {
73060         return this.nodes[this.nodes.length - 1];
73061     },
73062
73063
73064     contains: function(node) {
73065         return this.nodes.indexOf(node) >= 0;
73066     },
73067
73068
73069     affix: function(node) {
73070         if (this.nodes[0] === node) return 'prefix';
73071         if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
73072     },
73073
73074
73075     layer: function() {
73076         // explicit layer tag, clamp between -10, 10..
73077         if (isFinite(this.tags.layer)) {
73078             return Math.max(-10, Math.min(+(this.tags.layer), 10));
73079         }
73080
73081         // implied layer tag..
73082         if (this.tags.location === 'overground') return 1;
73083         if (this.tags.location === 'underground') return -1;
73084         if (this.tags.location === 'underwater') return -10;
73085
73086         if (this.tags.power === 'line') return 10;
73087         if (this.tags.power === 'minor_line') return 10;
73088         if (this.tags.aerialway) return 10;
73089         if (this.tags.bridge) return 1;
73090         if (this.tags.cutting) return -1;
73091         if (this.tags.tunnel) return -1;
73092         if (this.tags.waterway) return -1;
73093         if (this.tags.man_made === 'pipeline') return -10;
73094         if (this.tags.boundary) return -10;
73095         return 0;
73096     },
73097
73098
73099     isOneWay: function() {
73100         // explicit oneway tag..
73101         if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
73102         if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
73103
73104         // implied oneway tag..
73105         for (var key in this.tags) {
73106             if (key in osmOneWayTags && (this.tags[key] in osmOneWayTags[key]))
73107                 return true;
73108         }
73109         return false;
73110     },
73111
73112
73113     lanes: function() {
73114         return osmLanes(this);
73115     },
73116
73117
73118     isClosed: function() {
73119         return this.nodes.length > 1 && this.first() === this.last();
73120     },
73121
73122
73123     isConvex: function(resolver) {
73124         if (!this.isClosed() || this.isDegenerate()) return null;
73125
73126         var nodes = lodash.uniq(resolver.childNodes(this)),
73127             coords = lodash.map(nodes, 'loc'),
73128             curr = 0, prev = 0;
73129
73130         for (var i = 0; i < coords.length; i++) {
73131             var o = coords[(i+1) % coords.length],
73132                 a = coords[i],
73133                 b = coords[(i+2) % coords.length],
73134                 res = geoCross(o, a, b);
73135
73136             curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
73137             if (curr === 0) {
73138                 continue;
73139             } else if (prev && curr !== prev) {
73140                 return false;
73141             }
73142             prev = curr;
73143         }
73144         return true;
73145     },
73146
73147
73148     isArea: function() {
73149         if (this.tags.area === 'yes')
73150             return true;
73151         if (!this.isClosed() || this.tags.area === 'no')
73152             return false;
73153         for (var key in this.tags) {
73154             if (key in areaKeys && !(this.tags[key] in areaKeys[key])) {
73155                 return true;
73156             }
73157         }
73158         return false;
73159     },
73160
73161
73162     isDegenerate: function() {
73163         return lodash.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
73164     },
73165
73166
73167     areAdjacent: function(n1, n2) {
73168         for (var i = 0; i < this.nodes.length; i++) {
73169             if (this.nodes[i] === n1) {
73170                 if (this.nodes[i - 1] === n2) return true;
73171                 if (this.nodes[i + 1] === n2) return true;
73172             }
73173         }
73174         return false;
73175     },
73176
73177
73178     geometry: function(graph) {
73179         return graph.transient(this, 'geometry', function() {
73180             return this.isArea() ? 'area' : 'line';
73181         });
73182     },
73183
73184
73185     // If this way is not closed, append the beginning node to the end of the nodelist to close it.
73186     close: function() {
73187         if (this.isClosed() || !this.nodes.length) return this;
73188
73189         var nodes = this.nodes.slice();
73190         nodes = nodes.filter(noRepeatNodes);
73191         nodes.push(nodes[0]);
73192         return this.update({ nodes: nodes });
73193     },
73194
73195
73196     // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
73197     unclose: function() {
73198         if (!this.isClosed()) return this;
73199
73200         var nodes = this.nodes.slice(),
73201             connector = this.first(),
73202             i = nodes.length - 1;
73203
73204         // remove trailing connectors..
73205         while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
73206             nodes.splice(i, 1);
73207             i = nodes.length - 1;
73208         }
73209
73210         nodes = nodes.filter(noRepeatNodes);
73211         return this.update({ nodes: nodes });
73212     },
73213
73214
73215     // Adds a node (id) in front of the node which is currently at position index.
73216     // If index is undefined, the node will be added to the end of the way for linear ways,
73217     //   or just before the final connecting node for circular ways.
73218     // Consecutive duplicates are eliminated including existing ones.
73219     // Circularity is always preserved when adding a node.
73220     addNode: function(id, index) {
73221         var nodes = this.nodes.slice(),
73222             isClosed = this.isClosed(),
73223             max$$1 = isClosed ? nodes.length - 1 : nodes.length;
73224
73225         if (index === undefined) {
73226             index = max$$1;
73227         }
73228
73229         if (index < 0 || index > max$$1) {
73230             throw new RangeError('index ' + index + ' out of range 0..' + max$$1);
73231         }
73232
73233         // If this is a closed way, remove all connector nodes except the first one
73234         // (there may be duplicates) and adjust index if necessary..
73235         if (isClosed) {
73236             var connector = this.first();
73237
73238             // leading connectors..
73239             var i = 1;
73240             while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
73241                 nodes.splice(i, 1);
73242                 if (index > i) index--;
73243             }
73244
73245             // trailing connectors..
73246             i = nodes.length - 1;
73247             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
73248                 nodes.splice(i, 1);
73249                 if (index > i) index--;
73250                 i = nodes.length - 1;
73251             }
73252         }
73253
73254         nodes.splice(index, 0, id);
73255         nodes = nodes.filter(noRepeatNodes);
73256
73257         // If the way was closed before, append a connector node to keep it closed..
73258         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
73259             nodes.push(nodes[0]);
73260         }
73261
73262         return this.update({ nodes: nodes });
73263     },
73264
73265
73266     // Replaces the node which is currently at position index with the given node (id).
73267     // Consecutive duplicates are eliminated including existing ones.
73268     // Circularity is preserved when updating a node.
73269     updateNode: function(id, index) {
73270         var nodes = this.nodes.slice(),
73271             isClosed = this.isClosed(),
73272             max$$1 = nodes.length - 1;
73273
73274         if (index === undefined || index < 0 || index > max$$1) {
73275             throw new RangeError('index ' + index + ' out of range 0..' + max$$1);
73276         }
73277
73278         // If this is a closed way, remove all connector nodes except the first one
73279         // (there may be duplicates) and adjust index if necessary..
73280         if (isClosed) {
73281             var connector = this.first();
73282
73283             // leading connectors..
73284             var i = 1;
73285             while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
73286                 nodes.splice(i, 1);
73287                 if (index > i) index--;
73288             }
73289
73290             // trailing connectors..
73291             i = nodes.length - 1;
73292             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
73293                 nodes.splice(i, 1);
73294                 if (index === i) index = 0;  // update leading connector instead
73295                 i = nodes.length - 1;
73296             }
73297         }
73298
73299         nodes.splice(index, 1, id);
73300         nodes = nodes.filter(noRepeatNodes);
73301
73302         // If the way was closed before, append a connector node to keep it closed..
73303         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
73304             nodes.push(nodes[0]);
73305         }
73306
73307         return this.update({nodes: nodes});
73308     },
73309
73310
73311     // Replaces each occurrence of node id needle with replacement.
73312     // Consecutive duplicates are eliminated including existing ones.
73313     // Circularity is preserved.
73314     replaceNode: function(needle, replacement) {
73315         var nodes = this.nodes.slice(),
73316             isClosed = this.isClosed();
73317
73318         for (var i = 0; i < nodes.length; i++) {
73319             if (nodes[i] === needle) {
73320                 nodes[i] = replacement;
73321             }
73322         }
73323
73324         nodes = nodes.filter(noRepeatNodes);
73325
73326         // If the way was closed before, append a connector node to keep it closed..
73327         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
73328             nodes.push(nodes[0]);
73329         }
73330
73331         return this.update({nodes: nodes});
73332     },
73333
73334
73335     // Removes each occurrence of node id needle with replacement.
73336     // Consecutive duplicates are eliminated including existing ones.
73337     // Circularity is preserved.
73338     removeNode: function(id) {
73339         var nodes = this.nodes.slice(),
73340             isClosed = this.isClosed();
73341
73342         nodes = nodes
73343             .filter(function(node) { return node !== id; })
73344             .filter(noRepeatNodes);
73345
73346         // If the way was closed before, append a connector node to keep it closed..
73347         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
73348             nodes.push(nodes[0]);
73349         }
73350
73351         return this.update({nodes: nodes});
73352     },
73353
73354
73355     asJXON: function(changeset_id) {
73356         var r = {
73357             way: {
73358                 '@id': this.osmId(),
73359                 '@version': this.version || 0,
73360                 nd: lodash.map(this.nodes, function(id) {
73361                     return { keyAttributes: { ref: osmEntity$$1.id.toOSM(id) } };
73362                 }),
73363                 tag: lodash.map(this.tags, function(v, k) {
73364                     return { keyAttributes: { k: k, v: v } };
73365                 })
73366             }
73367         };
73368         if (changeset_id) {
73369             r.way['@changeset'] = changeset_id;
73370         }
73371         return r;
73372     },
73373
73374
73375     asGeoJSON: function(resolver) {
73376         return resolver.transient(this, 'GeoJSON', function() {
73377             var coordinates = lodash.map(resolver.childNodes(this), 'loc');
73378             if (this.isArea() && this.isClosed()) {
73379                 return {
73380                     type: 'Polygon',
73381                     coordinates: [coordinates]
73382                 };
73383             } else {
73384                 return {
73385                     type: 'LineString',
73386                     coordinates: coordinates
73387                 };
73388             }
73389         });
73390     },
73391
73392
73393     area: function(resolver) {
73394         return resolver.transient(this, 'area', function() {
73395             var nodes = resolver.childNodes(this);
73396
73397             var json$$1 = {
73398                 type: 'Polygon',
73399                 coordinates: [lodash.map(nodes, 'loc')]
73400             };
73401
73402             if (!this.isClosed() && nodes.length) {
73403                 json$$1.coordinates[0].push(nodes[0].loc);
73404             }
73405
73406             var area$$1 = area(json$$1);
73407
73408             // Heuristic for detecting counterclockwise winding order. Assumes
73409             // that OpenStreetMap polygons are not hemisphere-spanning.
73410             if (area$$1 > 2 * Math.PI) {
73411                 json$$1.coordinates[0] = json$$1.coordinates[0].reverse();
73412                 area$$1 = area(json$$1);
73413             }
73414
73415             return isNaN(area$$1) ? 0 : area$$1;
73416         });
73417     }
73418 });
73419
73420
73421 // Filter function to eliminate consecutive duplicates.
73422 function noRepeatNodes(node, i, arr) {
73423     return i === 0 || node !== arr[i - 1];
73424 }
73425
73426 function osmTurn(turn) {
73427     if (!(this instanceof osmTurn))
73428         return new osmTurn(turn);
73429     lodash.extend(this, turn);
73430 }
73431
73432
73433 function osmIntersection(graph, vertexId) {
73434     var vertex = graph.entity(vertexId),
73435         parentWays = graph.parentWays(vertex),
73436         coincident = [],
73437         highways = {};
73438
73439     function addHighway(way, adjacentNodeId) {
73440         if (highways[adjacentNodeId]) {
73441             coincident.push(adjacentNodeId);
73442         } else {
73443             highways[adjacentNodeId] = way;
73444         }
73445     }
73446
73447     // Pre-split ways that would need to be split in
73448     // order to add a restriction. The real split will
73449     // happen when the restriction is added.
73450     parentWays.forEach(function(way) {
73451         if (!way.tags.highway || way.isArea() || way.isDegenerate())
73452             return;
73453
73454         var isFirst = (vertexId === way.first()),
73455             isLast = (vertexId === way.last()),
73456             isAffix = (isFirst || isLast),
73457             isClosingNode = (isFirst && isLast);
73458
73459         if (isAffix && !isClosingNode) {
73460             var index = (isFirst ? 1 : way.nodes.length - 2);
73461             addHighway(way, way.nodes[index]);
73462
73463         } else {
73464             var splitIndex, wayA, wayB, indexA, indexB;
73465             if (isClosingNode) {
73466                 splitIndex = Math.ceil(way.nodes.length / 2);  // split at midpoint
73467                 wayA = osmWay({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex)});
73468                 wayB = osmWay({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
73469                 indexA = 1;
73470                 indexB = way.nodes.length - 2;
73471             } else {
73472                 splitIndex = lodash.indexOf(way.nodes, vertex.id, 1);  // split at vertexid
73473                 wayA = osmWay({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex + 1)});
73474                 wayB = osmWay({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
73475                 indexA = splitIndex - 1;
73476                 indexB = splitIndex + 1;
73477             }
73478             graph = graph.replace(wayA).replace(wayB);
73479             addHighway(wayA, way.nodes[indexA]);
73480             addHighway(wayB, way.nodes[indexB]);
73481         }
73482     });
73483
73484     // remove any ways from this intersection that are coincident
73485     // (i.e. any adjacent node used by more than one intersecting way)
73486     coincident.forEach(function (n) {
73487         delete highways[n];
73488     });
73489
73490
73491     var intersection = {
73492         highways: highways,
73493         ways: lodash.values(highways),
73494         graph: graph
73495     };
73496
73497
73498     intersection.adjacentNodeId = function(fromWayId) {
73499         return lodash.find(lodash.keys(highways), function(k) {
73500             return highways[k].id === fromWayId;
73501         });
73502     };
73503
73504
73505     intersection.turns = function(fromNodeId) {
73506         var start = highways[fromNodeId];
73507         if (!start)
73508             return [];
73509
73510         if (start.first() === vertex.id && start.tags.oneway === 'yes')
73511             return [];
73512         if (start.last() === vertex.id && start.tags.oneway === '-1')
73513             return [];
73514
73515         function withRestriction(turn) {
73516             graph.parentRelations(graph.entity(turn.from.way)).forEach(function(relation) {
73517                 if (relation.tags.type !== 'restriction')
73518                     return;
73519
73520                 var f = relation.memberByRole('from'),
73521                     t = relation.memberByRole('to'),
73522                     v = relation.memberByRole('via');
73523
73524                 if (f && f.id === turn.from.way &&
73525                     v && v.id === turn.via.node &&
73526                     t && t.id === turn.to.way) {
73527                     turn.restriction = relation.id;
73528                 } else if (/^only_/.test(relation.tags.restriction) &&
73529                     f && f.id === turn.from.way &&
73530                     v && v.id === turn.via.node &&
73531                     t && t.id !== turn.to.way) {
73532                     turn.restriction = relation.id;
73533                     turn.indirect_restriction = true;
73534                 }
73535             });
73536
73537             return osmTurn(turn);
73538         }
73539
73540
73541         var from = {
73542                 node: fromNodeId,
73543                 way: start.id.split(/-(a|b)/)[0]
73544             },
73545             via = { node: vertex.id },
73546             turns = [];
73547
73548         lodash.each(highways, function(end, adjacentNodeId) {
73549             if (end === start)
73550                 return;
73551
73552             // backward
73553             if (end.first() !== vertex.id && end.tags.oneway !== 'yes') {
73554                 turns.push(withRestriction({
73555                     from: from,
73556                     via: via,
73557                     to: {
73558                         node: adjacentNodeId,
73559                         way: end.id.split(/-(a|b)/)[0]
73560                     }
73561                 }));
73562             }
73563
73564             // forward
73565             if (end.last() !== vertex.id && end.tags.oneway !== '-1') {
73566                 turns.push(withRestriction({
73567                     from: from,
73568                     via: via,
73569                     to: {
73570                         node: adjacentNodeId,
73571                         way: end.id.split(/-(a|b)/)[0]
73572                     }
73573                 }));
73574             }
73575
73576         });
73577
73578         // U-turn
73579         if (start.tags.oneway !== 'yes' && start.tags.oneway !== '-1') {
73580             turns.push(withRestriction({
73581                 from: from,
73582                 via: via,
73583                 to: from,
73584                 u: true
73585             }));
73586         }
73587
73588         return turns;
73589     };
73590
73591     return intersection;
73592 }
73593
73594
73595 function osmInferRestriction(graph, from, via, to, projection) {
73596     var fromWay = graph.entity(from.way),
73597         fromNode = graph.entity(from.node),
73598         toWay = graph.entity(to.way),
73599         toNode = graph.entity(to.node),
73600         viaNode = graph.entity(via.node),
73601         fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
73602             (fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
73603         toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
73604             (toWay.tags.oneway === '-1' && toWay.last() === via.node),
73605         angle = geoAngle(viaNode, fromNode, projection) -
73606                 geoAngle(viaNode, toNode, projection);
73607
73608     angle = angle * 180 / Math.PI;
73609
73610     while (angle < 0)
73611         angle += 360;
73612
73613     if (fromNode === toNode)
73614         return 'no_u_turn';
73615     if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
73616         return 'no_u_turn';
73617     if (angle < 158)
73618         return 'no_right_turn';
73619     if (angle > 202)
73620         return 'no_left_turn';
73621
73622     return 'no_straight_on';
73623 }
73624
73625 function actionAddMember(relationId, member, memberIndex) {
73626     return function(graph) {
73627         var relation = graph.entity(relationId);
73628
73629         if (isNaN(memberIndex) && member.type === 'way') {
73630             var members = relation.indexedMembers();
73631             members.push(member);
73632
73633             var joined = osmJoinWays(members, graph);
73634             for (var i = 0; i < joined.length; i++) {
73635                 var segment = joined[i];
73636                 for (var j = 0; j < segment.length && segment.length >= 2; j++) {
73637                     if (segment[j] !== member)
73638                         continue;
73639
73640                     if (j === 0) {
73641                         memberIndex = segment[j + 1].index;
73642                     } else if (j === segment.length - 1) {
73643                         memberIndex = segment[j - 1].index + 1;
73644                     } else {
73645                         memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
73646                     }
73647                 }
73648             }
73649         }
73650
73651         return graph.replace(relation.addMember(member, memberIndex));
73652     };
73653 }
73654
73655 function actionAddMidpoint(midpoint, node) {
73656     return function(graph) {
73657         graph = graph.replace(node.move(midpoint.loc));
73658
73659         var parents = lodash.intersection(
73660             graph.parentWays(graph.entity(midpoint.edge[0])),
73661             graph.parentWays(graph.entity(midpoint.edge[1])));
73662
73663         parents.forEach(function(way) {
73664             for (var i = 0; i < way.nodes.length - 1; i++) {
73665                 if (geoEdgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
73666                     graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1));
73667
73668                     // Add only one midpoint on doubled-back segments,
73669                     // turning them into self-intersections.
73670                     return;
73671                 }
73672             }
73673         });
73674
73675         return graph;
73676     };
73677 }
73678
73679 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
73680 function actionAddVertex(wayId, nodeId, index) {
73681     return function(graph) {
73682         return graph.replace(graph.entity(wayId).addNode(nodeId, index));
73683     };
73684 }
73685
73686 function actionChangeMember(relationId, member, memberIndex) {
73687     return function(graph) {
73688         return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
73689     };
73690 }
73691
73692 function actionChangePreset(entityId, oldPreset, newPreset) {
73693     return function(graph) {
73694         var entity = graph.entity(entityId),
73695             geometry = entity.geometry(graph),
73696             tags = entity.tags;
73697
73698         if (oldPreset) tags = oldPreset.removeTags(tags, geometry);
73699         if (newPreset) tags = newPreset.applyTags(tags, geometry);
73700
73701         return graph.replace(entity.update({tags: tags}));
73702     };
73703 }
73704
73705 function actionChangeTags(entityId, tags) {
73706     return function(graph) {
73707         var entity = graph.entity(entityId);
73708         return graph.replace(entity.update({tags: tags}));
73709     };
73710 }
73711
73712 function actionCircularize(wayId, projection, maxAngle) {
73713     maxAngle = (maxAngle || 20) * Math.PI / 180;
73714
73715
73716     var action = function(graph, t) {
73717         if (t === null || !isFinite(t)) t = 1;
73718         t = Math.min(Math.max(+t, 0), 1);
73719
73720         var way = graph.entity(wayId),
73721             origNodes = {};
73722
73723         graph.childNodes(way).forEach(function(node) {
73724             if (!origNodes[node.id]) origNodes[node.id] = node;
73725         });
73726
73727         if (!way.isConvex(graph)) {
73728             graph = action.makeConvex(graph);
73729         }
73730
73731         var nodes = lodash.uniq(graph.childNodes(way)),
73732             keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }),
73733             points = nodes.map(function(n) { return projection(n.loc); }),
73734             keyPoints = keyNodes.map(function(n) { return projection(n.loc); }),
73735             centroid = (points.length === 2) ? geoInterp(points[0], points[1], 0.5) : d3polygonCentroid(points),
73736             radius = median(points, function(p) { return geoEuclideanDistance(centroid, p); }),
73737             sign = d3polygonArea(points) > 0 ? 1 : -1,
73738             ids;
73739
73740         // we need atleast two key nodes for the algorithm to work
73741         if (!keyNodes.length) {
73742             keyNodes = [nodes[0]];
73743             keyPoints = [points[0]];
73744         }
73745
73746         if (keyNodes.length === 1) {
73747             var index = nodes.indexOf(keyNodes[0]),
73748                 oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
73749
73750             keyNodes.push(nodes[oppositeIndex]);
73751             keyPoints.push(points[oppositeIndex]);
73752         }
73753
73754         // key points and nodes are those connected to the ways,
73755         // they are projected onto the circle, inbetween nodes are moved
73756         // to constant intervals between key nodes, extra inbetween nodes are
73757         // added if necessary.
73758         for (var i = 0; i < keyPoints.length; i++) {
73759             var nextKeyNodeIndex = (i + 1) % keyNodes.length,
73760                 startNode = keyNodes[i],
73761                 endNode = keyNodes[nextKeyNodeIndex],
73762                 startNodeIndex = nodes.indexOf(startNode),
73763                 endNodeIndex = nodes.indexOf(endNode),
73764                 numberNewPoints = -1,
73765                 indexRange = endNodeIndex - startNodeIndex,
73766                 nearNodes = {},
73767                 inBetweenNodes = [],
73768                 startAngle, endAngle, totalAngle, eachAngle,
73769                 angle, loc, node, origNode, j;
73770
73771             if (indexRange < 0) {
73772                 indexRange += nodes.length;
73773             }
73774
73775             // position this key node
73776             var distance = geoEuclideanDistance(centroid, keyPoints[i]);
73777             if (distance === 0) { distance = 1e-4; }
73778             keyPoints[i] = [
73779                 centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius,
73780                 centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius
73781             ];
73782             loc = projection.invert(keyPoints[i]);
73783             node = keyNodes[i];
73784             origNode = origNodes[node.id];
73785             node = node.move(geoInterp(origNode.loc, loc, t));
73786             graph = graph.replace(node);
73787
73788             // figure out the between delta angle we want to match to
73789             startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
73790             endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
73791             totalAngle = endAngle - startAngle;
73792
73793             // detects looping around -pi/pi
73794             if (totalAngle * sign > 0) {
73795                 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
73796             }
73797
73798             do {
73799                 numberNewPoints++;
73800                 eachAngle = totalAngle / (indexRange + numberNewPoints);
73801             } while (Math.abs(eachAngle) > maxAngle);
73802
73803
73804             // move existing nodes
73805             for (j = 1; j < indexRange; j++) {
73806                 angle = startAngle + j * eachAngle;
73807                 loc = projection.invert([
73808                     centroid[0] + Math.cos(angle) * radius,
73809                     centroid[1] + Math.sin(angle) * radius
73810                 ]);
73811
73812                 node = nodes[(j + startNodeIndex) % nodes.length];
73813                 origNode = origNodes[node.id];
73814                 nearNodes[node.id] = angle;
73815
73816                 node = node.move(geoInterp(origNode.loc, loc, t));
73817                 graph = graph.replace(node);
73818             }
73819
73820             // add new inbetween nodes if necessary
73821             for (j = 0; j < numberNewPoints; j++) {
73822                 angle = startAngle + (indexRange + j) * eachAngle;
73823                 loc = projection.invert([
73824                     centroid[0] + Math.cos(angle) * radius,
73825                     centroid[1] + Math.sin(angle) * radius
73826                 ]);
73827
73828                 // choose a nearnode to use as the original
73829                 var min$$1 = Infinity;
73830                 for (var nodeId in nearNodes) {
73831                     var nearAngle = nearNodes[nodeId],
73832                         dist = Math.abs(nearAngle - angle);
73833                     if (dist < min$$1) {
73834                         dist = min$$1;
73835                         origNode = origNodes[nodeId];
73836                     }
73837                 }
73838
73839                 node = osmNode({ loc: geoInterp(origNode.loc, loc, t) });
73840                 graph = graph.replace(node);
73841
73842                 nodes.splice(endNodeIndex + j, 0, node);
73843                 inBetweenNodes.push(node.id);
73844             }
73845
73846             // Check for other ways that share these keyNodes..
73847             // If keyNodes are adjacent in both ways,
73848             // we can add inBetween nodes to that shared way too..
73849             if (indexRange === 1 && inBetweenNodes.length) {
73850                 var startIndex1 = way.nodes.lastIndexOf(startNode.id),
73851                     endIndex1 = way.nodes.lastIndexOf(endNode.id),
73852                     wayDirection1 = (endIndex1 - startIndex1);
73853                 if (wayDirection1 < -1) { wayDirection1 = 1; }
73854
73855                 /* eslint-disable no-loop-func */
73856                 lodash.each(lodash.without(graph.parentWays(keyNodes[i]), way), function(sharedWay) {
73857                     if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
73858                         var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id),
73859                             endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id),
73860                             wayDirection2 = (endIndex2 - startIndex2),
73861                             insertAt = endIndex2;
73862                         if (wayDirection2 < -1) { wayDirection2 = 1; }
73863
73864                         if (wayDirection1 !== wayDirection2) {
73865                             inBetweenNodes.reverse();
73866                             insertAt = startIndex2;
73867                         }
73868                         for (j = 0; j < inBetweenNodes.length; j++) {
73869                             sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j);
73870                         }
73871                         graph = graph.replace(sharedWay);
73872                     }
73873                 });
73874                 /* eslint-enable no-loop-func */
73875             }
73876
73877         }
73878
73879         // update the way to have all the new nodes
73880         ids = nodes.map(function(n) { return n.id; });
73881         ids.push(ids[0]);
73882
73883         way = way.update({nodes: ids});
73884         graph = graph.replace(way);
73885
73886         return graph;
73887     };
73888
73889
73890     action.makeConvex = function(graph) {
73891         var way = graph.entity(wayId),
73892             nodes = lodash.uniq(graph.childNodes(way)),
73893             points = nodes.map(function(n) { return projection(n.loc); }),
73894             sign = d3polygonArea(points) > 0 ? 1 : -1,
73895             hull = d3polygonHull(points);
73896
73897         // D3 convex hulls go counterclockwise..
73898         if (sign === -1) {
73899             nodes.reverse();
73900             points.reverse();
73901         }
73902
73903         for (var i = 0; i < hull.length - 1; i++) {
73904             var startIndex = points.indexOf(hull[i]),
73905                 endIndex = points.indexOf(hull[i+1]),
73906                 indexRange = (endIndex - startIndex);
73907
73908             if (indexRange < 0) {
73909                 indexRange += nodes.length;
73910             }
73911
73912             // move interior nodes to the surface of the convex hull..
73913             for (var j = 1; j < indexRange; j++) {
73914                 var point = geoInterp(hull[i], hull[i+1], j / indexRange),
73915                     node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
73916                 graph = graph.replace(node);
73917             }
73918         }
73919         return graph;
73920     };
73921
73922
73923     action.disabled = function(graph) {
73924         if (!graph.entity(wayId).isClosed())
73925             return 'not_closed';
73926     };
73927
73928
73929     action.transitionable = true;
73930
73931
73932     return action;
73933 }
73934
73935 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
73936 function actionDeleteWay(wayId) {
73937
73938
73939     function canDeleteNode(node, graph) {
73940         return !graph.parentWays(node).length &&
73941             !graph.parentRelations(node).length &&
73942             !node.hasInterestingTags();
73943     }
73944
73945
73946     var action = function(graph) {
73947         var way = graph.entity(wayId);
73948
73949         graph.parentRelations(way)
73950             .forEach(function(parent) {
73951                 parent = parent.removeMembersWithID(wayId);
73952                 graph = graph.replace(parent);
73953
73954                 if (parent.isDegenerate()) {
73955                     graph = actionDeleteRelation(parent.id)(graph);
73956                 }
73957             });
73958
73959         lodash.uniq(way.nodes).forEach(function(nodeId) {
73960             graph = graph.replace(way.removeNode(nodeId));
73961
73962             var node = graph.entity(nodeId);
73963             if (canDeleteNode(node, graph)) {
73964                 graph = graph.remove(node);
73965             }
73966         });
73967
73968         return graph.remove(way);
73969     };
73970
73971
73972     return action;
73973 }
73974
73975 function actionDeleteMultiple(ids) {
73976     var actions = {
73977         way: actionDeleteWay,
73978         node: actionDeleteNode,
73979         relation: actionDeleteRelation
73980     };
73981
73982
73983     var action = function(graph) {
73984         ids.forEach(function(id) {
73985             if (graph.hasEntity(id)) { // It may have been deleted aready.
73986                 graph = actions[graph.entity(id).type](id)(graph);
73987             }
73988         });
73989
73990         return graph;
73991     };
73992
73993
73994     return action;
73995 }
73996
73997 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
73998 function actionDeleteRelation(relationId) {
73999
74000
74001     function canDeleteEntity(entity, graph) {
74002         return !graph.parentWays(entity).length &&
74003             !graph.parentRelations(entity).length &&
74004             !entity.hasInterestingTags();
74005     }
74006
74007
74008     var action = function(graph) {
74009         var relation = graph.entity(relationId);
74010
74011         graph.parentRelations(relation)
74012             .forEach(function(parent) {
74013                 parent = parent.removeMembersWithID(relationId);
74014                 graph = graph.replace(parent);
74015
74016                 if (parent.isDegenerate()) {
74017                     graph = actionDeleteRelation(parent.id)(graph);
74018                 }
74019             });
74020
74021         lodash.uniq(lodash.map(relation.members, 'id')).forEach(function(memberId) {
74022             graph = graph.replace(relation.removeMembersWithID(memberId));
74023
74024             var entity = graph.entity(memberId);
74025             if (canDeleteEntity(entity, graph)) {
74026                 graph = actionDeleteMultiple([memberId])(graph);
74027             }
74028         });
74029
74030         return graph.remove(relation);
74031     };
74032
74033
74034     return action;
74035 }
74036
74037 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as
74038 function actionDeleteNode(nodeId) {
74039     var action = function(graph) {
74040         var node = graph.entity(nodeId);
74041
74042         graph.parentWays(node)
74043             .forEach(function(parent) {
74044                 parent = parent.removeNode(nodeId);
74045                 graph = graph.replace(parent);
74046
74047                 if (parent.isDegenerate()) {
74048                     graph = actionDeleteWay(parent.id)(graph);
74049                 }
74050             });
74051
74052         graph.parentRelations(node)
74053             .forEach(function(parent) {
74054                 parent = parent.removeMembersWithID(nodeId);
74055                 graph = graph.replace(parent);
74056
74057                 if (parent.isDegenerate()) {
74058                     graph = actionDeleteRelation(parent.id)(graph);
74059                 }
74060             });
74061
74062         return graph.remove(node);
74063     };
74064
74065
74066     return action;
74067 }
74068
74069 // Connect the ways at the given nodes.
74070 //
74071 // The last node will survive. All other nodes will be replaced with
74072 // the surviving node in parent ways, and then removed.
74073 //
74074 // Tags and relation memberships of of non-surviving nodes are merged
74075 // to the survivor.
74076 //
74077 // This is the inverse of `iD.actionDisconnect`.
74078 //
74079 // Reference:
74080 //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
74081 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
74082 //
74083 function actionConnect(nodeIds) {
74084     return function(graph) {
74085         var survivor = graph.entity(lodash.last(nodeIds));
74086
74087         for (var i = 0; i < nodeIds.length - 1; i++) {
74088             var node = graph.entity(nodeIds[i]);
74089
74090             /* eslint-disable no-loop-func */
74091             graph.parentWays(node).forEach(function(parent) {
74092                 if (!parent.areAdjacent(node.id, survivor.id)) {
74093                     graph = graph.replace(parent.replaceNode(node.id, survivor.id));
74094                 }
74095             });
74096
74097             graph.parentRelations(node).forEach(function(parent) {
74098                 graph = graph.replace(parent.replaceMember(node, survivor));
74099             });
74100             /* eslint-enable no-loop-func */
74101
74102             survivor = survivor.mergeTags(node.tags);
74103             graph = actionDeleteNode(node.id)(graph);
74104         }
74105
74106         graph = graph.replace(survivor);
74107
74108         return graph;
74109     };
74110 }
74111
74112 function actionCopyEntities(ids, fromGraph) {
74113     var copies = {};
74114
74115
74116     var action = function(graph) {
74117         ids.forEach(function(id) {
74118             fromGraph.entity(id).copy(fromGraph, copies);
74119         });
74120
74121         for (var id in copies) {
74122             graph = graph.replace(copies[id]);
74123         }
74124
74125         return graph;
74126     };
74127
74128
74129     action.copies = function() {
74130         return copies;
74131     };
74132
74133
74134     return action;
74135 }
74136
74137 function actionDeleteMember(relationId, memberIndex) {
74138     return function(graph) {
74139         var relation = graph.entity(relationId)
74140             .removeMember(memberIndex);
74141
74142         graph = graph.replace(relation);
74143
74144         if (relation.isDegenerate())
74145             graph = actionDeleteRelation(relation.id)(graph);
74146
74147         return graph;
74148     };
74149 }
74150
74151 function actionDeprecateTags(entityId) {
74152
74153     return function(graph) {
74154         var entity = graph.entity(entityId),
74155             newtags = lodash.clone(entity.tags),
74156             change = false,
74157             rule;
74158
74159         // This handles dataDeprecated tags with a single condition
74160         for (var i = 0; i < dataDeprecated.length; i++) {
74161
74162             rule = dataDeprecated[i];
74163             var match = lodash.toPairs(rule.old)[0],
74164                 replacements = rule.replace ? lodash.toPairs(rule.replace) : null;
74165
74166             if (entity.tags[match[0]] && match[1] === '*') {
74167
74168                 var value = entity.tags[match[0]];
74169                 if (replacements && !newtags[replacements[0][0]]) {
74170                     newtags[replacements[0][0]] = value;
74171                 }
74172                 delete newtags[match[0]];
74173                 change = true;
74174
74175             } else if (entity.tags[match[0]] === match[1]) {
74176                 newtags = lodash.assign({}, rule.replace || {}, lodash.omit(newtags, match[0]));
74177                 change = true;
74178             }
74179         }
74180
74181         if (change) {
74182             return graph.replace(entity.update({tags: newtags}));
74183         } else {
74184             return graph;
74185         }
74186     };
74187 }
74188
74189 function actionDiscardTags(difference) {
74190
74191     return function(graph) {
74192         function discardTags(entity) {
74193             if (!lodash.isEmpty(entity.tags)) {
74194                 var tags = {};
74195                 lodash.each(entity.tags, function(v, k) {
74196                     if (v) tags[k] = v;
74197                 });
74198
74199                 graph = graph.replace(entity.update({
74200                     tags: lodash.omit(tags, dataDiscarded)
74201                 }));
74202             }
74203         }
74204
74205         difference.modified().forEach(discardTags);
74206         difference.created().forEach(discardTags);
74207
74208         return graph;
74209     };
74210 }
74211
74212 // Disconect the ways at the given node.
74213 //
74214 // Optionally, disconnect only the given ways.
74215 //
74216 // For testing convenience, accepts an ID to assign to the (first) new node.
74217 // Normally, this will be undefined and the way will automatically
74218 // be assigned a new ID.
74219 //
74220 // This is the inverse of `iD.actionConnect`.
74221 //
74222 // Reference:
74223 //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
74224 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
74225 //
74226 function actionDisconnect(nodeId, newNodeId) {
74227     var wayIds;
74228
74229
74230     var action = function(graph) {
74231         var node = graph.entity(nodeId),
74232             connections = action.connections(graph);
74233
74234         connections.forEach(function(connection) {
74235             var way = graph.entity(connection.wayID),
74236                 newNode = osmNode({id: newNodeId, loc: node.loc, tags: node.tags});
74237
74238             graph = graph.replace(newNode);
74239             if (connection.index === 0 && way.isArea()) {
74240                 // replace shared node with shared node..
74241                 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
74242             } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
74243                 // replace closing node with new new node..
74244                 graph = graph.replace(way.unclose().addNode(newNode.id));
74245             } else {
74246                 // replace shared node with multiple new nodes..
74247                 graph = graph.replace(way.updateNode(newNode.id, connection.index));
74248             }
74249         });
74250
74251         return graph;
74252     };
74253
74254
74255     action.connections = function(graph) {
74256         var candidates = [],
74257             keeping = false,
74258             parentWays = graph.parentWays(graph.entity(nodeId));
74259
74260         parentWays.forEach(function(way) {
74261             if (wayIds && wayIds.indexOf(way.id) === -1) {
74262                 keeping = true;
74263                 return;
74264             }
74265             if (way.isArea() && (way.nodes[0] === nodeId)) {
74266                 candidates.push({ wayID: way.id, index: 0 });
74267             } else {
74268                 way.nodes.forEach(function(waynode, index) {
74269                     if (waynode === nodeId) {
74270                         candidates.push({ wayID: way.id, index: index });
74271                     }
74272                 });
74273             }
74274         });
74275
74276         return keeping ? candidates : candidates.slice(1);
74277     };
74278
74279
74280     action.disabled = function(graph) {
74281         var connections = action.connections(graph);
74282         if (connections.length === 0 || (wayIds && wayIds.length !== connections.length))
74283             return 'not_connected';
74284
74285         var parentWays = graph.parentWays(graph.entity(nodeId)),
74286             seenRelationIds = {},
74287             sharedRelation;
74288
74289         parentWays.forEach(function(way) {
74290             if (wayIds && wayIds.indexOf(way.id) === -1)
74291                 return;
74292
74293             var relations = graph.parentRelations(way);
74294             relations.forEach(function(relation) {
74295                 if (relation.id in seenRelationIds) {
74296                     sharedRelation = relation;
74297                 } else {
74298                     seenRelationIds[relation.id] = true;
74299                 }
74300             });
74301         });
74302
74303         if (sharedRelation)
74304             return 'relation';
74305     };
74306
74307
74308     action.limitWays = function(_) {
74309         if (!arguments.length) return wayIds;
74310         wayIds = _;
74311         return action;
74312     };
74313
74314
74315     return action;
74316 }
74317
74318 // Join ways at the end node they share.
74319 //
74320 // This is the inverse of `iD.actionSplit`.
74321 //
74322 // Reference:
74323 //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
74324 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
74325 //
74326 function actionJoin(ids) {
74327
74328     function groupEntitiesByGeometry(graph) {
74329         var entities = ids.map(function(id) { return graph.entity(id); });
74330         return lodash.extend({line: []}, lodash.groupBy(entities, function(entity) { return entity.geometry(graph); }));
74331     }
74332
74333
74334     var action = function(graph) {
74335         var ways = ids.map(graph.entity, graph),
74336             survivor = ways[0];
74337
74338         // Prefer to keep an existing way.
74339         for (var i = 0; i < ways.length; i++) {
74340             if (!ways[i].isNew()) {
74341                 survivor = ways[i];
74342                 break;
74343             }
74344         }
74345
74346         var joined = osmJoinWays(ways, graph)[0];
74347
74348         survivor = survivor.update({nodes: lodash.map(joined.nodes, 'id')});
74349         graph = graph.replace(survivor);
74350
74351         joined.forEach(function(way) {
74352             if (way.id === survivor.id)
74353                 return;
74354
74355             graph.parentRelations(way).forEach(function(parent) {
74356                 graph = graph.replace(parent.replaceMember(way, survivor));
74357             });
74358
74359             survivor = survivor.mergeTags(way.tags);
74360
74361             graph = graph.replace(survivor);
74362             graph = actionDeleteWay(way.id)(graph);
74363         });
74364
74365         return graph;
74366     };
74367
74368
74369     action.disabled = function(graph) {
74370         var geometries = groupEntitiesByGeometry(graph);
74371         if (ids.length < 2 || ids.length !== geometries.line.length)
74372             return 'not_eligible';
74373
74374         var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
74375         if (joined.length > 1)
74376             return 'not_adjacent';
74377
74378         var nodeIds = lodash.map(joined[0].nodes, 'id').slice(1, -1),
74379             relation,
74380             tags = {},
74381             conflicting = false;
74382
74383         joined[0].forEach(function(way) {
74384             var parents = graph.parentRelations(way);
74385             parents.forEach(function(parent) {
74386                 if (parent.isRestriction() && parent.members.some(function(m) { return nodeIds.indexOf(m.id) >= 0; }))
74387                     relation = parent;
74388             });
74389
74390             for (var k in way.tags) {
74391                 if (!(k in tags)) {
74392                     tags[k] = way.tags[k];
74393                 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
74394                     conflicting = true;
74395                 }
74396             }
74397         });
74398
74399         if (relation)
74400             return 'restriction';
74401
74402         if (conflicting)
74403             return 'conflicting_tags';
74404     };
74405
74406
74407     return action;
74408 }
74409
74410 function actionMerge(ids) {
74411
74412     function groupEntitiesByGeometry(graph) {
74413         var entities = ids.map(function(id) { return graph.entity(id); });
74414         return lodash.extend({point: [], area: [], line: [], relation: []},
74415             lodash.groupBy(entities, function(entity) { return entity.geometry(graph); }));
74416     }
74417
74418
74419     var action = function(graph) {
74420         var geometries = groupEntitiesByGeometry(graph),
74421             target = geometries.area[0] || geometries.line[0],
74422             points = geometries.point;
74423
74424         points.forEach(function(point) {
74425             target = target.mergeTags(point.tags);
74426             graph = graph.replace(target);
74427
74428             graph.parentRelations(point).forEach(function(parent) {
74429                 graph = graph.replace(parent.replaceMember(point, target));
74430             });
74431
74432             var nodes = lodash.uniq(graph.childNodes(target)),
74433                 removeNode = point;
74434
74435             for (var i = 0; i < nodes.length; i++) {
74436                 var node = nodes[i];
74437                 if (graph.parentWays(node).length > 1 ||
74438                     graph.parentRelations(node).length ||
74439                     node.hasInterestingTags()) {
74440                     continue;
74441                 }
74442
74443                 // Found an uninteresting child node on the target way.
74444                 // Move orig point into its place to preserve point's history. #3683
74445                 graph = graph.replace(point.update({ tags: {}, loc: node.loc }));
74446                 target = target.replaceNode(node.id, point.id);
74447                 graph = graph.replace(target);
74448                 removeNode = node;
74449                 break;
74450             }
74451
74452             graph = graph.remove(removeNode);
74453         });
74454
74455         return graph;
74456     };
74457
74458
74459     action.disabled = function(graph) {
74460         var geometries = groupEntitiesByGeometry(graph);
74461         if (geometries.point.length === 0 ||
74462             (geometries.area.length + geometries.line.length) !== 1 ||
74463             geometries.relation.length !== 0)
74464             return 'not_eligible';
74465     };
74466
74467
74468     return action;
74469 }
74470
74471 function actionMergePolygon(ids, newRelationId) {
74472
74473     function groupEntities(graph) {
74474         var entities = ids.map(function (id) { return graph.entity(id); });
74475         return lodash.extend({
74476                 closedWay: [],
74477                 multipolygon: [],
74478                 other: []
74479             }, lodash.groupBy(entities, function(entity) {
74480                 if (entity.type === 'way' && entity.isClosed()) {
74481                     return 'closedWay';
74482                 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
74483                     return 'multipolygon';
74484                 } else {
74485                     return 'other';
74486                 }
74487             }));
74488     }
74489
74490
74491     var action = function(graph) {
74492         var entities = groupEntities(graph);
74493
74494         // An array representing all the polygons that are part of the multipolygon.
74495         //
74496         // Each element is itself an array of objects with an id property, and has a
74497         // locs property which is an array of the locations forming the polygon.
74498         var polygons = entities.multipolygon.reduce(function(polygons, m) {
74499             return polygons.concat(osmJoinWays(m.members, graph));
74500         }, []).concat(entities.closedWay.map(function(d) {
74501             var member = [{id: d.id}];
74502             member.nodes = graph.childNodes(d);
74503             return member;
74504         }));
74505
74506         // contained is an array of arrays of boolean values,
74507         // where contained[j][k] is true iff the jth way is
74508         // contained by the kth way.
74509         var contained = polygons.map(function(w, i) {
74510             return polygons.map(function(d, n) {
74511                 if (i === n) return null;
74512                 return geoPolygonContainsPolygon(
74513                     lodash.map(d.nodes, 'loc'),
74514                     lodash.map(w.nodes, 'loc'));
74515             });
74516         });
74517
74518         // Sort all polygons as either outer or inner ways
74519         var members = [],
74520             outer = true;
74521
74522         while (polygons.length) {
74523             extractUncontained(polygons);
74524             polygons = polygons.filter(isContained);
74525             contained = contained.filter(isContained).map(filterContained);
74526         }
74527
74528         function isContained(d, i) {
74529             return lodash.some(contained[i]);
74530         }
74531
74532         function filterContained(d) {
74533             return d.filter(isContained);
74534         }
74535
74536         function extractUncontained(polygons) {
74537             polygons.forEach(function(d, i) {
74538                 if (!isContained(d, i)) {
74539                     d.forEach(function(member) {
74540                         members.push({
74541                             type: 'way',
74542                             id: member.id,
74543                             role: outer ? 'outer' : 'inner'
74544                         });
74545                     });
74546                 }
74547             });
74548             outer = !outer;
74549         }
74550
74551         // Move all tags to one relation
74552         var relation = entities.multipolygon[0] ||
74553             osmRelation({ id: newRelationId, tags: { type: 'multipolygon' }});
74554
74555         entities.multipolygon.slice(1).forEach(function(m) {
74556             relation = relation.mergeTags(m.tags);
74557             graph = graph.remove(m);
74558         });
74559
74560         entities.closedWay.forEach(function(way) {
74561             function isThisOuter(m) {
74562                 return m.id === way.id && m.role !== 'inner';
74563             }
74564             if (members.some(isThisOuter)) {
74565                 relation = relation.mergeTags(way.tags);
74566                 graph = graph.replace(way.update({ tags: {} }));
74567             }
74568         });
74569
74570         return graph.replace(relation.update({
74571             members: members,
74572             tags: lodash.omit(relation.tags, 'area')
74573         }));
74574     };
74575
74576
74577     action.disabled = function(graph) {
74578         var entities = groupEntities(graph);
74579         if (entities.other.length > 0 ||
74580             entities.closedWay.length + entities.multipolygon.length < 2)
74581             return 'not_eligible';
74582         if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
74583             return 'incomplete_relation';
74584     };
74585
74586
74587     return action;
74588 }
74589
74590 // Copyright (c) 2006, 2008 Tony Garnock-Jones <tonyg@lshift.net>
74591 // Copyright (c) 2006, 2008 LShift Ltd. <query@lshift.net>
74592 //
74593 // Permission is hereby granted, free of charge, to any person
74594 // obtaining a copy of this software and associated documentation files
74595 // (the "Software"), to deal in the Software without restriction,
74596 // including without limitation the rights to use, copy, modify, merge,
74597 // publish, distribute, sublicense, and/or sell copies of the Software,
74598 // and to permit persons to whom the Software is furnished to do so,
74599 // subject to the following conditions:
74600 //
74601 // The above copyright notice and this permission notice shall be
74602 // included in all copies or substantial portions of the Software.
74603 //
74604 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
74605 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
74606 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
74607 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
74608 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
74609 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
74610 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
74611 // SOFTWARE.
74612
74613 // source:  https://bitbucket.org/lshift/synchrotron/src
74614 function longest_common_subsequence(file1, file2) {
74615     /* Text diff algorithm following Hunt and McIlroy 1976.
74616      * J. W. Hunt and M. D. McIlroy, An algorithm for differential file
74617      * comparison, Bell Telephone Laboratories CSTR #41 (1976)
74618      * http://www.cs.dartmouth.edu/~doug/
74619      *
74620      * Expects two arrays of strings.
74621      */
74622     var equivalenceClasses;
74623     var file2indices;
74624     var newCandidate;
74625     var candidates;
74626     var line;
74627     var c, i, j, jX, r, s;
74628
74629     equivalenceClasses = {};
74630     for (j = 0; j < file2.length; j++) {
74631         line = file2[j];
74632         if (equivalenceClasses[line]) {
74633             equivalenceClasses[line].push(j);
74634         } else {
74635             equivalenceClasses[line] = [j];
74636         }
74637     }
74638
74639     candidates = [{file1index: -1,
74640                    file2index: -1,
74641                    chain: null}];
74642
74643     for (i = 0; i < file1.length; i++) {
74644         line = file1[i];
74645         file2indices = equivalenceClasses[line] || [];
74646
74647         r = 0;
74648         c = candidates[0];
74649
74650         for (jX = 0; jX < file2indices.length; jX++) {
74651             j = file2indices[jX];
74652
74653             for (s = 0; s < candidates.length; s++) {
74654                 if ((candidates[s].file2index < j) &&
74655                     ((s === candidates.length - 1) ||
74656                      (candidates[s + 1].file2index > j)))
74657                     break;
74658             }
74659
74660             if (s < candidates.length) {
74661                 newCandidate = {file1index: i,
74662                                 file2index: j,
74663                                 chain: candidates[s]};
74664                 if (r === candidates.length) {
74665                     candidates.push(c);
74666                 } else {
74667                     candidates[r] = c;
74668                 }
74669                 r = s + 1;
74670                 c = newCandidate;
74671                 if (r === candidates.length) {
74672                     break; // no point in examining further (j)s
74673                 }
74674             }
74675         }
74676
74677         candidates[r] = c;
74678     }
74679
74680     // At this point, we know the LCS: it's in the reverse of the
74681     // linked-list through .chain of
74682     // candidates[candidates.length - 1].
74683
74684     return candidates[candidates.length - 1];
74685 }
74686
74687
74688
74689
74690
74691
74692
74693
74694
74695
74696
74697 function diff_indices(file1, file2) {
74698     // We apply the LCS to give a simple representation of the
74699     // offsets and lengths of mismatched chunks in the input
74700     // files. This is used by diff3_merge_indices below.
74701
74702     var result = [];
74703     var tail1 = file1.length;
74704     var tail2 = file2.length;
74705
74706     for (var candidate = longest_common_subsequence(file1, file2);
74707          candidate !== null;
74708          candidate = candidate.chain)
74709     {
74710         var mismatchLength1 = tail1 - candidate.file1index - 1;
74711         var mismatchLength2 = tail2 - candidate.file2index - 1;
74712         tail1 = candidate.file1index;
74713         tail2 = candidate.file2index;
74714
74715         if (mismatchLength1 || mismatchLength2) {
74716             result.push({file1: [tail1 + 1, mismatchLength1],
74717                          file2: [tail2 + 1, mismatchLength2]});
74718         }
74719     }
74720
74721     result.reverse();
74722     return result;
74723 }
74724
74725 function diff3_merge_indices (a, o, b) {
74726     // Given three files, A, O, and B, where both A and B are
74727     // independently derived from O, returns a fairly complicated
74728     // internal representation of merge decisions it's taken. The
74729     // interested reader may wish to consult
74730     //
74731     // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce. "A
74732     // Formal Investigation of Diff3." In Arvind and Prasad,
74733     // editors, Foundations of Software Technology and Theoretical
74734     // Computer Science (FSTTCS), December 2007.
74735     //
74736     // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
74737     var i;
74738
74739     var m1 = diff_indices(o, a);
74740     var m2 = diff_indices(o, b);
74741
74742     var hunks = [];
74743     function addHunk(h, side) {
74744         hunks.push([h.file1[0], side, h.file1[1], h.file2[0], h.file2[1]]);
74745     }
74746     for (i = 0; i < m1.length; i++) { addHunk(m1[i], 0); }
74747     for (i = 0; i < m2.length; i++) { addHunk(m2[i], 2); }
74748     hunks.sort();
74749
74750     var result = [];
74751     var commonOffset = 0;
74752     function copyCommon(targetOffset) {
74753         if (targetOffset > commonOffset) {
74754             result.push([1, commonOffset, targetOffset - commonOffset]);
74755             commonOffset = targetOffset;
74756         }
74757     }
74758
74759     for (var hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {
74760         var firstHunkIndex = hunkIndex;
74761         var hunk = hunks[hunkIndex];
74762         var regionLhs = hunk[0];
74763         var regionRhs = regionLhs + hunk[2];
74764         while (hunkIndex < hunks.length - 1) {
74765             var maybeOverlapping = hunks[hunkIndex + 1];
74766             var maybeLhs = maybeOverlapping[0];
74767             if (maybeLhs > regionRhs) break;
74768             regionRhs = maybeLhs + maybeOverlapping[2];
74769             hunkIndex++;
74770         }
74771
74772         copyCommon(regionLhs);
74773         if (firstHunkIndex === hunkIndex) {
74774     // The "overlap" was only one hunk long, meaning that
74775     // there's no conflict here. Either a and o were the
74776     // same, or b and o were the same.
74777             if (hunk[4] > 0) {
74778                 result.push([hunk[1], hunk[3], hunk[4]]);
74779             }
74780         } else {
74781     // A proper conflict. Determine the extents of the
74782     // regions involved from a, o and b. Effectively merge
74783     // all the hunks on the left into one giant hunk, and
74784     // do the same for the right; then, correct for skew
74785     // in the regions of o that each side changed, and
74786     // report appropriate spans for the three sides.
74787     var regions = {
74788         0: [a.length, -1, o.length, -1],
74789         2: [b.length, -1, o.length, -1]
74790     };
74791             for (i = firstHunkIndex; i <= hunkIndex; i++) {
74792         hunk = hunks[i];
74793                 var side = hunk[1];
74794         var r = regions[side];
74795         var oLhs = hunk[0];
74796         var oRhs = oLhs + hunk[2];
74797                 var abLhs = hunk[3];
74798                 var abRhs = abLhs + hunk[4];
74799         r[0] = Math.min(abLhs, r[0]);
74800         r[1] = Math.max(abRhs, r[1]);
74801         r[2] = Math.min(oLhs, r[2]);
74802         r[3] = Math.max(oRhs, r[3]);
74803             }
74804     var aLhs = regions[0][0] + (regionLhs - regions[0][2]);
74805     var aRhs = regions[0][1] + (regionRhs - regions[0][3]);
74806     var bLhs = regions[2][0] + (regionLhs - regions[2][2]);
74807     var bRhs = regions[2][1] + (regionRhs - regions[2][3]);
74808             result.push([-1,
74809              aLhs,      aRhs      - aLhs,
74810              regionLhs, regionRhs - regionLhs,
74811              bLhs,      bRhs      - bLhs]);
74812         }
74813         commonOffset = regionRhs;
74814     }
74815
74816     copyCommon(o.length);
74817     return result;
74818 }
74819
74820 function diff3_merge (a, o, b, excludeFalseConflicts) {
74821     // Applies the output of Diff3.diff3_merge_indices to actually
74822     // construct the merged file; the returned result alternates
74823     // between "ok" and "conflict" blocks.
74824
74825     var result = [];
74826     var files = [a, o, b];
74827     var indices = diff3_merge_indices(a, o, b);
74828
74829     var okLines = [];
74830     function flushOk() {
74831         if (okLines.length) {
74832             result.push({ok: okLines});
74833         }
74834         okLines = [];
74835     }
74836     function pushOk(xs) {
74837         for (var j = 0; j < xs.length; j++) {
74838             okLines.push(xs[j]);
74839         }
74840     }
74841
74842     function isTrueConflict(rec) {
74843         if (rec[2] !== rec[6]) return true;
74844         var aoff = rec[1];
74845         var boff = rec[5];
74846         for (var j = 0; j < rec[2]; j++) {
74847             if (a[j + aoff] !== b[j + boff]) return true;
74848         }
74849         return false;
74850     }
74851
74852     for (var i = 0; i < indices.length; i++) {
74853         var x = indices[i];
74854         var side = x[0];
74855         if (side === -1) {
74856             if (excludeFalseConflicts && !isTrueConflict(x)) {
74857                 pushOk(files[0].slice(x[1], x[1] + x[2]));
74858             } else {
74859                 flushOk();
74860                 result.push({conflict: {a: a.slice(x[1], x[1] + x[2]),
74861                                         aIndex: x[1],
74862                                         o: o.slice(x[3], x[3] + x[4]),
74863                                         oIndex: x[3],
74864                                         b: b.slice(x[5], x[5] + x[6]),
74865                                         bIndex: x[5]}});
74866             }
74867         } else {
74868             pushOk(files[side].slice(x[1], x[1] + x[2]));
74869         }
74870     }
74871
74872     flushOk();
74873     return result;
74874 }
74875
74876 function actionMergeRemoteChanges(id, localGraph, remoteGraph, formatUser) {
74877     var option = 'safe',  // 'safe', 'force_local', 'force_remote'
74878         conflicts = [];
74879
74880
74881     function user(d) {
74882         return lodash.isFunction(formatUser) ? formatUser(d) : d;
74883     }
74884
74885
74886     function mergeLocation(remote, target) {
74887         function pointEqual(a, b) {
74888             var epsilon = 1e-6;
74889             return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon);
74890         }
74891
74892         if (option === 'force_local' || pointEqual(target.loc, remote.loc)) {
74893             return target;
74894         }
74895         if (option === 'force_remote') {
74896             return target.update({loc: remote.loc});
74897         }
74898
74899         conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
74900         return target;
74901     }
74902
74903
74904     function mergeNodes(base, remote, target) {
74905         if (option === 'force_local' || lodash.isEqual(target.nodes, remote.nodes)) {
74906             return target;
74907         }
74908         if (option === 'force_remote') {
74909             return target.update({nodes: remote.nodes});
74910         }
74911
74912         var ccount = conflicts.length,
74913             o = base.nodes || [],
74914             a = target.nodes || [],
74915             b = remote.nodes || [],
74916             nodes = [],
74917             hunks = diff3_merge(a, o, b, true);
74918
74919         for (var i = 0; i < hunks.length; i++) {
74920             var hunk = hunks[i];
74921             if (hunk.ok) {
74922                 nodes.push.apply(nodes, hunk.ok);
74923             } else {
74924                 // for all conflicts, we can assume c.a !== c.b
74925                 // because `diff3_merge` called with `true` option to exclude false conflicts..
74926                 var c = hunk.conflict;
74927                 if (lodash.isEqual(c.o, c.a)) {  // only changed remotely
74928                     nodes.push.apply(nodes, c.b);
74929                 } else if (lodash.isEqual(c.o, c.b)) {  // only changed locally
74930                     nodes.push.apply(nodes, c.a);
74931                 } else {       // changed both locally and remotely
74932                     conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
74933                     break;
74934                 }
74935             }
74936         }
74937
74938         return (conflicts.length === ccount) ? target.update({nodes: nodes}) : target;
74939     }
74940
74941
74942     function mergeChildren(targetWay, children, updates, graph) {
74943         function isUsed(node, targetWay) {
74944             var parentWays = lodash.map(graph.parentWays(node), 'id');
74945             return node.hasInterestingTags() ||
74946                 lodash.without(parentWays, targetWay.id).length > 0 ||
74947                 graph.parentRelations(node).length > 0;
74948         }
74949
74950         var ccount = conflicts.length;
74951
74952         for (var i = 0; i < children.length; i++) {
74953             var id = children[i],
74954                 node = graph.hasEntity(id);
74955
74956             // remove unused childNodes..
74957             if (targetWay.nodes.indexOf(id) === -1) {
74958                 if (node && !isUsed(node, targetWay)) {
74959                     updates.removeIds.push(id);
74960                 }
74961                 continue;
74962             }
74963
74964             // restore used childNodes..
74965             var local = localGraph.hasEntity(id),
74966                 remote = remoteGraph.hasEntity(id),
74967                 target;
74968
74969             if (option === 'force_remote' && remote && remote.visible) {
74970                 updates.replacements.push(remote);
74971
74972             } else if (option === 'force_local' && local) {
74973                 target = osmEntity$$1(local);
74974                 if (remote) {
74975                     target = target.update({ version: remote.version });
74976                 }
74977                 updates.replacements.push(target);
74978
74979             } else if (option === 'safe' && local && remote && local.version !== remote.version) {
74980                 target = osmEntity$$1(local, { version: remote.version });
74981                 if (remote.visible) {
74982                     target = mergeLocation(remote, target);
74983                 } else {
74984                     conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
74985                 }
74986
74987                 if (conflicts.length !== ccount) break;
74988                 updates.replacements.push(target);
74989             }
74990         }
74991
74992         return targetWay;
74993     }
74994
74995
74996     function updateChildren(updates, graph) {
74997         for (var i = 0; i < updates.replacements.length; i++) {
74998             graph = graph.replace(updates.replacements[i]);
74999         }
75000         if (updates.removeIds.length) {
75001             graph = actionDeleteMultiple(updates.removeIds)(graph);
75002         }
75003         return graph;
75004     }
75005
75006
75007     function mergeMembers(remote, target) {
75008         if (option === 'force_local' || lodash.isEqual(target.members, remote.members)) {
75009             return target;
75010         }
75011         if (option === 'force_remote') {
75012             return target.update({members: remote.members});
75013         }
75014
75015         conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
75016         return target;
75017     }
75018
75019
75020     function mergeTags(base, remote, target) {
75021         function ignoreKey(k) {
75022             return lodash.includes(dataDiscarded, k);
75023         }
75024
75025         if (option === 'force_local' || lodash.isEqual(target.tags, remote.tags)) {
75026             return target;
75027         }
75028         if (option === 'force_remote') {
75029             return target.update({tags: remote.tags});
75030         }
75031
75032         var ccount = conflicts.length,
75033             o = base.tags || {},
75034             a = target.tags || {},
75035             b = remote.tags || {},
75036             keys = lodash.reject(lodash.union(lodash.keys(o), lodash.keys(a), lodash.keys(b)), ignoreKey),
75037             tags = lodash.clone(a),
75038             changed = false;
75039
75040         for (var i = 0; i < keys.length; i++) {
75041             var k = keys[i];
75042
75043             if (o[k] !== b[k] && a[k] !== b[k]) {    // changed remotely..
75044                 if (o[k] !== a[k]) {      // changed locally..
75045                     conflicts.push(t('merge_remote_changes.conflict.tags',
75046                         { tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
75047
75048                 } else {                  // unchanged locally, accept remote change..
75049                     if (b.hasOwnProperty(k)) {
75050                         tags[k] = b[k];
75051                     } else {
75052                         delete tags[k];
75053                     }
75054                     changed = true;
75055                 }
75056             }
75057         }
75058
75059         return (changed && conflicts.length === ccount) ? target.update({tags: tags}) : target;
75060     }
75061
75062
75063     //  `graph.base()` is the common ancestor of the two graphs.
75064     //  `localGraph` contains user's edits up to saving
75065     //  `remoteGraph` contains remote edits to modified nodes
75066     //  `graph` must be a descendent of `localGraph` and may include
75067     //      some conflict resolution actions performed on it.
75068     //
75069     //                  --- ... --- `localGraph` -- ... -- `graph`
75070     //                 /
75071     //  `graph.base()` --- ... --- `remoteGraph`
75072     //
75073     var action = function(graph) {
75074         var updates = { replacements: [], removeIds: [] },
75075             base = graph.base().entities[id],
75076             local = localGraph.entity(id),
75077             remote = remoteGraph.entity(id),
75078             target = osmEntity$$1(local, { version: remote.version });
75079
75080         // delete/undelete
75081         if (!remote.visible) {
75082             if (option === 'force_remote') {
75083                 return actionDeleteMultiple([id])(graph);
75084
75085             } else if (option === 'force_local') {
75086                 if (target.type === 'way') {
75087                     target = mergeChildren(target, lodash.uniq(local.nodes), updates, graph);
75088                     graph = updateChildren(updates, graph);
75089                 }
75090                 return graph.replace(target);
75091
75092             } else {
75093                 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
75094                 return graph;  // do nothing
75095             }
75096         }
75097
75098         // merge
75099         if (target.type === 'node') {
75100             target = mergeLocation(remote, target);
75101
75102         } else if (target.type === 'way') {
75103             // pull in any child nodes that may not be present locally..
75104             graph.rebase(remoteGraph.childNodes(remote), [graph], false);
75105             target = mergeNodes(base, remote, target);
75106             target = mergeChildren(target, lodash.union(local.nodes, remote.nodes), updates, graph);
75107
75108         } else if (target.type === 'relation') {
75109             target = mergeMembers(remote, target);
75110         }
75111
75112         target = mergeTags(base, remote, target);
75113
75114         if (!conflicts.length) {
75115             graph = updateChildren(updates, graph).replace(target);
75116         }
75117
75118         return graph;
75119     };
75120
75121
75122     action.withOption = function(opt) {
75123         option = opt;
75124         return action;
75125     };
75126
75127
75128     action.conflicts = function() {
75129         return conflicts;
75130     };
75131
75132
75133     return action;
75134 }
75135
75136 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
75137 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
75138 function actionMove(moveIds, tryDelta, projection, cache) {
75139     var delta = tryDelta;
75140
75141     function vecAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
75142     function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
75143
75144     function setupCache(graph) {
75145         function canMove(nodeId) {
75146             // Allow movement of any node that is in the selectedIDs list..
75147             if (moveIds.indexOf(nodeId) !== -1) return true;
75148
75149             // Allow movement of a vertex where 2 ways meet..
75150             var parents = lodash.map(graph.parentWays(graph.entity(nodeId)), 'id');
75151             if (parents.length < 3) return true;
75152
75153             // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
75154             var parentsMoving = lodash.every(parents, function(id) { return cache.moving[id]; });
75155             if (!parentsMoving) delete cache.moving[nodeId];
75156
75157             return parentsMoving;
75158         }
75159
75160         function cacheEntities(ids) {
75161             ids.forEach(function(id) {
75162                 if (cache.moving[id]) return;
75163                 cache.moving[id] = true;
75164
75165                 var entity = graph.hasEntity(id);
75166                 if (!entity) return;
75167
75168                 if (entity.type === 'node') {
75169                     cache.nodes.push(id);
75170                     cache.startLoc[id] = entity.loc;
75171                 } else if (entity.type === 'way') {
75172                     cache.ways.push(id);
75173                     cacheEntities(entity.nodes);
75174                 } else {
75175                     cacheEntities(entity.members.map(function(member) {
75176                         return member.id;
75177                     }));
75178                 }
75179             });
75180         }
75181
75182         function cacheIntersections(ids) {
75183             function isEndpoint(way, id) { return !way.isClosed() && !!way.affix(id); }
75184
75185             ids.forEach(function(id) {
75186                 // consider only intersections with 1 moved and 1 unmoved way.
75187                 var childNodes = graph.childNodes(graph.entity(id));
75188                 childNodes.forEach(function(node) {
75189                     var parents = graph.parentWays(node);
75190                     if (parents.length !== 2) return;
75191
75192                     var moved = graph.entity(id),
75193                         unmoved = lodash.find(parents, function(way) { return !cache.moving[way.id]; });
75194                     if (!unmoved) return;
75195
75196                     // exclude ways that are overly connected..
75197                     if (lodash.intersection(moved.nodes, unmoved.nodes).length > 2) return;
75198
75199                     if (moved.isArea() || unmoved.isArea()) return;
75200
75201                     cache.intersection[node.id] = {
75202                         nodeId: node.id,
75203                         movedId: moved.id,
75204                         unmovedId: unmoved.id,
75205                         movedIsEP: isEndpoint(moved, node.id),
75206                         unmovedIsEP: isEndpoint(unmoved, node.id)
75207                     };
75208                 });
75209             });
75210         }
75211
75212
75213         if (!cache) {
75214             cache = {};
75215         }
75216         if (!cache.ok) {
75217             cache.moving = {};
75218             cache.intersection = {};
75219             cache.replacedVertex = {};
75220             cache.startLoc = {};
75221             cache.nodes = [];
75222             cache.ways = [];
75223
75224             cacheEntities(moveIds);
75225             cacheIntersections(cache.ways);
75226             cache.nodes = lodash.filter(cache.nodes, canMove);
75227
75228             cache.ok = true;
75229         }
75230     }
75231
75232
75233     // Place a vertex where the moved vertex used to be, to preserve way shape..
75234     function replaceMovedVertex(nodeId, wayId, graph, delta) {
75235         var way = graph.entity(wayId),
75236             moved = graph.entity(nodeId),
75237             movedIndex = way.nodes.indexOf(nodeId),
75238             len, prevIndex, nextIndex;
75239
75240         if (way.isClosed()) {
75241             len = way.nodes.length - 1;
75242             prevIndex = (movedIndex + len - 1) % len;
75243             nextIndex = (movedIndex + len + 1) % len;
75244         } else {
75245             len = way.nodes.length;
75246             prevIndex = movedIndex - 1;
75247             nextIndex = movedIndex + 1;
75248         }
75249
75250         var prev = graph.hasEntity(way.nodes[prevIndex]),
75251             next = graph.hasEntity(way.nodes[nextIndex]);
75252
75253         // Don't add orig vertex at endpoint..
75254         if (!prev || !next) return graph;
75255
75256         var key = wayId + '_' + nodeId,
75257             orig = cache.replacedVertex[key];
75258         if (!orig) {
75259             orig = osmNode();
75260             cache.replacedVertex[key] = orig;
75261             cache.startLoc[orig.id] = cache.startLoc[nodeId];
75262         }
75263
75264         var start, end;
75265         if (delta) {
75266             start = projection(cache.startLoc[nodeId]);
75267             end = projection.invert(vecAdd(start, delta));
75268         } else {
75269             end = cache.startLoc[nodeId];
75270         }
75271         orig = orig.move(end);
75272
75273         var angle = Math.abs(geoAngle(orig, prev, projection) -
75274                 geoAngle(orig, next, projection)) * 180 / Math.PI;
75275
75276         // Don't add orig vertex if it would just make a straight line..
75277         if (angle > 175 && angle < 185) return graph;
75278
75279         // Don't add orig vertex if another point is already nearby (within 10m)
75280         if (geoSphericalDistance(prev.loc, orig.loc) < 10 ||
75281             geoSphericalDistance(orig.loc, next.loc) < 10) return graph;
75282
75283         // moving forward or backward along way?
75284         var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection),
75285             p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection),
75286             d1 = geoPathLength(p1),
75287             d2 = geoPathLength(p2),
75288             insertAt = (d1 < d2) ? movedIndex : nextIndex;
75289
75290         // moving around closed loop?
75291         if (way.isClosed() && insertAt === 0) insertAt = len;
75292
75293         way = way.addNode(orig.id, insertAt);
75294         return graph.replace(orig).replace(way);
75295     }
75296
75297
75298     // Reorder nodes around intersections that have moved..
75299     function unZorroIntersection(intersection, graph) {
75300         var vertex = graph.entity(intersection.nodeId),
75301             way1 = graph.entity(intersection.movedId),
75302             way2 = graph.entity(intersection.unmovedId),
75303             isEP1 = intersection.movedIsEP,
75304             isEP2 = intersection.unmovedIsEP;
75305
75306         // don't move the vertex if it is the endpoint of both ways.
75307         if (isEP1 && isEP2) return graph;
75308
75309         var nodes1 = lodash.without(graph.childNodes(way1), vertex),
75310             nodes2 = lodash.without(graph.childNodes(way2), vertex);
75311
75312         if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
75313         if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
75314
75315         var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection),
75316             edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection),
75317             loc;
75318
75319         // snap vertex to nearest edge (or some point between them)..
75320         if (!isEP1 && !isEP2) {
75321             var epsilon = 1e-4, maxIter = 10;
75322             for (var i = 0; i < maxIter; i++) {
75323                 loc = geoInterp(edge1.loc, edge2.loc, 0.5);
75324                 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
75325                 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
75326                 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
75327             }
75328         } else if (!isEP1) {
75329             loc = edge1.loc;
75330         } else {
75331             loc = edge2.loc;
75332         }
75333
75334         graph = graph.replace(vertex.move(loc));
75335
75336         // if zorro happened, reorder nodes..
75337         if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
75338             way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
75339             graph = graph.replace(way1);
75340         }
75341         if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
75342             way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
75343             graph = graph.replace(way2);
75344         }
75345
75346         return graph;
75347     }
75348
75349
75350     function cleanupIntersections(graph) {
75351         lodash.each(cache.intersection, function(obj) {
75352             graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, delta);
75353             graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
75354             graph = unZorroIntersection(obj, graph);
75355         });
75356
75357         return graph;
75358     }
75359
75360
75361     // check if moving way endpoint can cross an unmoved way, if so limit delta..
75362     function limitDelta(graph) {
75363         lodash.each(cache.intersection, function(obj) {
75364             // Don't limit movement if this is vertex joins 2 endpoints..
75365             if (obj.movedIsEP && obj.unmovedIsEP) return;
75366             // Don't limit movement if this vertex is not an endpoint anyway..
75367             if (!obj.movedIsEP) return;
75368
75369             var node = graph.entity(obj.nodeId),
75370                 start = projection(node.loc),
75371                 end = vecAdd(start, delta),
75372                 movedNodes = graph.childNodes(graph.entity(obj.movedId)),
75373                 movedPath = lodash.map(lodash.map(movedNodes, 'loc'),
75374                     function(loc) { return vecAdd(projection(loc), delta); }),
75375                 unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId)),
75376                 unmovedPath = lodash.map(lodash.map(unmovedNodes, 'loc'), projection),
75377                 hits = geoPathIntersections(movedPath, unmovedPath);
75378
75379             for (var i = 0; i < hits.length; i++) {
75380                 if (lodash.isEqual(hits[i], end)) continue;
75381                 var edge = geoChooseEdge(unmovedNodes, end, projection);
75382                 delta = vecSub(projection(edge.loc), start);
75383             }
75384         });
75385     }
75386
75387
75388     var action = function(graph) {
75389         if (delta[0] === 0 && delta[1] === 0) return graph;
75390
75391         setupCache(graph);
75392
75393         if (!lodash.isEmpty(cache.intersection)) {
75394             limitDelta(graph);
75395         }
75396
75397         lodash.each(cache.nodes, function(id) {
75398             var node = graph.entity(id),
75399                 start = projection(node.loc),
75400                 end = vecAdd(start, delta);
75401             graph = graph.replace(node.move(projection.invert(end)));
75402         });
75403
75404         if (!lodash.isEmpty(cache.intersection)) {
75405             graph = cleanupIntersections(graph);
75406         }
75407
75408         return graph;
75409     };
75410
75411
75412     action.delta = function() {
75413         return delta;
75414     };
75415
75416
75417     return action;
75418 }
75419
75420 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
75421 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
75422 function actionMoveNode(nodeId, loc) {
75423     return function(graph) {
75424         return graph.replace(graph.entity(nodeId).move(loc));
75425     };
75426 }
75427
75428 function actionNoop() {
75429     return function(graph) {
75430         return graph;
75431     };
75432 }
75433
75434 /*
75435  * Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
75436  */
75437 function actionOrthogonalize(wayId, projection) {
75438     var threshold = 12, // degrees within right or straight to alter
75439         lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180),
75440         upperThreshold = Math.cos(threshold * Math.PI / 180);
75441
75442
75443     var action = function(graph, t) {
75444         if (t === null || !isFinite(t)) t = 1;
75445         t = Math.min(Math.max(+t, 0), 1);
75446
75447         var way = graph.entity(wayId),
75448             nodes = graph.childNodes(way),
75449             points = lodash.uniq(nodes).map(function(n) { return projection(n.loc); }),
75450             corner = {i: 0, dotp: 1},
75451             epsilon = 1e-4,
75452             node, loc, score, motions, i, j;
75453
75454         if (points.length === 3) {   // move only one vertex for right triangle
75455             for (i = 0; i < 1000; i++) {
75456                 motions = points.map(calcMotion);
75457                 points[corner.i] = addPoints(points[corner.i], motions[corner.i]);
75458                 score = corner.dotp;
75459                 if (score < epsilon) {
75460                     break;
75461                 }
75462             }
75463
75464             node = graph.entity(nodes[corner.i].id);
75465             loc = projection.invert(points[corner.i]);
75466             graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
75467
75468         } else {
75469             var best,
75470                 originalPoints = lodash.clone(points);
75471             score = Infinity;
75472
75473             for (i = 0; i < 1000; i++) {
75474                 motions = points.map(calcMotion);
75475                 for (j = 0; j < motions.length; j++) {
75476                     points[j] = addPoints(points[j],motions[j]);
75477                 }
75478                 var newScore = squareness(points);
75479                 if (newScore < score) {
75480                     best = lodash.clone(points);
75481                     score = newScore;
75482                 }
75483                 if (score < epsilon) {
75484                     break;
75485                 }
75486             }
75487
75488             points = best;
75489
75490             for (i = 0; i < points.length; i++) {
75491                 // only move the points that actually moved
75492                 if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
75493                     loc = projection.invert(points[i]);
75494                     node = graph.entity(nodes[i].id);
75495                     graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
75496                 }
75497             }
75498
75499             // remove empty nodes on straight sections
75500             for (i = 0; t === 1 && i < points.length; i++) {
75501                 node = graph.entity(nodes[i].id);
75502
75503                 if (graph.parentWays(node).length > 1 ||
75504                     graph.parentRelations(node).length ||
75505                     node.hasInterestingTags()) {
75506                     continue;
75507                 }
75508
75509                 var dotp = normalizedDotProduct(i, points);
75510                 if (dotp < -1 + epsilon) {
75511                     graph = actionDeleteNode(node.id)(graph);
75512                 }
75513             }
75514         }
75515
75516         return graph;
75517
75518
75519         function calcMotion(b, i, array) {
75520             var a = array[(i - 1 + array.length) % array.length],
75521                 c = array[(i + 1) % array.length],
75522                 p = subtractPoints(a, b),
75523                 q = subtractPoints(c, b),
75524                 scale, dotp;
75525
75526             scale = 2 * Math.min(geoEuclideanDistance(p, [0, 0]), geoEuclideanDistance(q, [0, 0]));
75527             p = normalizePoint(p, 1.0);
75528             q = normalizePoint(q, 1.0);
75529
75530             dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]);
75531
75532             // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
75533             if (array.length > 3) {
75534                 if (dotp < -0.707106781186547) {
75535                     dotp += 1.0;
75536                 }
75537             } else if (dotp && Math.abs(dotp) < corner.dotp) {
75538                 corner.i = i;
75539                 corner.dotp = Math.abs(dotp);
75540             }
75541
75542             return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
75543         }
75544     };
75545
75546
75547     function squareness(points) {
75548         return points.reduce(function(sum, val, i, array) {
75549             var dotp = normalizedDotProduct(i, array);
75550
75551             dotp = filterDotProduct(dotp);
75552             return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
75553         }, 0);
75554     }
75555
75556
75557     function normalizedDotProduct(i, points) {
75558         var a = points[(i - 1 + points.length) % points.length],
75559             b = points[i],
75560             c = points[(i + 1) % points.length],
75561             p = subtractPoints(a, b),
75562             q = subtractPoints(c, b);
75563
75564         p = normalizePoint(p, 1.0);
75565         q = normalizePoint(q, 1.0);
75566
75567         return p[0] * q[0] + p[1] * q[1];
75568     }
75569
75570
75571     function subtractPoints(a, b) {
75572         return [a[0] - b[0], a[1] - b[1]];
75573     }
75574
75575
75576     function addPoints(a, b) {
75577         return [a[0] + b[0], a[1] + b[1]];
75578     }
75579
75580
75581     function normalizePoint(point, scale) {
75582         var vector = [0, 0];
75583         var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
75584         if (length !== 0) {
75585             vector[0] = point[0] / length;
75586             vector[1] = point[1] / length;
75587         }
75588
75589         vector[0] *= scale;
75590         vector[1] *= scale;
75591
75592         return vector;
75593     }
75594
75595
75596     function filterDotProduct(dotp) {
75597         if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) {
75598             return dotp;
75599         }
75600
75601         return 0;
75602     }
75603
75604
75605     action.disabled = function(graph) {
75606         var way = graph.entity(wayId),
75607             nodes = graph.childNodes(way),
75608             points = lodash.uniq(nodes).map(function(n) { return projection(n.loc); });
75609
75610         if (squareness(points)) {
75611             return false;
75612         }
75613
75614         return 'not_squarish';
75615     };
75616
75617
75618     action.transitionable = true;
75619
75620
75621     return action;
75622 }
75623
75624 // Split a way at the given node.
75625 //
75626 // Optionally, split only the given ways, if multiple ways share
75627 // the given node.
75628 //
75629 // This is the inverse of `iD.actionJoin`.
75630 //
75631 // For testing convenience, accepts an ID to assign to the new way.
75632 // Normally, this will be undefined and the way will automatically
75633 // be assigned a new ID.
75634 //
75635 // Reference:
75636 //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
75637 //
75638 function actionSplit(nodeId, newWayIds) {
75639     var wayIds;
75640
75641     // if the way is closed, we need to search for a partner node
75642     // to split the way at.
75643     //
75644     // The following looks for a node that is both far away from
75645     // the initial node in terms of way segment length and nearby
75646     // in terms of beeline-distance. This assures that areas get
75647     // split on the most "natural" points (independent of the number
75648     // of nodes).
75649     // For example: bone-shaped areas get split across their waist
75650     // line, circles across the diameter.
75651     function splitArea(nodes, idxA, graph) {
75652         var lengths = new Array(nodes.length),
75653             length,
75654             i,
75655             best = 0,
75656             idxB;
75657
75658         function wrap(index) {
75659             return utilWrap(index, nodes.length);
75660         }
75661
75662         function dist(nA, nB) {
75663             return geoSphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc);
75664         }
75665
75666         // calculate lengths
75667         length = 0;
75668         for (i = wrap(idxA+1); i !== idxA; i = wrap(i+1)) {
75669             length += dist(nodes[i], nodes[wrap(i-1)]);
75670             lengths[i] = length;
75671         }
75672
75673         length = 0;
75674         for (i = wrap(idxA-1); i !== idxA; i = wrap(i-1)) {
75675             length += dist(nodes[i], nodes[wrap(i+1)]);
75676             if (length < lengths[i])
75677                 lengths[i] = length;
75678         }
75679
75680         // determine best opposite node to split
75681         for (i = 0; i < nodes.length; i++) {
75682             var cost = lengths[i] / dist(nodes[idxA], nodes[i]);
75683             if (cost > best) {
75684                 idxB = i;
75685                 best = cost;
75686             }
75687         }
75688
75689         return idxB;
75690     }
75691
75692
75693     function split(graph, wayA, newWayId) {
75694         var wayB = osmWay({id: newWayId, tags: wayA.tags}),
75695             nodesA,
75696             nodesB,
75697             isArea = wayA.isArea(),
75698             isOuter = osmIsSimpleMultipolygonOuterMember(wayA, graph);
75699
75700         if (wayA.isClosed()) {
75701             var nodes = wayA.nodes.slice(0, -1),
75702                 idxA = lodash.indexOf(nodes, nodeId),
75703                 idxB = splitArea(nodes, idxA, graph);
75704
75705             if (idxB < idxA) {
75706                 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
75707                 nodesB = nodes.slice(idxB, idxA + 1);
75708             } else {
75709                 nodesA = nodes.slice(idxA, idxB + 1);
75710                 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
75711             }
75712         } else {
75713             var idx = lodash.indexOf(wayA.nodes, nodeId, 1);
75714             nodesA = wayA.nodes.slice(0, idx + 1);
75715             nodesB = wayA.nodes.slice(idx);
75716         }
75717
75718         wayA = wayA.update({nodes: nodesA});
75719         wayB = wayB.update({nodes: nodesB});
75720
75721         graph = graph.replace(wayA);
75722         graph = graph.replace(wayB);
75723
75724         graph.parentRelations(wayA).forEach(function(relation) {
75725             if (relation.isRestriction()) {
75726                 var via = relation.memberByRole('via');
75727                 if (via && wayB.contains(via.id)) {
75728                     relation = relation.updateMember({id: wayB.id}, relation.memberById(wayA.id).index);
75729                     graph = graph.replace(relation);
75730                 }
75731             } else {
75732                 if (relation === isOuter) {
75733                     graph = graph.replace(relation.mergeTags(wayA.tags));
75734                     graph = graph.replace(wayA.update({tags: {}}));
75735                     graph = graph.replace(wayB.update({tags: {}}));
75736                 }
75737
75738                 var member = {
75739                     id: wayB.id,
75740                     type: 'way',
75741                     role: relation.memberById(wayA.id).role
75742                 };
75743
75744                 graph = actionAddMember(relation.id, member)(graph);
75745             }
75746         });
75747
75748         if (!isOuter && isArea) {
75749             var multipolygon = osmRelation({
75750                 tags: lodash.extend({}, wayA.tags, {type: 'multipolygon'}),
75751                 members: [
75752                     {id: wayA.id, role: 'outer', type: 'way'},
75753                     {id: wayB.id, role: 'outer', type: 'way'}
75754                 ]});
75755
75756             graph = graph.replace(multipolygon);
75757             graph = graph.replace(wayA.update({tags: {}}));
75758             graph = graph.replace(wayB.update({tags: {}}));
75759         }
75760
75761         return graph;
75762     }
75763
75764
75765     var action = function(graph) {
75766         var candidates = action.ways(graph);
75767         for (var i = 0; i < candidates.length; i++) {
75768             graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
75769         }
75770         return graph;
75771     };
75772
75773
75774     action.ways = function(graph) {
75775         var node = graph.entity(nodeId),
75776             parents = graph.parentWays(node),
75777             hasLines = lodash.some(parents, function(parent) { return parent.geometry(graph) === 'line'; });
75778
75779         return parents.filter(function(parent) {
75780             if (wayIds && wayIds.indexOf(parent.id) === -1)
75781                 return false;
75782
75783             if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
75784                 return false;
75785
75786             if (parent.isClosed()) {
75787                 return true;
75788             }
75789
75790             for (var i = 1; i < parent.nodes.length - 1; i++) {
75791                 if (parent.nodes[i] === nodeId) {
75792                     return true;
75793                 }
75794             }
75795
75796             return false;
75797         });
75798     };
75799
75800
75801     action.disabled = function(graph) {
75802         var candidates = action.ways(graph);
75803         if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
75804             return 'not_eligible';
75805     };
75806
75807
75808     action.limitWays = function(_) {
75809         if (!arguments.length) return wayIds;
75810         wayIds = _;
75811         return action;
75812     };
75813
75814
75815     return action;
75816 }
75817
75818 // Create a restriction relation for `turn`, which must have the following structure:
75819 //
75820 //     {
75821 //         from: { node: <node ID>, way: <way ID> },
75822 //         via:  { node: <node ID> },
75823 //         to:   { node: <node ID>, way: <way ID> },
75824 //         restriction: <'no_right_turn', 'no_left_turn', etc.>
75825 //     }
75826 //
75827 // This specifies a restriction of type `restriction` when traveling from
75828 // `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
75829 // (The action does not check that these entities form a valid intersection.)
75830 //
75831 // If `restriction` is not provided, it is automatically determined by
75832 // osmInferRestriction.
75833 //
75834 // If necessary, the `from` and `to` ways are split. In these cases, `from.node`
75835 // and `to.node` are used to determine which portion of the split ways become
75836 // members of the restriction.
75837 //
75838 // For testing convenience, accepts an ID to assign to the new relation.
75839 // Normally, this will be undefined and the relation will automatically
75840 // be assigned a new ID.
75841 //
75842 function actionRestrictTurn(turn, projection, restrictionId) {
75843
75844     return function(graph) {
75845         var from = graph.entity(turn.from.way),
75846             via  = graph.entity(turn.via.node),
75847             to   = graph.entity(turn.to.way);
75848
75849         function isClosingNode(way, nodeId) {
75850             return nodeId === way.first() && nodeId === way.last();
75851         }
75852
75853         function split(toOrFrom) {
75854             var newID = toOrFrom.newID || osmWay().id;
75855             graph = actionSplit(via.id, [newID])
75856                 .limitWays([toOrFrom.way])(graph);
75857
75858             var a = graph.entity(newID),
75859                 b = graph.entity(toOrFrom.way);
75860
75861             if (a.nodes.indexOf(toOrFrom.node) !== -1) {
75862                 return [a, b];
75863             } else {
75864                 return [b, a];
75865             }
75866         }
75867
75868         if (!from.affix(via.id) || isClosingNode(from, via.id)) {
75869             if (turn.from.node === turn.to.node) {
75870                 // U-turn
75871                 from = to = split(turn.from)[0];
75872             } else if (turn.from.way === turn.to.way) {
75873                 // Straight-on or circular
75874                 var s = split(turn.from);
75875                 from = s[0];
75876                 to   = s[1];
75877             } else {
75878                 // Other
75879                 from = split(turn.from)[0];
75880             }
75881         }
75882
75883         if (!to.affix(via.id) || isClosingNode(to, via.id)) {
75884             to = split(turn.to)[0];
75885         }
75886
75887         return graph.replace(osmRelation({
75888             id: restrictionId,
75889             tags: {
75890                 type: 'restriction',
75891                 restriction: turn.restriction ||
75892                     osmInferRestriction(
75893                         graph,
75894                         turn.from,
75895                         turn.via,
75896                         turn.to,
75897                         projection)
75898             },
75899             members: [
75900                 {id: from.id, type: 'way',  role: 'from'},
75901                 {id: via.id,  type: 'node', role: 'via'},
75902                 {id: to.id,   type: 'way',  role: 'to'}
75903             ]
75904         }));
75905     };
75906 }
75907
75908 function actionRevert(id) {
75909     var action = function(graph) {
75910         var entity = graph.hasEntity(id),
75911             base = graph.base().entities[id];
75912
75913         if (entity && !base) {    // entity will be removed..
75914             if (entity.type === 'node') {
75915                 graph.parentWays(entity)
75916                     .forEach(function(parent) {
75917                         parent = parent.removeNode(id);
75918                         graph = graph.replace(parent);
75919
75920                         if (parent.isDegenerate()) {
75921                             graph = actionDeleteWay(parent.id)(graph);
75922                         }
75923                     });
75924             }
75925
75926             graph.parentRelations(entity)
75927                 .forEach(function(parent) {
75928                     parent = parent.removeMembersWithID(id);
75929                     graph = graph.replace(parent);
75930
75931                     if (parent.isDegenerate()) {
75932                         graph = actionDeleteRelation(parent.id)(graph);
75933                     }
75934                 });
75935         }
75936
75937         return graph.revert(id);
75938     };
75939
75940     return action;
75941 }
75942
75943 function actionRotate(rotateIds, pivot, angle, projection) {
75944
75945     var action = function(graph) {
75946         return graph.update(function(graph) {
75947             utilGetAllNodes(rotateIds, graph).forEach(function(node) {
75948                 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
75949                 graph = graph.replace(node.move(projection.invert(point)));
75950             });
75951         });
75952     };
75953
75954     return action;
75955 }
75956
75957 /*
75958  * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
75959  */
75960 function actionStraighten(wayId, projection) {
75961
75962     function positionAlongWay(n, s, e) {
75963         return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1])) /
75964                 (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
75965     }
75966
75967
75968     var action = function(graph, t) {
75969         if (t === null || !isFinite(t)) t = 1;
75970         t = Math.min(Math.max(+t, 0), 1);
75971
75972         var way = graph.entity(wayId),
75973             nodes = graph.childNodes(way),
75974             points = nodes.map(function(n) { return projection(n.loc); }),
75975             startPoint = points[0],
75976             endPoint = points[points.length-1],
75977             toDelete = [],
75978             i;
75979
75980         for (i = 1; i < points.length-1; i++) {
75981             var node = nodes[i],
75982                 point = points[i];
75983
75984             if (t < 1 || graph.parentWays(node).length > 1 ||
75985                 graph.parentRelations(node).length ||
75986                 node.hasInterestingTags()) {
75987
75988                 var u = positionAlongWay(point, startPoint, endPoint),
75989                     p = [
75990                         startPoint[0] + u * (endPoint[0] - startPoint[0]),
75991                         startPoint[1] + u * (endPoint[1] - startPoint[1])
75992                     ],
75993                     loc2 = projection.invert(p);
75994
75995                 graph = graph.replace(node.move(geoInterp(node.loc, loc2, t)));
75996
75997             } else {
75998                 // safe to delete
75999                 if (toDelete.indexOf(node) === -1) {
76000                     toDelete.push(node);
76001                 }
76002             }
76003         }
76004
76005         for (i = 0; i < toDelete.length; i++) {
76006             graph = actionDeleteNode(toDelete[i].id)(graph);
76007         }
76008
76009         return graph;
76010     };
76011
76012
76013     action.disabled = function(graph) {
76014         // check way isn't too bendy
76015         var way = graph.entity(wayId),
76016             nodes = graph.childNodes(way),
76017             points = nodes.map(function(n) { return projection(n.loc); }),
76018             startPoint = points[0],
76019             endPoint = points[points.length-1],
76020             threshold = 0.2 * geoEuclideanDistance(startPoint, endPoint),
76021             i;
76022
76023         if (threshold === 0) {
76024             return 'too_bendy';
76025         }
76026
76027         for (i = 1; i < points.length-1; i++) {
76028             var point = points[i],
76029                 u = positionAlongWay(point, startPoint, endPoint),
76030                 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
76031                 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
76032                 dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
76033
76034             // to bendy if point is off by 20% of total start/end distance in projected space
76035             if (isNaN(dist) || dist > threshold) {
76036                 return 'too_bendy';
76037             }
76038         }
76039     };
76040
76041
76042     action.transitionable = true;
76043
76044
76045     return action;
76046 }
76047
76048 // Remove the effects of `turn.restriction` on `turn`, which must have the
76049 // following structure:
76050 //
76051 //     {
76052 //         from: { node: <node ID>, way: <way ID> },
76053 //         via:  { node: <node ID> },
76054 //         to:   { node: <node ID>, way: <way ID> },
76055 //         restriction: <relation ID>
76056 //     }
76057 //
76058 // In the simple case, `restriction` is a reference to a `no_*` restriction
76059 // on the turn itself. In this case, it is simply deleted.
76060 //
76061 // The more complex case is where `restriction` references an `only_*`
76062 // restriction on a different turn in the same intersection. In that case,
76063 // that restriction is also deleted, but at the same time restrictions on
76064 // the turns other than the first two are created.
76065 //
76066 function actionUnrestrictTurn(turn) {
76067     return function(graph) {
76068         return actionDeleteRelation(turn.restriction)(graph);
76069     };
76070 }
76071
76072 /* Reflect the given area around its axis of symmetry */
76073 function actionReflect(reflectIds, projection) {
76074     var useLongAxis = true;
76075
76076
76077     // http://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points
76078     // http://gis.stackexchange.com/questions/3739/generalisation-strategies-for-building-outlines/3756#3756
76079     function getSmallestSurroundingRectangle(graph, nodes) {
76080         var points = nodes.map(function(n) { return projection(n.loc); }),
76081             hull = d3polygonHull(points),
76082             centroid = d3polygonCentroid(hull),
76083             minArea = Infinity,
76084             ssrExtent = [],
76085             ssrAngle = 0,
76086             c1 = hull[0];
76087
76088         for (var i = 0; i < hull.length - 1; i++) {
76089             var c2 = hull[i + 1],
76090                 angle = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]),
76091                 poly = geoRotate(hull, -angle, centroid),
76092                 extent$$1 = poly.reduce(function(extent$$1, point) {
76093                         return extent$$1.extend(geoExtent$$1(point));
76094                     }, geoExtent$$1()),
76095                 area$$1 = extent$$1.area();
76096
76097             if (area$$1 < minArea) {
76098                 minArea = area$$1;
76099                 ssrExtent = extent$$1;
76100                 ssrAngle = angle;
76101             }
76102             c1 = c2;
76103         }
76104
76105         return {
76106             poly: geoRotate(ssrExtent.polygon(), ssrAngle, centroid),
76107             angle: ssrAngle
76108         };
76109     }
76110
76111
76112     var action = function(graph, t) {
76113         if (t === null || !isFinite(t)) t = 1;
76114         t = Math.min(Math.max(+t, 0), 1);
76115
76116         var nodes = utilGetAllNodes(reflectIds, graph),
76117             ssr = getSmallestSurroundingRectangle(graph, nodes);
76118
76119         // Choose line pq = axis of symmetry.
76120         // The shape's surrounding rectangle has 2 axes of symmetry.
76121         // Reflect across the longer axis by default.
76122         var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2 ],
76123             q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2 ],
76124             p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2 ],
76125             q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2 ],
76126             p, q;
76127
76128         var isLong = (geoEuclideanDistance(p1, q1) > geoEuclideanDistance(p2, q2));
76129         if ((useLongAxis && isLong) || (!useLongAxis && !isLong)) {
76130             p = p1;
76131             q = q1;
76132         } else {
76133             p = p2;
76134             q = q2;
76135         }
76136
76137         // reflect c across pq
76138         // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
76139         var dx = q[0] - p[0];
76140         var dy = q[1] - p[1];
76141         var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
76142         var b = 2 * dx * dy / (dx * dx + dy * dy);
76143         for (var i = 0; i < nodes.length; i++) {
76144             var node = nodes[i];
76145             var c = projection(node.loc);
76146             var c2 = [
76147                 a * (c[0] - p[0]) + b * (c[1] - p[1]) + p[0],
76148                 b * (c[0] - p[0]) - a * (c[1] - p[1]) + p[1]
76149             ];
76150             var loc2 = projection.invert(c2);
76151             node = node.move(geoInterp(node.loc, loc2, t));
76152             graph = graph.replace(node);
76153         }
76154
76155         return graph;
76156     };
76157
76158
76159     action.useLongAxis = function(_) {
76160         if (!arguments.length) return useLongAxis;
76161         useLongAxis = _;
76162         return action;
76163     };
76164
76165
76166     action.transitionable = true;
76167
76168
76169     return action;
76170 }
76171
76172
76173
76174 var index$17 = Object.freeze({
76175         d3combobox: d3combobox,
76176         d3geoTile: d3geoTile,
76177         d3keybinding: d3keybinding
76178 });
76179
76180 /* export some legacy symbols: */
76181 var Connection = services.osm;
76182 var debug = false;
76183
76184
76185
76186
76187 var iD = Object.freeze({
76188         Connection: Connection,
76189         debug: debug,
76190         d3: index$2,
76191         _: lodash$1,
76192         lib: index$17,
76193         Context: coreContext,
76194         setAreaKeys: setAreaKeys,
76195         Difference: coreDifference,
76196         Graph: coreGraph$$1,
76197         History: coreHistory,
76198         Tree: coreTree,
76199         Entity: osmEntity$$1,
76200         Node: osmNode,
76201         Relation: osmRelation,
76202         Way: osmWay,
76203         BackgroundSource: rendererBackgroundSource,
76204         Background: rendererBackground,
76205         Features: rendererFeatures,
76206         Map: rendererMap,
76207         TileLayer: rendererTileLayer,
76208         Detect: utilDetect,
76209         actionAddEntity: actionAddEntity,
76210         actionAddMember: actionAddMember,
76211         actionAddMidpoint: actionAddMidpoint,
76212         actionAddVertex: actionAddVertex,
76213         actionChangeMember: actionChangeMember,
76214         actionChangePreset: actionChangePreset,
76215         actionChangeTags: actionChangeTags,
76216         actionCircularize: actionCircularize,
76217         actionConnect: actionConnect,
76218         actionCopyEntities: actionCopyEntities,
76219         actionDeleteMember: actionDeleteMember,
76220         actionDeleteMultiple: actionDeleteMultiple,
76221         actionDeleteNode: actionDeleteNode,
76222         actionDeleteRelation: actionDeleteRelation,
76223         actionDeleteWay: actionDeleteWay,
76224         actionDeprecateTags: actionDeprecateTags,
76225         actionDiscardTags: actionDiscardTags,
76226         actionDisconnect: actionDisconnect,
76227         actionJoin: actionJoin,
76228         actionMerge: actionMerge,
76229         actionMergePolygon: actionMergePolygon,
76230         actionMergeRemoteChanges: actionMergeRemoteChanges,
76231         actionMove: actionMove,
76232         actionMoveNode: actionMoveNode,
76233         actionNoop: actionNoop,
76234         actionOrthogonalize: actionOrthogonalize,
76235         actionRestrictTurn: actionRestrictTurn,
76236         actionReverse: actionReverse,
76237         actionRevert: actionRevert,
76238         actionRotate: actionRotate,
76239         actionSplit: actionSplit,
76240         actionStraighten: actionStraighten,
76241         actionUnrestrictTurn: actionUnrestrictTurn,
76242         actionReflect: actionReflect,
76243         behaviorAddWay: behaviorAddWay,
76244         behaviorBreathe: behaviorBreathe,
76245         behaviorCopy: behaviorCopy,
76246         behaviorDrag: behaviorDrag,
76247         behaviorDrawWay: behaviorDrawWay,
76248         behaviorDraw: behaviorDraw,
76249         behaviorEdit: behaviorEdit,
76250         behaviorHash: behaviorHash,
76251         behaviorHover: behaviorHover,
76252         behaviorLasso: behaviorLasso,
76253         behaviorOperation: behaviorOperation,
76254         behaviorPaste: behaviorPaste,
76255         behaviorSelect: behaviorSelect,
76256         behaviorTail: behaviorTail,
76257         coreContext: coreContext,
76258         coreDifference: coreDifference,
76259         coreGraph: coreGraph$$1,
76260         coreHistory: coreHistory,
76261         coreTree: coreTree,
76262         dataFeatureIcons: dataFeatureIcons,
76263         data: data,
76264         dataWikipedia: dataWikipedia,
76265         dataSuggestions: dataSuggestions,
76266         dataAddressFormats: dataAddressFormats,
76267         dataDeprecated: dataDeprecated,
76268         dataDiscarded: dataDiscarded,
76269         dataLocales: dataLocales,
76270         dataPhoneFormats: dataPhoneFormats,
76271         dataImperial: dataImperial,
76272         dataDriveLeft: dataDriveLeft,
76273         dataEn: en,
76274         geoAngle: geoAngle,
76275         geoChooseEdge: geoChooseEdge,
76276         geoCross: geoCross,
76277         geoEdgeEqual: geoEdgeEqual,
76278         geoEuclideanDistance: geoEuclideanDistance,
76279         geoExtent: geoExtent$$1,
76280         geoInterp: geoInterp,
76281         geoRawMercator: geoRawMercator,
76282         geoRoundCoords: geoRoundCoords,
76283         geoRotate: geoRotate,
76284         geoLatToMeters: geoLatToMeters,
76285         geoLineIntersection: geoLineIntersection,
76286         geoLonToMeters: geoLonToMeters,
76287         geoMetersToLat: geoMetersToLat,
76288         geoMetersToLon: geoMetersToLon,
76289         geoMetersToOffset: geoMetersToOffset,
76290         geoOffsetToMeters: geoOffsetToMeters,
76291         geoPathIntersections: geoPathIntersections,
76292         geoPathLength: geoPathLength,
76293         geoPointInPolygon: geoPointInPolygon,
76294         geoPolygonContainsPolygon: geoPolygonContainsPolygon,
76295         geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
76296         geoSphericalDistance: geoSphericalDistance,
76297         modeAddArea: modeAddArea$$1,
76298         modeAddLine: modeAddLine$$1,
76299         modeAddPoint: modeAddPoint$$1,
76300         modeBrowse: modeBrowse,
76301         modeDragNode: modeDragNode$$1,
76302         modeDrawArea: modeDrawArea,
76303         modeDrawLine: modeDrawLine,
76304         modeMove: modeMove$$1,
76305         modeRotate: modeRotate$$1,
76306         modeSave: modeSave$$1,
76307         modeSelect: modeSelect,
76308         operationCircularize: operationCircularize,
76309         operationContinue: operationContinue,
76310         operationDelete: operationDelete,
76311         operationDisconnect: operationDisconnect,
76312         operationMerge: operationMerge,
76313         operationMove: operationMove,
76314         operationOrthogonalize: operationOrthogonalize,
76315         operationReflectShort: operationReflectShort,
76316         operationReflectLong: operationReflectLong,
76317         operationReverse: operationReverse,
76318         operationRotate: operationRotate,
76319         operationSplit: operationSplit,
76320         operationStraighten: operationStraighten,
76321         osmChangeset: osmChangeset,
76322         osmEntity: osmEntity$$1,
76323         osmNode: osmNode,
76324         osmRelation: osmRelation,
76325         osmWay: osmWay,
76326         osmIntersection: osmIntersection,
76327         osmTurn: osmTurn,
76328         osmInferRestriction: osmInferRestriction,
76329         osmLanes: osmLanes,
76330         osmIsSimpleMultipolygonOuterMember: osmIsSimpleMultipolygonOuterMember,
76331         osmSimpleMultipolygonOuterMember: osmSimpleMultipolygonOuterMember,
76332         osmJoinWays: osmJoinWays,
76333         osmOneWayTags: osmOneWayTags,
76334         osmPavedTags: osmPavedTags,
76335         osmIsInterestingTag: osmIsInterestingTag,
76336         presetCategory: presetCategory,
76337         presetCollection: presetCollection,
76338         presetField: presetField,
76339         presetPreset: presetPreset,
76340         presetIndex: presetIndex,
76341         rendererBackgroundSource: rendererBackgroundSource,
76342         rendererBackground: rendererBackground,
76343         rendererFeatures: rendererFeatures,
76344         rendererMap: rendererMap,
76345         rendererTileLayer: rendererTileLayer,
76346         services: services,
76347         svgAreas: svgAreas$$1,
76348         svgDebug: svgDebug,
76349         svgDefs: svgDefs,
76350         svgGpx: svgGpx,
76351         svgIcon: svgIcon,
76352         svgLabels: svgLabels,
76353         svgLayers: svgLayers,
76354         svgLines: svgLines$$1,
76355         svgMapillaryImages: svgMapillaryImages,
76356         svgMapillarySigns: svgMapillarySigns,
76357         svgMidpoints: svgMidpoints$$1,
76358         svgOneWaySegments: svgOneWaySegments,
76359         svgOsm: svgOsm,
76360         svgPath: svgPath,
76361         svgPointTransform: svgPointTransform,
76362         svgPoints: svgPoints$$1,
76363         svgRelationMemberTags: svgRelationMemberTags,
76364         svgTagClasses: svgTagClasses,
76365         svgTurns: svgTurns,
76366         svgVertices: svgVertices$$1,
76367         uiFields: uiFields,
76368         uiFieldDefaultCheck: uiFieldCheck,
76369         uiFieldOnewayCheck: uiFieldCheck,
76370         uiFieldCheck: uiFieldCheck,
76371         uiFieldMultiCombo: uiFieldCombo,
76372         uiFieldNetworkCombo: uiFieldCombo,
76373         uiFieldSemiCombo: uiFieldCombo,
76374         uiFieldTypeCombo: uiFieldCombo,
76375         uiFieldCombo: uiFieldCombo,
76376         uiFieldUrl: uiFieldText,
76377         uiFieldNumber: uiFieldText,
76378         uiFieldTel: uiFieldText,
76379         uiFieldEmail: uiFieldText,
76380         uiFieldText: uiFieldText,
76381         uiFieldAccess: uiFieldAccess,
76382         uiFieldAddress: uiFieldAddress,
76383         uiFieldCycleway: uiFieldCycleway,
76384         uiFieldLanes: uiFieldLanes,
76385         uiFieldLocalized: uiFieldLocalized,
76386         uiFieldMaxspeed: uiFieldMaxspeed,
76387         uiFieldStructureRadio: uiFieldRadio,
76388         uiFieldRadio: uiFieldRadio,
76389         uiFieldRestrictions: uiFieldRestrictions,
76390         uiFieldTextarea: uiFieldTextarea,
76391         uiFieldWikipedia: uiFieldWikipedia,
76392         uiIntro: uiIntro,
76393         uiInit: uiInit,
76394         uiAccount: uiAccount,
76395         uiAttribution: uiAttribution,
76396         uiBackground: uiBackground,
76397         uiCmd: uiCmd,
76398         uiCommit: uiCommit,
76399         uiConfirm: uiConfirm,
76400         uiConflicts: uiConflicts,
76401         uiContributors: uiContributors,
76402         uiCurtain: uiCurtain,
76403         uiDisclosure: uiDisclosure,
76404         uiEditMenu: uiEditMenu,
76405         uiEntityEditor: uiEntityEditor,
76406         uiFeatureInfo: uiFeatureInfo,
76407         uiFeatureList: uiFeatureList,
76408         uiFlash: uiFlash,
76409         uiFullScreen: uiFullScreen,
76410         uiGeolocate: uiGeolocate,
76411         uiHelp: uiHelp,
76412         uiInfo: uiInfo,
76413         uiInspector: uiInspector,
76414         uiLasso: uiLasso,
76415         uiLoading: uiLoading,
76416         uiMapData: uiMapData,
76417         uiMapInMap: uiMapInMap,
76418         uiModal: uiModal,
76419         uiModes: uiModes,
76420         uiNotice: uiNotice,
76421         uiPreset: uiPreset,
76422         uiPresetIcon: uiPresetIcon,
76423         uiPresetList: uiPresetList,
76424         uiRadialMenu: uiRadialMenu,
76425         uiRawMemberEditor: uiRawMemberEditor,
76426         uiRawMembershipEditor: uiRawMembershipEditor,
76427         uiRawTagEditor: uiRawTagEditor,
76428         uiRestore: uiRestore,
76429         uiSave: uiSave,
76430         uiScale: uiScale,
76431         uiSelectionList: uiSelectionList,
76432         uiSidebar: uiSidebar,
76433         uiSourceSwitch: uiSourceSwitch,
76434         uiSpinner: uiSpinner,
76435         uiSplash: uiSplash,
76436         uiStatus: uiStatus,
76437         uiSuccess: uiSuccess,
76438         uiTagReference: uiTagReference,
76439         uiToggle: uiToggle,
76440         uiTooltipHtml: uiTooltipHtml,
76441         uiUndoRedo: uiUndoRedo,
76442         uiVersion: uiVersion,
76443         uiViewOnOSM: uiViewOnOSM,
76444         uiZoom: uiZoom,
76445         utilAsyncMap: utilAsyncMap,
76446         utilDisplayName: utilDisplayName,
76447         utilDisplayNameForPath: utilDisplayNameForPath,
76448         utilDisplayType: utilDisplayType,
76449         utilEditDistance: utilEditDistance,
76450         utilEntitySelector: utilEntitySelector,
76451         utilEntityOrMemberSelector: utilEntityOrMemberSelector,
76452         utilFastMouse: utilFastMouse,
76453         utilFunctor: utilFunctor,
76454         utilGetAllNodes: utilGetAllNodes,
76455         utilGetPrototypeOf: utilGetPrototypeOf,
76456         utilGetSetValue: utilGetSetValue,
76457         utilNoAuto: utilNoAuto,
76458         utilPrefixCSSProperty: utilPrefixCSSProperty,
76459         utilPrefixDOMProperty: utilPrefixDOMProperty,
76460         utilQsString: utilQsString,
76461         utilRebind: utilRebind,
76462         utilSetTransform: utilSetTransform,
76463         utilSessionMutex: utilSessionMutex,
76464         utilStringQs: utilStringQs,
76465         utilSuggestNames: utilSuggestNames,
76466         utilTagText: utilTagText,
76467         utilTriggerEvent: utilTriggerEvent,
76468         utilWrap: utilWrap,
76469         d3combobox: d3combobox,
76470         d3geoTile: d3geoTile,
76471         d3keybinding: d3keybinding,
76472         validationDeprecatedTag: validationDeprecatedTag,
76473         validationDisconnectedHighway: validationDisconnectedHighway,
76474         validationManyDeletions: validationManyDeletions,
76475         validationMissingTag: validationMissingTag,
76476         validationOldMultipolygon: validationOldMultipolygon,
76477         validationTagSuggestsArea: validationTagSuggestsArea
76478 });
76479
76480 window.iD = iD;
76481
76482 }());
76483 //# sourceMappingURL=iD.js.map