]> git.openstreetmap.org Git - rails.git/blob - vendor/assets/iD/iD.js
Merge remote-tracking branch 'upstream/pull/1575'
[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 dataShortcuts = [{"tab":"browsing","text":"shortcuts.browsing.title","columns":[{"rows":[{"section":"navigation","text":"shortcuts.browsing.navigation.title"},{"shortcuts":["↓","↑","←","→"],"text":"shortcuts.browsing.navigation.pan","separator":","},{"modifiers":["⌘"],"shortcuts":["↓","↑","←","→"],"text":"shortcuts.browsing.navigation.pan_more","separator":","},{"shortcuts":["+","-"],"text":"shortcuts.browsing.navigation.zoom","separator":","},{"modifiers":["⌘"],"shortcuts":["+","-"],"text":"shortcuts.browsing.navigation.zoom_more","separator":","},{"section":"help","text":"shortcuts.browsing.help.title"},{"shortcuts":["H"],"text":"shortcuts.browsing.help.help"},{"shortcuts":["?"],"text":"shortcuts.browsing.help.keyboard"},{"section":"display_options","text":"shortcuts.browsing.display_options.title"},{"shortcuts":["B"],"text":"shortcuts.browsing.display_options.background"},{"modifiers":["⌘"],"shortcuts":["B"],"text":"shortcuts.browsing.display_options.background_switch"},{"shortcuts":["F"],"text":"shortcuts.browsing.display_options.map_data"},{"modifiers":["⌃","⌘"],"shortcuts":["F","F11"],"text":"shortcuts.browsing.display_options.fullscreen"},{"shortcuts":["W"],"text":"shortcuts.browsing.display_options.wireframe"},{"shortcuts":["/"],"text":"shortcuts.browsing.display_options.minimap"}]},{"rows":[{"section":"selecting","text":"shortcuts.browsing.selecting.title"},{"shortcuts":["Left-click"],"text":"shortcuts.browsing.selecting.select_one"},{"modifiers":["⇧"],"shortcuts":["Left-click"],"text":"shortcuts.browsing.selecting.select_multi"},{"modifiers":["⇧"],"shortcuts":["Left-click"],"gesture":"shortcuts.gesture.drag","text":"shortcuts.browsing.selecting.lasso"},{"shortcuts":[],"text":""},{"section":"with_selected","text":"shortcuts.browsing.with_selected.title"},{"shortcuts":["Right-click","shortcuts.key.space"],"text":"shortcuts.browsing.with_selected.edit_menu"},{"modifiers":["⌘"],"shortcuts":["I"],"text":"shortcuts.browsing.with_selected.infobox"},{"section":"vertex_selected","text":"shortcuts.browsing.vertex_selected.title"},{"shortcuts":["[","↖"],"text":"shortcuts.browsing.vertex_selected.previous"},{"shortcuts":["]","↘"],"text":"shortcuts.browsing.vertex_selected.next"},{"shortcuts":["{","⇞"],"text":"shortcuts.browsing.vertex_selected.first"},{"shortcuts":["}","⇟"],"text":"shortcuts.browsing.vertex_selected.last"},{"shortcuts":["\\","shortcuts.key.pause"],"text":"shortcuts.browsing.vertex_selected.change_parent"}]}]},{"tab":"editing","text":"shortcuts.editing.title","columns":[{"rows":[{"section":"drawing","text":"shortcuts.editing.drawing.title"},{"shortcuts":["1"],"text":"shortcuts.editing.drawing.add_point"},{"shortcuts":["2"],"text":"shortcuts.editing.drawing.add_line"},{"shortcuts":["3"],"text":"shortcuts.editing.drawing.add_area"},{"shortcuts":["shortcuts.key.space"],"text":"shortcuts.editing.drawing.place_point"},{"shortcuts":["⌥"],"text":"shortcuts.editing.drawing.disable_snap"},{"shortcuts":["↵","⎋"],"text":"shortcuts.editing.drawing.stop_line"},{"section":"commands","text":"shortcuts.editing.commands.title"},{"modifiers":["⌘"],"shortcuts":["C"],"text":"shortcuts.editing.commands.copy"},{"modifiers":["⌘"],"shortcuts":["V"],"text":"shortcuts.editing.commands.paste"},{"modifiers":["⌘"],"shortcuts":["Z"],"text":"shortcuts.editing.commands.undo"},{"modifiers":["⌘","⇧"],"shortcuts":["Z"],"text":"shortcuts.editing.commands.redo"},{"modifiers":["⌘"],"shortcuts":["S"],"text":"shortcuts.editing.commands.save"}]},{"rows":[{"section":"operations","text":"shortcuts.editing.operations.title"},{"shortcuts":["operations.continue.key"],"text":"shortcuts.editing.operations.continue_line"},{"shortcuts":["operations.merge.key"],"text":"shortcuts.editing.operations.merge"},{"shortcuts":["operations.disconnect.key"],"text":"shortcuts.editing.operations.disconnect"},{"shortcuts":["operations.split.key"],"text":"shortcuts.editing.operations.split"},{"shortcuts":["operations.reverse.key"],"text":"shortcuts.editing.operations.reverse"},{"shortcuts":["operations.move.key"],"text":"shortcuts.editing.operations.move"},{"shortcuts":["operations.rotate.key"],"text":"shortcuts.editing.operations.rotate"},{"shortcuts":["operations.orthogonalize.key"],"text":"shortcuts.editing.operations.orthogonalize"},{"shortcuts":["operations.circularize.key"],"text":"shortcuts.editing.operations.circularize"},{"shortcuts":["operations.reflect.key.long"],"text":"shortcuts.editing.operations.reflect_long"},{"shortcuts":["operations.reflect.key.short"],"text":"shortcuts.editing.operations.reflect_short"},{"modifiers":["⌘"],"shortcuts":["⌫"],"text":"shortcuts.editing.operations.delete"}]}]}];
18610
18611 var type = "FeatureCollection";
18612 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]]]}}];
18613 var dataImperial = {
18614         type: type,
18615         features: features
18616 };
18617
18618 var type$1 = "FeatureCollection";
18619 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]]]}}];
18620 var dataDriveLeft = {
18621         type: type$1,
18622         features: features$1
18623 };
18624
18625 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\nYou can view a list of keyboard shortcuts by pressing the `?` key.\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!"}},"shortcuts":{"title":"Keyboard shortcuts","tooltip":"Show the keyboard shortcuts screen.","key":{"alt":"Alt","backspace":"Backspace","cmd":"Cmd","ctrl":"Ctrl","delete":"Delete","del":"Del","end":"End","enter":"Enter","esc":"Esc","home":"Home","option":"Option","pause":"Pause","pgdn":"PgDn","pgup":"PgUp","return":"Return","shift":"Shift","space":"Space"},"gesture":{"drag":"drag"},"or":"-or-","browsing":{"title":"Browsing","navigation":{"title":"Navigation","pan":"Pan map","pan_more":"Pan map by one screenful","zoom":"Zoom in / Zoom out","zoom_more":"Zoom in / Zoom out by a lot"},"help":{"title":"Help","help":"Show help/documentation","keyboard":"Show keyboard shortcuts"},"display_options":{"title":"Display options","background":"Show background options","background_switch":"Switch back to last background","map_data":"Show map data options","fullscreen":"Enter full screen mode","wireframe":"Toggle wireframe mode","minimap":"Toggle minimap"},"selecting":{"title":"Selecting features","select_one":"Select a single feature","select_multi":"Select multiple features","lasso":"Draw a selection lasso around features"},"with_selected":{"title":"With feature selected","infobox":"Toggle info / measurement box","edit_menu":"Toggle edit menu"},"vertex_selected":{"title":"With node selected","previous":"Jump to previous node","next":"Jump to next node","first":"Jump to first node","last":"Jump to last node","change_parent":"Switch parent way"}},"editing":{"title":"Editing","drawing":{"title":"Drawing","add_point":"'Add point' mode","add_line":"'Add line' mode","add_area":"'Add area' mode","place_point":"Place a point","disable_snap":"Hold to disable point snapping","stop_line":"Finish drawing a line or area"},"operations":{"title":"Operations","continue_line":"Continue a line at the selected node","merge":"Combine (merge) selected features","disconnect":"Disconnect features at the selected node","split":"Split a line into two at the selected node","reverse":"Reverse a line","move":"Move selected features","rotate":"Rotate selected features","orthogonalize":"Straighten line / Square area corners","circularize":"Circularize a closed line or area","reflect_long":"Reflect features across the longer axis","reflect_short":"Reflect features across the shorter axis","delete":"Delete selected features"},"commands":{"title":"Commands","copy":"Copy selected features","paste":"Paste copied features","undo":"Undo last action","redo":"Redo last action","save":"Save changes"}}},"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"},"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"},"maxweight":{"label":"Max Weight"},"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":"alcohol,beer,beverage,bier,booze,cider"},"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/distillery":{"name":"Distillery","terms":"alcohol,beverage,bourbon,booze,brandy,gin,hooch,liquor,mezcal,moonshine,rum,scotch,spirits,still,tequila,vodka,whiskey,whisky"},"craft/dressmaker":{"name":"Dressmaker","terms":"seamstress"},"craft/electrician":{"name":"Electrician","terms":"power,wire"},"craft/electronics_repair":{"name":"Electronics Repair Shop","terms":""},"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/elevator":{"name":"Elevator","terms":"lift"},"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":"football"},"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/appliance":{"name":"Appliance Store","terms":"air conditioner,appliance,dishwasher,dryer,freezer,fridge,grill,kitchen,oven,refrigerator,stove,washer,washing machine"},"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,blueray,camera,computer,dvd,home theater,radio,speaker,tv,video"},"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":""}}}};
18626
18627 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 © 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 © 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":"https://{switch:a,b,c}.tiles.mapbox.com/v4/digitalglobe.316c9a2e/{zoom}/{x}/{y}.png?access_token=pk.eyJ1IjoiZGlnaXRhbGdsb2JlIiwiYSI6ImNqM293YnJ5MTAwajIzMnF0bmV4dnV1MW4ifQ.psvzzOez33BOH8xmRiJZWg","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":"https://{switch:a,b,c}.tiles.mapbox.com/v4/digitalglobe.0a8e44ba/{zoom}/{x}/{y}.png?access_token=pk.eyJ1IjoiZGlnaXRhbGdsb2JlIiwiYSI6ImNqM293Y3Y5ZjAwaWgycW55ZXFncHk0a3QifQ.6Kprj_J4oDmXqV97RricwA","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":"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":[[[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 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,19],"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,19],"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":"LINZ_NZ_Aerial_Imagery","name":"LINZ NZ Aerial Imagery","type":"tms","template":"https://tiles-a.data-cdn.linz.govt.nz/services;key=3197c6d0e5cb494a95d58dc2de3216c2/tiles/v4/set=2/EPSG:3857/{zoom}/{x}/{y}.png","scaleExtent":[0,21],"polygon":[[[167.2503662109375,-47.21956811231548],[167.244873046875,-47.28016067076474],[167.5030517578125,-47.37975438400816],[168.2501220703125,-47.15610477504402],[168.7445068359375,-46.79629898997744],[169.3267822265625,-46.75491661928188],[169.78271484375,-46.604167162931844],[170.4254150390625,-46.11132565729794],[170.804443359375,-45.95114968669139],[170.9527587890625,-45.440862671781744],[171.309814453125,-44.91035917458493],[171.40869140625,-44.39061697878681],[172.562255859375,-43.92954993561458],[172.90283203125,-43.96909818325171],[173.1610107421875,-43.90976594390799],[173.2598876953125,-43.69567969789881],[172.9742431640625,-43.53660274231031],[172.760009765625,-43.37710501700071],[173.1500244140625,-43.17714134663171],[173.704833984375,-42.63395872267314],[174.36401367187497,-41.78360106648077],[174.320068359375,-41.409775832009544],[174.84741210937497,-41.52914198872309],[175.0726318359375,-41.70572851523751],[175.506591796875,-41.672911819602085],[176.2261962890625,-41.10832999732831],[176.8304443359375,-40.42604212826493],[177.17102050781247,-39.67337039176559],[177.0391845703125,-39.39375459224347],[177.4456787109375,-39.18117526158747],[177.60498046875,-39.3300485529424],[177.978515625,-39.368279149160124],[178.3355712890625,-38.65977773071253],[178.7091064453125,-37.74465712069938],[178.626708984375,-37.54457732085582],[178.3135986328125,-37.43125050179357],[177.6214599609375,-37.37888785004525],[177.0391845703125,-37.39634613318924],[176.561279296875,-37.37015718405751],[176.3360595703125,-37.05956083025124],[176.0064697265625,-36.29741818650809],[175.6768798828125,-36.05354012833974],[174.671630859375,-35.1782983520012],[173.1939697265625,-34.28445325435288],[172.6776123046875,-34.234512362369856],[172.386474609375,-34.40237742424137],[172.4798583984375,-34.71903991764788],[172.9852294921875,-35.32184842037683],[173.56201171875,-36.142310873529986],[174.30908203125,-37.077093191754415],[174.5562744140625,-38.052416771864834],[174.4793701171875,-38.655488159952995],[174.3255615234375,-38.865374851611634],[173.7982177734375,-38.95940879245421],[173.60595703125,-39.232253141714885],[173.6993408203125,-39.56335316582929],[174.5892333984375,-39.95606977009003],[174.9847412109375,-40.216635475391215],[174.9847412109375,-40.49291502689579],[174.7210693359375,-40.805493843894155],[174.1497802734375,-40.65147128144056],[173.2818603515625,-40.43440488077009],[172.5897216796875,-40.350730565917885],[172.0843505859375,-40.534676780615406],[171.7657470703125,-40.826280356677124],[171.57348632812497,-41.3974150664646],[171.2823486328125,-41.652392884268124],[170.8758544921875,-42.53284428171312],[170.35400390625,-42.87193842444846],[168.277587890625,-43.92954993561458],[167.6239013671875,-44.47691085722324],[166.55273437499997,-45.38687734827038],[166.27258300781247,-45.916765867649],[166.4813232421875,-46.22545288226937],[167.6788330078125,-46.471916320870406],[167.2503662109375,-47.21956811231548]]],"terms_url":"http://www.linz.govt.nz/data/licensing-and-using-data/attributing-elevation-or-aerial-imagery-data","terms_text":"Sourced from LINZ CC-BY 3.0","best":true},{"id":"LINZ_NZ_Topo50_Gridless_Maps","name":"LINZ NZ Topo50 Gridless Maps","type":"tms","template":"https://tiles-a.data-cdn.linz.govt.nz/services;key=3197c6d0e5cb494a95d58dc2de3216c2/tiles/v4/layer=2343/EPSG:3857/{zoom}/{x}/{y}.png","scaleExtent":[0,21],"polygon":[[[167.2503662109375,-47.21956811231548],[167.244873046875,-47.28016067076474],[167.5030517578125,-47.37975438400816],[168.2501220703125,-47.15610477504402],[168.7445068359375,-46.79629898997744],[169.3267822265625,-46.75491661928188],[169.78271484375,-46.604167162931844],[170.4254150390625,-46.11132565729794],[170.804443359375,-45.95114968669139],[170.9527587890625,-45.440862671781744],[171.309814453125,-44.91035917458493],[171.40869140625,-44.39061697878681],[172.562255859375,-43.92954993561458],[172.90283203125,-43.96909818325171],[173.1610107421875,-43.90976594390799],[173.2598876953125,-43.69567969789881],[172.9742431640625,-43.53660274231031],[172.760009765625,-43.37710501700071],[173.1500244140625,-43.17714134663171],[173.704833984375,-42.63395872267314],[174.36401367187497,-41.78360106648077],[174.320068359375,-41.409775832009544],[174.84741210937497,-41.52914198872309],[175.0726318359375,-41.70572851523751],[175.506591796875,-41.672911819602085],[176.2261962890625,-41.10832999732831],[176.8304443359375,-40.42604212826493],[177.17102050781247,-39.67337039176559],[177.0391845703125,-39.39375459224347],[177.4456787109375,-39.18117526158747],[177.60498046875,-39.3300485529424],[177.978515625,-39.368279149160124],[178.3355712890625,-38.65977773071253],[178.7091064453125,-37.74465712069938],[178.626708984375,-37.54457732085582],[178.3135986328125,-37.43125050179357],[177.6214599609375,-37.37888785004525],[177.0391845703125,-37.39634613318924],[176.561279296875,-37.37015718405751],[176.3360595703125,-37.05956083025124],[176.0064697265625,-36.29741818650809],[175.6768798828125,-36.05354012833974],[174.671630859375,-35.1782983520012],[173.1939697265625,-34.28445325435288],[172.6776123046875,-34.234512362369856],[172.386474609375,-34.40237742424137],[172.4798583984375,-34.71903991764788],[172.9852294921875,-35.32184842037683],[173.56201171875,-36.142310873529986],[174.30908203125,-37.077093191754415],[174.5562744140625,-38.052416771864834],[174.4793701171875,-38.655488159952995],[174.3255615234375,-38.865374851611634],[173.7982177734375,-38.95940879245421],[173.60595703125,-39.232253141714885],[173.6993408203125,-39.56335316582929],[174.5892333984375,-39.95606977009003],[174.9847412109375,-40.216635475391215],[174.9847412109375,-40.49291502689579],[174.7210693359375,-40.805493843894155],[174.1497802734375,-40.65147128144056],[173.2818603515625,-40.43440488077009],[172.5897216796875,-40.350730565917885],[172.0843505859375,-40.534676780615406],[171.7657470703125,-40.826280356677124],[171.57348632812497,-41.3974150664646],[171.2823486328125,-41.652392884268124],[170.8758544921875,-42.53284428171312],[170.35400390625,-42.87193842444846],[168.277587890625,-43.92954993561458],[167.6239013671875,-44.47691085722324],[166.55273437499997,-45.38687734827038],[166.27258300781247,-45.916765867649],[166.4813232421875,-46.22545288226937],[167.6788330078125,-46.471916320870406],[167.2503662109375,-47.21956811231548]]],"terms_url":"https://data.linz.govt.nz/layer/2343-nz-mainland-topo50-gridless-maps/","terms_text":"Sourced from the LINZ Data Service and licensed by LINZ for re-use under the Creative Commons Attribution 3.0 New Zealand licence."},{"id":"ORT10LT","name":"Lithuania - NŽT ORT10LT","type":"tms","template":"http://ort10lt.openmap.lt/g16/{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 2017"},{"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 2017","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 2017"},{"id":"Mapbox","name":"Mapbox Satellite","type":"tms","template":"https://{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://wmts.nlsc.gov.tw/wmts/EMAP5_OPENDATA/default/EPSG:3857/{zoom}/{y}/{x}","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":"© National Land Surveying and Mapping Center, Taiwan OGDL 1.0"},{"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://www.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":"https://www.openstreetmap.org/","terms_text":"© OpenStreetMap contributors"},{"id":"osm-gps","name":"OpenStreetMap GPS traces","type":"tms","template":"https://{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":"https://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='https://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_url":"http://www.nationaalgeoregister.nl/geonetwork/srv/dut/catalog.search#/search?facet.q=license%2FCC-BY&isChild=%27false%27&resultType=details&any_OR_title_OR_keyword=luchtfoto&fast=index&_content_type=json&from=1&to=20&sortBy=relevance","terms_text":"Kadaster / Beeldmateriaal.nl, 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":"Geodatastyrelsen_Denmark","name":"SDFE aerial imagery","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":"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","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":"https://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":"https://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","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"}];
18628
18629 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":"poi-storage-tank","fields":["operator","address","building_area","opening_hours","product"],"geometry":["point","area"],"terms":["alcohol","beer","beverage","bier","booze","cider"],"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/distillery":{"icon":"poi-storage-tank","fields":["operator","address","building_area","opening_hours","product"],"geometry":["point","area"],"terms":["alcohol","beverage","bourbon","booze","brandy","gin","hooch","liquor","mezcal","moonshine","rum","scotch","spirits","still","tequila","vodka","whiskey","whisky"],"tags":{"craft":"distillery"},"name":"Distillery"},"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/electronics_repair":{"icon":"poi-tool","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"tags":{"craft":"electronics_repair"},"name":"Electronics Repair Shop"},"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/elevator":{"icon":"poi-elevator","fields":["access_simple","opening_hours","maxweight","ref"],"geometry":["vertex"],"tags":{"highway":"elevator"},"terms":["lift"],"name":"Elevator"},"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":["football"],"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/appliance":{"icon":"shop","fields":["operator","address","building_area","opening_hours"],"geometry":["point","area"],"terms":["air conditioner","appliance","dishwasher","dryer","freezer","fridge","grill","kitchen","oven","refrigerator","stove","washer","washing machine"],"tags":{"shop":"appliance"},"name":"Appliance Store"},"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","blueray","camera","computer","dvd","home theater","radio","speaker","tv","video"],"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}};
18630
18631 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"]};
18632
18633 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"]}};
18634
18635 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"},"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},"maxweight":{"key":"maxweight","type":"combo","label":"Max Weight","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"}};
18636
18637 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"];
18638 var all$1 = {
18639         all: all
18640 };
18641
18642 var all$2 = Object.freeze({
18643         all: all,
18644         default: all$1
18645 });
18646
18647 var Airport = ["airfield","airport","heliport","rocket"];
18648 var Dining = ["bakery","bar","beer","cafe","fast-food","ice-cream","restaurant"];
18649 var Education = ["college","school"];
18650 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"];
18651 var Health = ["dentist","doctor","hospital","pharmacy"];
18652 var Outdoors = ["campsite","cemetery","dog-park","garden","golf","park","picnic-site","playground","zoo"];
18653 var Transit = ["bus","ferry"];
18654 var streets = {
18655         Airport: Airport,
18656         Dining: Dining,
18657         Education: Education,
18658         General: General,
18659         Health: Health,
18660         Outdoors: Outdoors,
18661         Transit: Transit,
18662         "Mountain peak": ["mountain","volcano"],
18663         "Rail station": ["entrance","rail","rail-light","rail-metro"]
18664 };
18665
18666 var streets$1 = Object.freeze({
18667         Airport: Airport,
18668         Dining: Dining,
18669         Education: Education,
18670         General: General,
18671         Health: Health,
18672         Outdoors: Outdoors,
18673         Transit: Transit,
18674         default: streets
18675 });
18676
18677 var require$$0 = ( all$2 && all$1 ) || all$2;
18678
18679 var require$$1 = ( streets$1 && streets ) || streets$1;
18680
18681 var index$1 = {
18682   layouts: {
18683     all: require$$0,
18684     streets: require$$1
18685   }
18686 };
18687
18688 var dataFeatureIcons = index$1.layouts.all.all;
18689
18690 var data = {
18691     imagery: dataImagery,
18692     presets: {
18693         presets: presets,
18694         defaults: defaults,
18695         categories: categories,
18696         fields: fields
18697     }
18698 };
18699
18700 function osmEntity$$1(attrs) {
18701     // For prototypal inheritance.
18702     if (this instanceof osmEntity$$1) return;
18703
18704     // Create the appropriate subtype.
18705     if (attrs && attrs.type) {
18706         return osmEntity$$1[attrs.type].apply(this, arguments);
18707     } else if (attrs && attrs.id) {
18708         return osmEntity$$1[osmEntity$$1.id.type(attrs.id)].apply(this, arguments);
18709     }
18710
18711     // Initialize a generic Entity (used only in tests).
18712     return (new osmEntity$$1()).initialize(arguments);
18713 }
18714
18715
18716 osmEntity$$1.id = function(type) {
18717     return osmEntity$$1.id.fromOSM(type, osmEntity$$1.id.next[type]--);
18718 };
18719
18720
18721 osmEntity$$1.id.next = {
18722     changeset: -1, node: -1, way: -1, relation: -1
18723 };
18724
18725
18726 osmEntity$$1.id.fromOSM = function(type, id) {
18727     return type[0] + id;
18728 };
18729
18730
18731 osmEntity$$1.id.toOSM = function(id) {
18732     return id.slice(1);
18733 };
18734
18735
18736 osmEntity$$1.id.type = function(id) {
18737     return { 'c': 'changeset', 'n': 'node', 'w': 'way', 'r': 'relation' }[id[0]];
18738 };
18739
18740
18741 // A function suitable for use as the second argument to d3.selection#data().
18742 osmEntity$$1.key = function(entity) {
18743     return entity.id + 'v' + (entity.v || 0);
18744 };
18745
18746
18747 osmEntity$$1.prototype = {
18748
18749     tags: {},
18750
18751
18752     initialize: function(sources) {
18753         for (var i = 0; i < sources.length; ++i) {
18754             var source = sources[i];
18755             for (var prop in source) {
18756                 if (Object.prototype.hasOwnProperty.call(source, prop)) {
18757                     if (source[prop] === undefined) {
18758                         delete this[prop];
18759                     } else {
18760                         this[prop] = source[prop];
18761                     }
18762                 }
18763             }
18764         }
18765
18766         if (!this.id && this.type) {
18767             this.id = osmEntity$$1.id(this.type);
18768         }
18769         if (!this.hasOwnProperty('visible')) {
18770             this.visible = true;
18771         }
18772
18773         if (debug) {
18774             Object.freeze(this);
18775             Object.freeze(this.tags);
18776
18777             if (this.loc) Object.freeze(this.loc);
18778             if (this.nodes) Object.freeze(this.nodes);
18779             if (this.members) Object.freeze(this.members);
18780         }
18781
18782         return this;
18783     },
18784
18785
18786     copy: function(resolver, copies) {
18787         if (copies[this.id])
18788             return copies[this.id];
18789
18790         var copy = osmEntity$$1(this, {id: undefined, user: undefined, version: undefined});
18791         copies[this.id] = copy;
18792
18793         return copy;
18794     },
18795
18796
18797     osmId: function() {
18798         return osmEntity$$1.id.toOSM(this.id);
18799     },
18800
18801
18802     isNew: function() {
18803         return this.osmId() < 0;
18804     },
18805
18806
18807     update: function(attrs) {
18808         return osmEntity$$1(this, attrs, {v: 1 + (this.v || 0)});
18809     },
18810
18811
18812     mergeTags: function(tags) {
18813         var merged = lodash.clone(this.tags), changed = false;
18814         for (var k in tags) {
18815             var t1 = merged[k],
18816                 t2 = tags[k];
18817             if (!t1) {
18818                 changed = true;
18819                 merged[k] = t2;
18820             } else if (t1 !== t2) {
18821                 changed = true;
18822                 merged[k] = lodash.union(t1.split(/;\s*/), t2.split(/;\s*/)).join(';');
18823             }
18824         }
18825         return changed ? this.update({tags: merged}) : this;
18826     },
18827
18828
18829     intersects: function(extent, resolver) {
18830         return this.extent(resolver).intersects(extent);
18831     },
18832
18833
18834     isUsed: function(resolver) {
18835         return lodash.without(Object.keys(this.tags), 'area').length > 0 ||
18836             resolver.parentRelations(this).length > 0;
18837     },
18838
18839
18840     hasInterestingTags: function() {
18841         return lodash.keys(this.tags).some(osmIsInterestingTag);
18842     },
18843
18844
18845     isHighwayIntersection: function() {
18846         return false;
18847     },
18848
18849     isDegenerate: function() {
18850         return true;
18851     },
18852
18853     deprecatedTags: function() {
18854         var tags = lodash.toPairs(this.tags);
18855         var deprecated = {};
18856
18857         dataDeprecated.forEach(function(d) {
18858             var match = lodash.toPairs(d.old)[0];
18859             tags.forEach(function(t) {
18860                 if (t[0] === match[0] &&
18861                     (t[1] === match[1] || match[1] === '*')) {
18862                     deprecated[t[0]] = t[1];
18863                 }
18864             });
18865         });
18866
18867         return deprecated;
18868     }
18869 };
18870
18871 function geoRoundCoords(c) {
18872     return [Math.floor(c[0]), Math.floor(c[1])];
18873 }
18874
18875
18876 function geoInterp(p1, p2, t) {
18877     return [p1[0] + (p2[0] - p1[0]) * t,
18878             p1[1] + (p2[1] - p1[1]) * t];
18879 }
18880
18881
18882 // 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
18883 // Returns a positive value, if OAB makes a counter-clockwise turn,
18884 // negative for clockwise turn, and zero if the points are collinear.
18885 function geoCross(o, a, b) {
18886     return (a[0] - o[0]) * (b[1] - o[1]) - (a[1] - o[1]) * (b[0] - o[0]);
18887 }
18888
18889
18890 // http://jsperf.com/id-dist-optimization
18891 function geoEuclideanDistance(a, b) {
18892     var x = a[0] - b[0], y = a[1] - b[1];
18893     return Math.sqrt((x * x) + (y * y));
18894 }
18895
18896
18897 // using WGS84 polar radius (6356752.314245179 m)
18898 // const = 2 * PI * r / 360
18899 function geoLatToMeters(dLat) {
18900     return dLat * 110946.257617;
18901 }
18902
18903
18904 // using WGS84 equatorial radius (6378137.0 m)
18905 // const = 2 * PI * r / 360
18906 function geoLonToMeters(dLon, atLat) {
18907     return Math.abs(atLat) >= 90 ? 0 :
18908         dLon * 111319.490793 * Math.abs(Math.cos(atLat * (Math.PI/180)));
18909 }
18910
18911
18912 // using WGS84 polar radius (6356752.314245179 m)
18913 // const = 2 * PI * r / 360
18914 function geoMetersToLat(m) {
18915     return m / 110946.257617;
18916 }
18917
18918
18919 // using WGS84 equatorial radius (6378137.0 m)
18920 // const = 2 * PI * r / 360
18921 function geoMetersToLon(m, atLat) {
18922     return Math.abs(atLat) >= 90 ? 0 :
18923         m / 111319.490793 / Math.abs(Math.cos(atLat * (Math.PI/180)));
18924 }
18925
18926
18927 function geoOffsetToMeters(offset) {
18928     var equatRadius = 6356752.314245179,
18929         polarRadius = 6378137.0,
18930         tileSize = 256;
18931
18932     return [
18933         offset[0] * 2 * Math.PI * equatRadius / tileSize,
18934         -offset[1] * 2 * Math.PI * polarRadius / tileSize
18935     ];
18936 }
18937
18938
18939 function geoMetersToOffset(meters) {
18940     var equatRadius = 6356752.314245179,
18941         polarRadius = 6378137.0,
18942         tileSize = 256;
18943
18944     return [
18945         meters[0] * tileSize / (2 * Math.PI * equatRadius),
18946         -meters[1] * tileSize / (2 * Math.PI * polarRadius)
18947     ];
18948 }
18949
18950
18951 // Equirectangular approximation of spherical distances on Earth
18952 function geoSphericalDistance(a, b) {
18953     var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2),
18954         y = geoLatToMeters(a[1] - b[1]);
18955     return Math.sqrt((x * x) + (y * y));
18956 }
18957
18958
18959 function geoEdgeEqual(a, b) {
18960     return (a[0] === b[0] && a[1] === b[1]) ||
18961         (a[0] === b[1] && a[1] === b[0]);
18962 }
18963
18964
18965 // Return the counterclockwise angle in the range (-pi, pi)
18966 // between the positive X axis and the line intersecting a and b.
18967 function geoAngle(a, b, projection) {
18968     a = projection(a.loc);
18969     b = projection(b.loc);
18970     return Math.atan2(b[1] - a[1], b[0] - a[0]);
18971 }
18972
18973
18974 // Rotate all points counterclockwise around a pivot point by given angle
18975 function geoRotate(points, angle, around) {
18976     return points.map(function(point) {
18977         var radial = [point[0] - around[0], point[1] - around[1]];
18978         return [
18979             radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + around[0],
18980             radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + around[1]
18981         ];
18982     });
18983 }
18984
18985
18986 // Choose the edge with the minimal distance from `point` to its orthogonal
18987 // projection onto that edge, if such a projection exists, or the distance to
18988 // the closest vertex on that edge. Returns an object with the `index` of the
18989 // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
18990 function geoChooseEdge(nodes, point, projection) {
18991     var dist = geoEuclideanDistance,
18992         points = nodes.map(function(n) { return projection(n.loc); }),
18993         min = Infinity,
18994         idx, loc;
18995
18996     function dot(p, q) {
18997         return p[0] * q[0] + p[1] * q[1];
18998     }
18999
19000     for (var i = 0; i < points.length - 1; i++) {
19001         var o = points[i],
19002             s = [points[i + 1][0] - o[0],
19003                  points[i + 1][1] - o[1]],
19004             v = [point[0] - o[0],
19005                  point[1] - o[1]],
19006             proj = dot(v, s) / dot(s, s),
19007             p;
19008
19009         if (proj < 0) {
19010             p = o;
19011         } else if (proj > 1) {
19012             p = points[i + 1];
19013         } else {
19014             p = [o[0] + proj * s[0], o[1] + proj * s[1]];
19015         }
19016
19017         var d = dist(p, point);
19018         if (d < min) {
19019             min = d;
19020             idx = i + 1;
19021             loc = projection.invert(p);
19022         }
19023     }
19024
19025     return {
19026         index: idx,
19027         distance: min,
19028         loc: loc
19029     };
19030 }
19031
19032
19033 // Return the intersection point of 2 line segments.
19034 // From https://github.com/pgkelley4/line-segments-intersect
19035 // This uses the vector cross product approach described below:
19036 //  http://stackoverflow.com/a/565282/786339
19037 function geoLineIntersection(a, b) {
19038     function subtractPoints(point1, point2) {
19039         return [point1[0] - point2[0], point1[1] - point2[1]];
19040     }
19041     function crossProduct(point1, point2) {
19042         return point1[0] * point2[1] - point1[1] * point2[0];
19043     }
19044
19045     var p = [a[0][0], a[0][1]],
19046         p2 = [a[1][0], a[1][1]],
19047         q = [b[0][0], b[0][1]],
19048         q2 = [b[1][0], b[1][1]],
19049         r = subtractPoints(p2, p),
19050         s = subtractPoints(q2, q),
19051         uNumerator = crossProduct(subtractPoints(q, p), r),
19052         denominator = crossProduct(r, s);
19053
19054     if (uNumerator && denominator) {
19055         var u = uNumerator / denominator,
19056             t = crossProduct(subtractPoints(q, p), s) / denominator;
19057
19058         if ((t >= 0) && (t <= 1) && (u >= 0) && (u <= 1)) {
19059             return geoInterp(p, p2, t);
19060         }
19061     }
19062
19063     return null;
19064 }
19065
19066
19067 function geoPathIntersections(path1, path2) {
19068     var intersections = [];
19069     for (var i = 0; i < path1.length - 1; i++) {
19070         for (var j = 0; j < path2.length - 1; j++) {
19071             var a = [ path1[i], path1[i+1] ],
19072                 b = [ path2[j], path2[j+1] ],
19073                 hit = geoLineIntersection(a, b);
19074             if (hit) intersections.push(hit);
19075         }
19076     }
19077     return intersections;
19078 }
19079
19080
19081 // Return whether point is contained in polygon.
19082 //
19083 // `point` should be a 2-item array of coordinates.
19084 // `polygon` should be an array of 2-item arrays of coordinates.
19085 //
19086 // From https://github.com/substack/point-in-polygon.
19087 // ray-casting algorithm based on
19088 // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
19089 //
19090 function geoPointInPolygon(point, polygon) {
19091     var x = point[0],
19092         y = point[1],
19093         inside = false;
19094
19095     for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
19096         var xi = polygon[i][0], yi = polygon[i][1];
19097         var xj = polygon[j][0], yj = polygon[j][1];
19098
19099         var intersect = ((yi > y) !== (yj > y)) &&
19100             (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
19101         if (intersect) inside = !inside;
19102     }
19103
19104     return inside;
19105 }
19106
19107
19108 function geoPolygonContainsPolygon(outer, inner) {
19109     return lodash.every(inner, function(point) {
19110         return geoPointInPolygon(point, outer);
19111     });
19112 }
19113
19114
19115 function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
19116     function testSegments(outer, inner) {
19117         for (var i = 0; i < outer.length - 1; i++) {
19118             for (var j = 0; j < inner.length - 1; j++) {
19119                 var a = [ outer[i], outer[i+1] ],
19120                     b = [ inner[j], inner[j+1] ];
19121                 if (geoLineIntersection(a, b)) return true;
19122             }
19123         }
19124         return false;
19125     }
19126
19127     function testPoints(outer, inner) {
19128         return lodash.some(inner, function(point) {
19129             return geoPointInPolygon(point, outer);
19130         });
19131     }
19132
19133    return testPoints(outer, inner) || (!!checkSegments && testSegments(outer, inner));
19134 }
19135
19136
19137 function geoPathLength(path) {
19138     var length = 0;
19139     for (var i = 0; i < path.length - 1; i++) {
19140         length += geoEuclideanDistance(path[i], path[i + 1]);
19141     }
19142     return length;
19143 }
19144
19145 function geoExtent$$1(min, max) {
19146     if (!(this instanceof geoExtent$$1)) return new geoExtent$$1(min, max);
19147     if (min instanceof geoExtent$$1) {
19148         return min;
19149     } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
19150         this[0] = min[0];
19151         this[1] = min[1];
19152     } else {
19153         this[0] = min        || [ Infinity,  Infinity];
19154         this[1] = max || min || [-Infinity, -Infinity];
19155     }
19156 }
19157
19158 geoExtent$$1.prototype = new Array(2);
19159
19160 lodash.extend(geoExtent$$1.prototype, {
19161
19162     equals: function (obj) {
19163         return this[0][0] === obj[0][0] &&
19164             this[0][1] === obj[0][1] &&
19165             this[1][0] === obj[1][0] &&
19166             this[1][1] === obj[1][1];
19167     },
19168
19169
19170     extend: function(obj) {
19171         if (!(obj instanceof geoExtent$$1)) obj = new geoExtent$$1(obj);
19172         return geoExtent$$1(
19173             [Math.min(obj[0][0], this[0][0]), Math.min(obj[0][1], this[0][1])],
19174             [Math.max(obj[1][0], this[1][0]), Math.max(obj[1][1], this[1][1])]
19175         );
19176     },
19177
19178
19179     _extend: function(extent) {
19180         this[0][0] = Math.min(extent[0][0], this[0][0]);
19181         this[0][1] = Math.min(extent[0][1], this[0][1]);
19182         this[1][0] = Math.max(extent[1][0], this[1][0]);
19183         this[1][1] = Math.max(extent[1][1], this[1][1]);
19184     },
19185
19186
19187     area: function() {
19188         return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
19189     },
19190
19191
19192     center: function() {
19193         return [(this[0][0] + this[1][0]) / 2,
19194                 (this[0][1] + this[1][1]) / 2];
19195     },
19196
19197
19198     rectangle: function() {
19199         return [this[0][0], this[0][1], this[1][0], this[1][1]];
19200     },
19201
19202
19203     bbox: function() {
19204         return { minX: this[0][0], minY: this[0][1], maxX: this[1][0], maxY: this[1][1] };
19205     },
19206
19207
19208     polygon: function() {
19209         return [
19210             [this[0][0], this[0][1]],
19211             [this[0][0], this[1][1]],
19212             [this[1][0], this[1][1]],
19213             [this[1][0], this[0][1]],
19214             [this[0][0], this[0][1]]
19215         ];
19216     },
19217
19218
19219     contains: function(obj) {
19220         if (!(obj instanceof geoExtent$$1)) obj = new geoExtent$$1(obj);
19221         return obj[0][0] >= this[0][0] &&
19222                obj[0][1] >= this[0][1] &&
19223                obj[1][0] <= this[1][0] &&
19224                obj[1][1] <= this[1][1];
19225     },
19226
19227
19228     intersects: function(obj) {
19229         if (!(obj instanceof geoExtent$$1)) obj = new geoExtent$$1(obj);
19230         return obj[0][0] <= this[1][0] &&
19231                obj[0][1] <= this[1][1] &&
19232                obj[1][0] >= this[0][0] &&
19233                obj[1][1] >= this[0][1];
19234     },
19235
19236
19237     intersection: function(obj) {
19238         if (!this.intersects(obj)) return new geoExtent$$1();
19239         return new geoExtent$$1(
19240             [Math.max(obj[0][0], this[0][0]), Math.max(obj[0][1], this[0][1])],
19241             [Math.min(obj[1][0], this[1][0]), Math.min(obj[1][1], this[1][1])]
19242         );
19243     },
19244
19245
19246     percentContainedIn: function(obj) {
19247         if (!(obj instanceof geoExtent$$1)) obj = new geoExtent$$1(obj);
19248         var a1 = this.intersection(obj).area(),
19249             a2 = this.area();
19250
19251         if (a1 === Infinity || a2 === Infinity || a1 === 0 || a2 === 0) {
19252             return 0;
19253         } else {
19254             return a1 / a2;
19255         }
19256     },
19257
19258
19259     padByMeters: function(meters) {
19260         var dLat = geoMetersToLat(meters),
19261             dLon = geoMetersToLon(meters, this.center()[1]);
19262         return geoExtent$$1(
19263             [this[0][0] - dLon, this[0][1] - dLat],
19264             [this[1][0] + dLon, this[1][1] + dLat]
19265         );
19266     },
19267
19268
19269     toParam: function() {
19270         return this.rectangle().join(',');
19271     }
19272
19273 });
19274
19275 var version = "4.9.1";
19276
19277 var ascending = function(a, b) {
19278   return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
19279 };
19280
19281 var bisector = function(compare) {
19282   if (compare.length === 1) compare = ascendingComparator(compare);
19283   return {
19284     left: function(a, x, lo, hi) {
19285       if (lo == null) lo = 0;
19286       if (hi == null) hi = a.length;
19287       while (lo < hi) {
19288         var mid = lo + hi >>> 1;
19289         if (compare(a[mid], x) < 0) lo = mid + 1;
19290         else hi = mid;
19291       }
19292       return lo;
19293     },
19294     right: function(a, x, lo, hi) {
19295       if (lo == null) lo = 0;
19296       if (hi == null) hi = a.length;
19297       while (lo < hi) {
19298         var mid = lo + hi >>> 1;
19299         if (compare(a[mid], x) > 0) hi = mid;
19300         else lo = mid + 1;
19301       }
19302       return lo;
19303     }
19304   };
19305 };
19306
19307 function ascendingComparator(f) {
19308   return function(d, x) {
19309     return ascending(f(d), x);
19310   };
19311 }
19312
19313 var ascendingBisect = bisector(ascending);
19314 var bisectRight = ascendingBisect.right;
19315 var bisectLeft = ascendingBisect.left;
19316
19317 var pairs = function(array, f) {
19318   if (f == null) f = pair;
19319   var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n);
19320   while (i < n) pairs[i] = f(p, p = array[++i]);
19321   return pairs;
19322 };
19323
19324 function pair(a, b) {
19325   return [a, b];
19326 }
19327
19328 var cross = function(values0, values1, reduce) {
19329   var n0 = values0.length,
19330       n1 = values1.length,
19331       values = new Array(n0 * n1),
19332       i0,
19333       i1,
19334       i,
19335       value0;
19336
19337   if (reduce == null) reduce = pair;
19338
19339   for (i0 = i = 0; i0 < n0; ++i0) {
19340     for (value0 = values0[i0], i1 = 0; i1 < n1; ++i1, ++i) {
19341       values[i] = reduce(value0, values1[i1]);
19342     }
19343   }
19344
19345   return values;
19346 };
19347
19348 var descending = function(a, b) {
19349   return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
19350 };
19351
19352 var number = function(x) {
19353   return x === null ? NaN : +x;
19354 };
19355
19356 var variance = function(values, valueof) {
19357   var n = values.length,
19358       m = 0,
19359       i = -1,
19360       mean = 0,
19361       value,
19362       delta,
19363       sum = 0;
19364
19365   if (valueof == null) {
19366     while (++i < n) {
19367       if (!isNaN(value = number(values[i]))) {
19368         delta = value - mean;
19369         mean += delta / ++m;
19370         sum += delta * (value - mean);
19371       }
19372     }
19373   }
19374
19375   else {
19376     while (++i < n) {
19377       if (!isNaN(value = number(valueof(values[i], i, values)))) {
19378         delta = value - mean;
19379         mean += delta / ++m;
19380         sum += delta * (value - mean);
19381       }
19382     }
19383   }
19384
19385   if (m > 1) return sum / (m - 1);
19386 };
19387
19388 var deviation = function(array, f) {
19389   var v = variance(array, f);
19390   return v ? Math.sqrt(v) : v;
19391 };
19392
19393 var extent = function(values, valueof) {
19394   var n = values.length,
19395       i = -1,
19396       value,
19397       min,
19398       max;
19399
19400   if (valueof == null) {
19401     while (++i < n) { // Find the first comparable value.
19402       if ((value = values[i]) != null && value >= value) {
19403         min = max = value;
19404         while (++i < n) { // Compare the remaining values.
19405           if ((value = values[i]) != null) {
19406             if (min > value) min = value;
19407             if (max < value) max = value;
19408           }
19409         }
19410       }
19411     }
19412   }
19413
19414   else {
19415     while (++i < n) { // Find the first comparable value.
19416       if ((value = valueof(values[i], i, values)) != null && value >= value) {
19417         min = max = value;
19418         while (++i < n) { // Compare the remaining values.
19419           if ((value = valueof(values[i], i, values)) != null) {
19420             if (min > value) min = value;
19421             if (max < value) max = value;
19422           }
19423         }
19424       }
19425     }
19426   }
19427
19428   return [min, max];
19429 };
19430
19431 var array = Array.prototype;
19432
19433 var slice = array.slice;
19434 var map = array.map;
19435
19436 var constant = function(x) {
19437   return function() {
19438     return x;
19439   };
19440 };
19441
19442 var identity = function(x) {
19443   return x;
19444 };
19445
19446 var sequence = function(start, stop, step) {
19447   start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
19448
19449   var i = -1,
19450       n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
19451       range = new Array(n);
19452
19453   while (++i < n) {
19454     range[i] = start + i * step;
19455   }
19456
19457   return range;
19458 };
19459
19460 var e10 = Math.sqrt(50);
19461 var e5 = Math.sqrt(10);
19462 var e2 = Math.sqrt(2);
19463
19464 var ticks = function(start, stop, count) {
19465   var reverse = stop < start,
19466       i = -1,
19467       n,
19468       ticks,
19469       step;
19470
19471   if (reverse) n = start, start = stop, stop = n;
19472
19473   if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
19474
19475   if (step > 0) {
19476     start = Math.ceil(start / step);
19477     stop = Math.floor(stop / step);
19478     ticks = new Array(n = Math.ceil(stop - start + 1));
19479     while (++i < n) ticks[i] = (start + i) * step;
19480   } else {
19481     start = Math.floor(start * step);
19482     stop = Math.ceil(stop * step);
19483     ticks = new Array(n = Math.ceil(start - stop + 1));
19484     while (++i < n) ticks[i] = (start - i) / step;
19485   }
19486
19487   if (reverse) ticks.reverse();
19488
19489   return ticks;
19490 };
19491
19492 function tickIncrement(start, stop, count) {
19493   var step = (stop - start) / Math.max(0, count),
19494       power = Math.floor(Math.log(step) / Math.LN10),
19495       error = step / Math.pow(10, power);
19496   return power >= 0
19497       ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power)
19498       : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
19499 }
19500
19501 function tickStep(start, stop, count) {
19502   var step0 = Math.abs(stop - start) / Math.max(0, count),
19503       step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
19504       error = step0 / step1;
19505   if (error >= e10) step1 *= 10;
19506   else if (error >= e5) step1 *= 5;
19507   else if (error >= e2) step1 *= 2;
19508   return stop < start ? -step1 : step1;
19509 }
19510
19511 var sturges = function(values) {
19512   return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
19513 };
19514
19515 var histogram = function() {
19516   var value = identity,
19517       domain = extent,
19518       threshold = sturges;
19519
19520   function histogram(data) {
19521     var i,
19522         n = data.length,
19523         x,
19524         values = new Array(n);
19525
19526     for (i = 0; i < n; ++i) {
19527       values[i] = value(data[i], i, data);
19528     }
19529
19530     var xz = domain(values),
19531         x0 = xz[0],
19532         x1 = xz[1],
19533         tz = threshold(values, x0, x1);
19534
19535     // Convert number of thresholds into uniform thresholds.
19536     if (!Array.isArray(tz)) {
19537       tz = tickStep(x0, x1, tz);
19538       tz = sequence(Math.ceil(x0 / tz) * tz, Math.floor(x1 / tz) * tz, tz); // exclusive
19539     }
19540
19541     // Remove any thresholds outside the domain.
19542     var m = tz.length;
19543     while (tz[0] <= x0) tz.shift(), --m;
19544     while (tz[m - 1] > x1) tz.pop(), --m;
19545
19546     var bins = new Array(m + 1),
19547         bin;
19548
19549     // Initialize bins.
19550     for (i = 0; i <= m; ++i) {
19551       bin = bins[i] = [];
19552       bin.x0 = i > 0 ? tz[i - 1] : x0;
19553       bin.x1 = i < m ? tz[i] : x1;
19554     }
19555
19556     // Assign data to bins by value, ignoring any outside the domain.
19557     for (i = 0; i < n; ++i) {
19558       x = values[i];
19559       if (x0 <= x && x <= x1) {
19560         bins[bisectRight(tz, x, 0, m)].push(data[i]);
19561       }
19562     }
19563
19564     return bins;
19565   }
19566
19567   histogram.value = function(_) {
19568     return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value;
19569   };
19570
19571   histogram.domain = function(_) {
19572     return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain;
19573   };
19574
19575   histogram.thresholds = function(_) {
19576     return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), histogram) : threshold;
19577   };
19578
19579   return histogram;
19580 };
19581
19582 var threshold = function(values, p, valueof) {
19583   if (valueof == null) valueof = number;
19584   if (!(n = values.length)) return;
19585   if ((p = +p) <= 0 || n < 2) return +valueof(values[0], 0, values);
19586   if (p >= 1) return +valueof(values[n - 1], n - 1, values);
19587   var n,
19588       i = (n - 1) * p,
19589       i0 = Math.floor(i),
19590       value0 = +valueof(values[i0], i0, values),
19591       value1 = +valueof(values[i0 + 1], i0 + 1, values);
19592   return value0 + (value1 - value0) * (i - i0);
19593 };
19594
19595 var freedmanDiaconis = function(values, min, max) {
19596   values = map.call(values, number).sort(ascending);
19597   return Math.ceil((max - min) / (2 * (threshold(values, 0.75) - threshold(values, 0.25)) * Math.pow(values.length, -1 / 3)));
19598 };
19599
19600 var scott = function(values, min, max) {
19601   return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3)));
19602 };
19603
19604 var max = function(values, valueof) {
19605   var n = values.length,
19606       i = -1,
19607       value,
19608       max;
19609
19610   if (valueof == null) {
19611     while (++i < n) { // Find the first comparable value.
19612       if ((value = values[i]) != null && value >= value) {
19613         max = value;
19614         while (++i < n) { // Compare the remaining values.
19615           if ((value = values[i]) != null && value > max) {
19616             max = value;
19617           }
19618         }
19619       }
19620     }
19621   }
19622
19623   else {
19624     while (++i < n) { // Find the first comparable value.
19625       if ((value = valueof(values[i], i, values)) != null && value >= value) {
19626         max = value;
19627         while (++i < n) { // Compare the remaining values.
19628           if ((value = valueof(values[i], i, values)) != null && value > max) {
19629             max = value;
19630           }
19631         }
19632       }
19633     }
19634   }
19635
19636   return max;
19637 };
19638
19639 var mean = function(values, valueof) {
19640   var n = values.length,
19641       m = n,
19642       i = -1,
19643       value,
19644       sum = 0;
19645
19646   if (valueof == null) {
19647     while (++i < n) {
19648       if (!isNaN(value = number(values[i]))) sum += value;
19649       else --m;
19650     }
19651   }
19652
19653   else {
19654     while (++i < n) {
19655       if (!isNaN(value = number(valueof(values[i], i, values)))) sum += value;
19656       else --m;
19657     }
19658   }
19659
19660   if (m) return sum / m;
19661 };
19662
19663 var median = function(values, valueof) {
19664   var n = values.length,
19665       i = -1,
19666       value,
19667       numbers = [];
19668
19669   if (valueof == null) {
19670     while (++i < n) {
19671       if (!isNaN(value = number(values[i]))) {
19672         numbers.push(value);
19673       }
19674     }
19675   }
19676
19677   else {
19678     while (++i < n) {
19679       if (!isNaN(value = number(valueof(values[i], i, values)))) {
19680         numbers.push(value);
19681       }
19682     }
19683   }
19684
19685   return threshold(numbers.sort(ascending), 0.5);
19686 };
19687
19688 var merge = function(arrays) {
19689   var n = arrays.length,
19690       m,
19691       i = -1,
19692       j = 0,
19693       merged,
19694       array;
19695
19696   while (++i < n) j += arrays[i].length;
19697   merged = new Array(j);
19698
19699   while (--n >= 0) {
19700     array = arrays[n];
19701     m = array.length;
19702     while (--m >= 0) {
19703       merged[--j] = array[m];
19704     }
19705   }
19706
19707   return merged;
19708 };
19709
19710 var min = function(values, valueof) {
19711   var n = values.length,
19712       i = -1,
19713       value,
19714       min;
19715
19716   if (valueof == null) {
19717     while (++i < n) { // Find the first comparable value.
19718       if ((value = values[i]) != null && value >= value) {
19719         min = value;
19720         while (++i < n) { // Compare the remaining values.
19721           if ((value = values[i]) != null && min > value) {
19722             min = value;
19723           }
19724         }
19725       }
19726     }
19727   }
19728
19729   else {
19730     while (++i < n) { // Find the first comparable value.
19731       if ((value = valueof(values[i], i, values)) != null && value >= value) {
19732         min = value;
19733         while (++i < n) { // Compare the remaining values.
19734           if ((value = valueof(values[i], i, values)) != null && min > value) {
19735             min = value;
19736           }
19737         }
19738       }
19739     }
19740   }
19741
19742   return min;
19743 };
19744
19745 var permute = function(array, indexes) {
19746   var i = indexes.length, permutes = new Array(i);
19747   while (i--) permutes[i] = array[indexes[i]];
19748   return permutes;
19749 };
19750
19751 var scan = function(values, compare) {
19752   if (!(n = values.length)) return;
19753   var n,
19754       i = 0,
19755       j = 0,
19756       xi,
19757       xj = values[j];
19758
19759   if (compare == null) compare = ascending;
19760
19761   while (++i < n) {
19762     if (compare(xi = values[i], xj) < 0 || compare(xj, xj) !== 0) {
19763       xj = xi, j = i;
19764     }
19765   }
19766
19767   if (compare(xj, xj) === 0) return j;
19768 };
19769
19770 var shuffle = function(array, i0, i1) {
19771   var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0),
19772       t,
19773       i;
19774
19775   while (m) {
19776     i = Math.random() * m-- | 0;
19777     t = array[m + i0];
19778     array[m + i0] = array[i + i0];
19779     array[i + i0] = t;
19780   }
19781
19782   return array;
19783 };
19784
19785 var sum = function(values, valueof) {
19786   var n = values.length,
19787       i = -1,
19788       value,
19789       sum = 0;
19790
19791   if (valueof == null) {
19792     while (++i < n) {
19793       if (value = +values[i]) sum += value; // Note: zero and null are equivalent.
19794     }
19795   }
19796
19797   else {
19798     while (++i < n) {
19799       if (value = +valueof(values[i], i, values)) sum += value;
19800     }
19801   }
19802
19803   return sum;
19804 };
19805
19806 var transpose = function(matrix) {
19807   if (!(n = matrix.length)) return [];
19808   for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) {
19809     for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) {
19810       row[j] = matrix[j][i];
19811     }
19812   }
19813   return transpose;
19814 };
19815
19816 function length(d) {
19817   return d.length;
19818 }
19819
19820 var zip = function() {
19821   return transpose(arguments);
19822 };
19823
19824 var slice$1 = Array.prototype.slice;
19825
19826 var identity$1 = function(x) {
19827   return x;
19828 };
19829
19830 var top = 1;
19831 var right = 2;
19832 var bottom = 3;
19833 var left = 4;
19834 var epsilon = 1e-6;
19835
19836 function translateX(x) {
19837   return "translate(" + (x + 0.5) + ",0)";
19838 }
19839
19840 function translateY(y) {
19841   return "translate(0," + (y + 0.5) + ")";
19842 }
19843
19844 function center(scale) {
19845   var offset = Math.max(0, scale.bandwidth() - 1) / 2; // Adjust for 0.5px offset.
19846   if (scale.round()) offset = Math.round(offset);
19847   return function(d) {
19848     return scale(d) + offset;
19849   };
19850 }
19851
19852 function entering() {
19853   return !this.__axis;
19854 }
19855
19856 function axis(orient, scale) {
19857   var tickArguments = [],
19858       tickValues = null,
19859       tickFormat = null,
19860       tickSizeInner = 6,
19861       tickSizeOuter = 6,
19862       tickPadding = 3,
19863       k = orient === top || orient === left ? -1 : 1,
19864       x = orient === left || orient === right ? "x" : "y",
19865       transform = orient === top || orient === bottom ? translateX : translateY;
19866
19867   function axis(context) {
19868     var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues,
19869         format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$1) : tickFormat,
19870         spacing = Math.max(tickSizeInner, 0) + tickPadding,
19871         range = scale.range(),
19872         range0 = range[0] + 0.5,
19873         range1 = range[range.length - 1] + 0.5,
19874         position = (scale.bandwidth ? center : identity$1)(scale.copy()),
19875         selection = context.selection ? context.selection() : context,
19876         path = selection.selectAll(".domain").data([null]),
19877         tick = selection.selectAll(".tick").data(values, scale).order(),
19878         tickExit = tick.exit(),
19879         tickEnter = tick.enter().append("g").attr("class", "tick"),
19880         line = tick.select("line"),
19881         text = tick.select("text");
19882
19883     path = path.merge(path.enter().insert("path", ".tick")
19884         .attr("class", "domain")
19885         .attr("stroke", "#000"));
19886
19887     tick = tick.merge(tickEnter);
19888
19889     line = line.merge(tickEnter.append("line")
19890         .attr("stroke", "#000")
19891         .attr(x + "2", k * tickSizeInner));
19892
19893     text = text.merge(tickEnter.append("text")
19894         .attr("fill", "#000")
19895         .attr(x, k * spacing)
19896         .attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em"));
19897
19898     if (context !== selection) {
19899       path = path.transition(context);
19900       tick = tick.transition(context);
19901       line = line.transition(context);
19902       text = text.transition(context);
19903
19904       tickExit = tickExit.transition(context)
19905           .attr("opacity", epsilon)
19906           .attr("transform", function(d) { return isFinite(d = position(d)) ? transform(d) : this.getAttribute("transform"); });
19907
19908       tickEnter
19909           .attr("opacity", epsilon)
19910           .attr("transform", function(d) { var p = this.parentNode.__axis; return transform(p && isFinite(p = p(d)) ? p : position(d)); });
19911     }
19912
19913     tickExit.remove();
19914
19915     path
19916         .attr("d", orient === left || orient == right
19917             ? "M" + k * tickSizeOuter + "," + range0 + "H0.5V" + range1 + "H" + k * tickSizeOuter
19918             : "M" + range0 + "," + k * tickSizeOuter + "V0.5H" + range1 + "V" + k * tickSizeOuter);
19919
19920     tick
19921         .attr("opacity", 1)
19922         .attr("transform", function(d) { return transform(position(d)); });
19923
19924     line
19925         .attr(x + "2", k * tickSizeInner);
19926
19927     text
19928         .attr(x, k * spacing)
19929         .text(format);
19930
19931     selection.filter(entering)
19932         .attr("fill", "none")
19933         .attr("font-size", 10)
19934         .attr("font-family", "sans-serif")
19935         .attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle");
19936
19937     selection
19938         .each(function() { this.__axis = position; });
19939   }
19940
19941   axis.scale = function(_) {
19942     return arguments.length ? (scale = _, axis) : scale;
19943   };
19944
19945   axis.ticks = function() {
19946     return tickArguments = slice$1.call(arguments), axis;
19947   };
19948
19949   axis.tickArguments = function(_) {
19950     return arguments.length ? (tickArguments = _ == null ? [] : slice$1.call(_), axis) : tickArguments.slice();
19951   };
19952
19953   axis.tickValues = function(_) {
19954     return arguments.length ? (tickValues = _ == null ? null : slice$1.call(_), axis) : tickValues && tickValues.slice();
19955   };
19956
19957   axis.tickFormat = function(_) {
19958     return arguments.length ? (tickFormat = _, axis) : tickFormat;
19959   };
19960
19961   axis.tickSize = function(_) {
19962     return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner;
19963   };
19964
19965   axis.tickSizeInner = function(_) {
19966     return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner;
19967   };
19968
19969   axis.tickSizeOuter = function(_) {
19970     return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter;
19971   };
19972
19973   axis.tickPadding = function(_) {
19974     return arguments.length ? (tickPadding = +_, axis) : tickPadding;
19975   };
19976
19977   return axis;
19978 }
19979
19980 function axisTop(scale) {
19981   return axis(top, scale);
19982 }
19983
19984 function axisRight(scale) {
19985   return axis(right, scale);
19986 }
19987
19988 function axisBottom(scale) {
19989   return axis(bottom, scale);
19990 }
19991
19992 function axisLeft(scale) {
19993   return axis(left, scale);
19994 }
19995
19996 var noop = {value: function() {}};
19997
19998 function dispatch() {
19999   for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
20000     if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
20001     _[t] = [];
20002   }
20003   return new Dispatch(_);
20004 }
20005
20006 function Dispatch(_) {
20007   this._ = _;
20008 }
20009
20010 function parseTypenames(typenames, types) {
20011   return typenames.trim().split(/^|\s+/).map(function(t) {
20012     var name = "", i = t.indexOf(".");
20013     if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
20014     if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
20015     return {type: t, name: name};
20016   });
20017 }
20018
20019 Dispatch.prototype = dispatch.prototype = {
20020   constructor: Dispatch,
20021   on: function(typename, callback) {
20022     var _ = this._,
20023         T = parseTypenames(typename + "", _),
20024         t,
20025         i = -1,
20026         n = T.length;
20027
20028     // If no callback was specified, return the callback of the given type and name.
20029     if (arguments.length < 2) {
20030       while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
20031       return;
20032     }
20033
20034     // If a type was specified, set the callback for the given type and name.
20035     // Otherwise, if a null callback was specified, remove callbacks of the given name.
20036     if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
20037     while (++i < n) {
20038       if (t = (typename = T[i]).type) _[t] = set(_[t], typename.name, callback);
20039       else if (callback == null) for (t in _) _[t] = set(_[t], typename.name, null);
20040     }
20041
20042     return this;
20043   },
20044   copy: function() {
20045     var copy = {}, _ = this._;
20046     for (var t in _) copy[t] = _[t].slice();
20047     return new Dispatch(copy);
20048   },
20049   call: function(type, that) {
20050     if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
20051     if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
20052     for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
20053   },
20054   apply: function(type, that, args) {
20055     if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
20056     for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
20057   }
20058 };
20059
20060 function get(type, name) {
20061   for (var i = 0, n = type.length, c; i < n; ++i) {
20062     if ((c = type[i]).name === name) {
20063       return c.value;
20064     }
20065   }
20066 }
20067
20068 function set(type, name, callback) {
20069   for (var i = 0, n = type.length; i < n; ++i) {
20070     if (type[i].name === name) {
20071       type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
20072       break;
20073     }
20074   }
20075   if (callback != null) type.push({name: name, value: callback});
20076   return type;
20077 }
20078
20079 var xhtml = "http://www.w3.org/1999/xhtml";
20080
20081 var namespaces = {
20082   svg: "http://www.w3.org/2000/svg",
20083   xhtml: xhtml,
20084   xlink: "http://www.w3.org/1999/xlink",
20085   xml: "http://www.w3.org/XML/1998/namespace",
20086   xmlns: "http://www.w3.org/2000/xmlns/"
20087 };
20088
20089 var namespace = function(name) {
20090   var prefix = name += "", i = prefix.indexOf(":");
20091   if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
20092   return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name;
20093 };
20094
20095 function creatorInherit(name) {
20096   return function() {
20097     var document = this.ownerDocument,
20098         uri = this.namespaceURI;
20099     return uri === xhtml && document.documentElement.namespaceURI === xhtml
20100         ? document.createElement(name)
20101         : document.createElementNS(uri, name);
20102   };
20103 }
20104
20105 function creatorFixed(fullname) {
20106   return function() {
20107     return this.ownerDocument.createElementNS(fullname.space, fullname.local);
20108   };
20109 }
20110
20111 var creator = function(name) {
20112   var fullname = namespace(name);
20113   return (fullname.local
20114       ? creatorFixed
20115       : creatorInherit)(fullname);
20116 };
20117
20118 var nextId = 0;
20119
20120 function local$1() {
20121   return new Local;
20122 }
20123
20124 function Local() {
20125   this._ = "@" + (++nextId).toString(36);
20126 }
20127
20128 Local.prototype = local$1.prototype = {
20129   constructor: Local,
20130   get: function(node) {
20131     var id = this._;
20132     while (!(id in node)) if (!(node = node.parentNode)) return;
20133     return node[id];
20134   },
20135   set: function(node, value) {
20136     return node[this._] = value;
20137   },
20138   remove: function(node) {
20139     return this._ in node && delete node[this._];
20140   },
20141   toString: function() {
20142     return this._;
20143   }
20144 };
20145
20146 var matcher = function(selector) {
20147   return function() {
20148     return this.matches(selector);
20149   };
20150 };
20151
20152 if (typeof document !== "undefined") {
20153   var element = document.documentElement;
20154   if (!element.matches) {
20155     var vendorMatches = element.webkitMatchesSelector
20156         || element.msMatchesSelector
20157         || element.mozMatchesSelector
20158         || element.oMatchesSelector;
20159     matcher = function(selector) {
20160       return function() {
20161         return vendorMatches.call(this, selector);
20162       };
20163     };
20164   }
20165 }
20166
20167 var matcher$1 = matcher;
20168
20169 var filterEvents = {};
20170
20171 var event = null;
20172
20173 if (typeof document !== "undefined") {
20174   var element$1 = document.documentElement;
20175   if (!("onmouseenter" in element$1)) {
20176     filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"};
20177   }
20178 }
20179
20180 function filterContextListener(listener, index, group) {
20181   listener = contextListener(listener, index, group);
20182   return function(event) {
20183     var related = event.relatedTarget;
20184     if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) {
20185       listener.call(this, event);
20186     }
20187   };
20188 }
20189
20190 function contextListener(listener, index, group) {
20191   return function(event1) {
20192     var event0 = event; // Events can be reentrant (e.g., focus).
20193     event = event1;
20194     try {
20195       listener.call(this, this.__data__, index, group);
20196     } finally {
20197       event = event0;
20198     }
20199   };
20200 }
20201
20202 function parseTypenames$1(typenames) {
20203   return typenames.trim().split(/^|\s+/).map(function(t) {
20204     var name = "", i = t.indexOf(".");
20205     if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
20206     return {type: t, name: name};
20207   });
20208 }
20209
20210 function onRemove(typename) {
20211   return function() {
20212     var on = this.__on;
20213     if (!on) return;
20214     for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
20215       if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
20216         this.removeEventListener(o.type, o.listener, o.capture);
20217       } else {
20218         on[++i] = o;
20219       }
20220     }
20221     if (++i) on.length = i;
20222     else delete this.__on;
20223   };
20224 }
20225
20226 function onAdd(typename, value, capture) {
20227   var wrap = filterEvents.hasOwnProperty(typename.type) ? filterContextListener : contextListener;
20228   return function(d, i, group) {
20229     var on = this.__on, o, listener = wrap(value, i, group);
20230     if (on) for (var j = 0, m = on.length; j < m; ++j) {
20231       if ((o = on[j]).type === typename.type && o.name === typename.name) {
20232         this.removeEventListener(o.type, o.listener, o.capture);
20233         this.addEventListener(o.type, o.listener = listener, o.capture = capture);
20234         o.value = value;
20235         return;
20236       }
20237     }
20238     this.addEventListener(typename.type, listener, capture);
20239     o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture};
20240     if (!on) this.__on = [o];
20241     else on.push(o);
20242   };
20243 }
20244
20245 var selection_on = function(typename, value, capture) {
20246   var typenames = parseTypenames$1(typename + ""), i, n = typenames.length, t;
20247
20248   if (arguments.length < 2) {
20249     var on = this.node().__on;
20250     if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
20251       for (i = 0, o = on[j]; i < n; ++i) {
20252         if ((t = typenames[i]).type === o.type && t.name === o.name) {
20253           return o.value;
20254         }
20255       }
20256     }
20257     return;
20258   }
20259
20260   on = value ? onAdd : onRemove;
20261   if (capture == null) capture = false;
20262   for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture));
20263   return this;
20264 };
20265
20266 function customEvent(event1, listener, that, args) {
20267   var event0 = event;
20268   event1.sourceEvent = event;
20269   event = event1;
20270   try {
20271     return listener.apply(that, args);
20272   } finally {
20273     event = event0;
20274   }
20275 }
20276
20277 var sourceEvent = function() {
20278   var current = event, source;
20279   while (source = current.sourceEvent) current = source;
20280   return current;
20281 };
20282
20283 var point = function(node, event) {
20284   var svg = node.ownerSVGElement || node;
20285
20286   if (svg.createSVGPoint) {
20287     var point = svg.createSVGPoint();
20288     point.x = event.clientX, point.y = event.clientY;
20289     point = point.matrixTransform(node.getScreenCTM().inverse());
20290     return [point.x, point.y];
20291   }
20292
20293   var rect = node.getBoundingClientRect();
20294   return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
20295 };
20296
20297 var mouse = function(node) {
20298   var event = sourceEvent();
20299   if (event.changedTouches) event = event.changedTouches[0];
20300   return point(node, event);
20301 };
20302
20303 function none() {}
20304
20305 var selector = function(selector) {
20306   return selector == null ? none : function() {
20307     return this.querySelector(selector);
20308   };
20309 };
20310
20311 var selection_select = function(select) {
20312   if (typeof select !== "function") select = selector(select);
20313
20314   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
20315     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
20316       if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
20317         if ("__data__" in node) subnode.__data__ = node.__data__;
20318         subgroup[i] = subnode;
20319       }
20320     }
20321   }
20322
20323   return new Selection(subgroups, this._parents);
20324 };
20325
20326 function empty$1() {
20327   return [];
20328 }
20329
20330 var selectorAll = function(selector) {
20331   return selector == null ? empty$1 : function() {
20332     return this.querySelectorAll(selector);
20333   };
20334 };
20335
20336 var selection_selectAll = function(select) {
20337   if (typeof select !== "function") select = selectorAll(select);
20338
20339   for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
20340     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
20341       if (node = group[i]) {
20342         subgroups.push(select.call(node, node.__data__, i, group));
20343         parents.push(node);
20344       }
20345     }
20346   }
20347
20348   return new Selection(subgroups, parents);
20349 };
20350
20351 var selection_filter = function(match) {
20352   if (typeof match !== "function") match = matcher$1(match);
20353
20354   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
20355     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
20356       if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
20357         subgroup.push(node);
20358       }
20359     }
20360   }
20361
20362   return new Selection(subgroups, this._parents);
20363 };
20364
20365 var sparse = function(update) {
20366   return new Array(update.length);
20367 };
20368
20369 var selection_enter = function() {
20370   return new Selection(this._enter || this._groups.map(sparse), this._parents);
20371 };
20372
20373 function EnterNode(parent, datum) {
20374   this.ownerDocument = parent.ownerDocument;
20375   this.namespaceURI = parent.namespaceURI;
20376   this._next = null;
20377   this._parent = parent;
20378   this.__data__ = datum;
20379 }
20380
20381 EnterNode.prototype = {
20382   constructor: EnterNode,
20383   appendChild: function(child) { return this._parent.insertBefore(child, this._next); },
20384   insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },
20385   querySelector: function(selector) { return this._parent.querySelector(selector); },
20386   querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
20387 };
20388
20389 var constant$1 = function(x) {
20390   return function() {
20391     return x;
20392   };
20393 };
20394
20395 var keyPrefix = "$"; // Protect against keys like “__proto__”.
20396
20397 function bindIndex(parent, group, enter, update, exit, data) {
20398   var i = 0,
20399       node,
20400       groupLength = group.length,
20401       dataLength = data.length;
20402
20403   // Put any non-null nodes that fit into update.
20404   // Put any null nodes into enter.
20405   // Put any remaining data into enter.
20406   for (; i < dataLength; ++i) {
20407     if (node = group[i]) {
20408       node.__data__ = data[i];
20409       update[i] = node;
20410     } else {
20411       enter[i] = new EnterNode(parent, data[i]);
20412     }
20413   }
20414
20415   // Put any non-null nodes that don’t fit into exit.
20416   for (; i < groupLength; ++i) {
20417     if (node = group[i]) {
20418       exit[i] = node;
20419     }
20420   }
20421 }
20422
20423 function bindKey(parent, group, enter, update, exit, data, key) {
20424   var i,
20425       node,
20426       nodeByKeyValue = {},
20427       groupLength = group.length,
20428       dataLength = data.length,
20429       keyValues = new Array(groupLength),
20430       keyValue;
20431
20432   // Compute the key for each node.
20433   // If multiple nodes have the same key, the duplicates are added to exit.
20434   for (i = 0; i < groupLength; ++i) {
20435     if (node = group[i]) {
20436       keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group);
20437       if (keyValue in nodeByKeyValue) {
20438         exit[i] = node;
20439       } else {
20440         nodeByKeyValue[keyValue] = node;
20441       }
20442     }
20443   }
20444
20445   // Compute the key for each datum.
20446   // If there a node associated with this key, join and add it to update.
20447   // If there is not (or the key is a duplicate), add it to enter.
20448   for (i = 0; i < dataLength; ++i) {
20449     keyValue = keyPrefix + key.call(parent, data[i], i, data);
20450     if (node = nodeByKeyValue[keyValue]) {
20451       update[i] = node;
20452       node.__data__ = data[i];
20453       nodeByKeyValue[keyValue] = null;
20454     } else {
20455       enter[i] = new EnterNode(parent, data[i]);
20456     }
20457   }
20458
20459   // Add any remaining nodes that were not bound to data to exit.
20460   for (i = 0; i < groupLength; ++i) {
20461     if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
20462       exit[i] = node;
20463     }
20464   }
20465 }
20466
20467 var selection_data = function(value, key) {
20468   if (!value) {
20469     data = new Array(this.size()), j = -1;
20470     this.each(function(d) { data[++j] = d; });
20471     return data;
20472   }
20473
20474   var bind = key ? bindKey : bindIndex,
20475       parents = this._parents,
20476       groups = this._groups;
20477
20478   if (typeof value !== "function") value = constant$1(value);
20479
20480   for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
20481     var parent = parents[j],
20482         group = groups[j],
20483         groupLength = group.length,
20484         data = value.call(parent, parent && parent.__data__, j, parents),
20485         dataLength = data.length,
20486         enterGroup = enter[j] = new Array(dataLength),
20487         updateGroup = update[j] = new Array(dataLength),
20488         exitGroup = exit[j] = new Array(groupLength);
20489
20490     bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
20491
20492     // Now connect the enter nodes to their following update node, such that
20493     // appendChild can insert the materialized enter node before this node,
20494     // rather than at the end of the parent node.
20495     for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
20496       if (previous = enterGroup[i0]) {
20497         if (i0 >= i1) i1 = i0 + 1;
20498         while (!(next = updateGroup[i1]) && ++i1 < dataLength);
20499         previous._next = next || null;
20500       }
20501     }
20502   }
20503
20504   update = new Selection(update, parents);
20505   update._enter = enter;
20506   update._exit = exit;
20507   return update;
20508 };
20509
20510 var selection_exit = function() {
20511   return new Selection(this._exit || this._groups.map(sparse), this._parents);
20512 };
20513
20514 var selection_merge = function(selection$$1) {
20515
20516   for (var groups0 = this._groups, groups1 = selection$$1._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
20517     for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
20518       if (node = group0[i] || group1[i]) {
20519         merge[i] = node;
20520       }
20521     }
20522   }
20523
20524   for (; j < m0; ++j) {
20525     merges[j] = groups0[j];
20526   }
20527
20528   return new Selection(merges, this._parents);
20529 };
20530
20531 var selection_order = function() {
20532
20533   for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
20534     for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
20535       if (node = group[i]) {
20536         if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
20537         next = node;
20538       }
20539     }
20540   }
20541
20542   return this;
20543 };
20544
20545 var selection_sort = function(compare) {
20546   if (!compare) compare = ascending$1;
20547
20548   function compareNode(a, b) {
20549     return a && b ? compare(a.__data__, b.__data__) : !a - !b;
20550   }
20551
20552   for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
20553     for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
20554       if (node = group[i]) {
20555         sortgroup[i] = node;
20556       }
20557     }
20558     sortgroup.sort(compareNode);
20559   }
20560
20561   return new Selection(sortgroups, this._parents).order();
20562 };
20563
20564 function ascending$1(a, b) {
20565   return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
20566 }
20567
20568 var selection_call = function() {
20569   var callback = arguments[0];
20570   arguments[0] = this;
20571   callback.apply(null, arguments);
20572   return this;
20573 };
20574
20575 var selection_nodes = function() {
20576   var nodes = new Array(this.size()), i = -1;
20577   this.each(function() { nodes[++i] = this; });
20578   return nodes;
20579 };
20580
20581 var selection_node = function() {
20582
20583   for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
20584     for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
20585       var node = group[i];
20586       if (node) return node;
20587     }
20588   }
20589
20590   return null;
20591 };
20592
20593 var selection_size = function() {
20594   var size = 0;
20595   this.each(function() { ++size; });
20596   return size;
20597 };
20598
20599 var selection_empty = function() {
20600   return !this.node();
20601 };
20602
20603 var selection_each = function(callback) {
20604
20605   for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
20606     for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
20607       if (node = group[i]) callback.call(node, node.__data__, i, group);
20608     }
20609   }
20610
20611   return this;
20612 };
20613
20614 function attrRemove(name) {
20615   return function() {
20616     this.removeAttribute(name);
20617   };
20618 }
20619
20620 function attrRemoveNS(fullname) {
20621   return function() {
20622     this.removeAttributeNS(fullname.space, fullname.local);
20623   };
20624 }
20625
20626 function attrConstant(name, value) {
20627   return function() {
20628     this.setAttribute(name, value);
20629   };
20630 }
20631
20632 function attrConstantNS(fullname, value) {
20633   return function() {
20634     this.setAttributeNS(fullname.space, fullname.local, value);
20635   };
20636 }
20637
20638 function attrFunction(name, value) {
20639   return function() {
20640     var v = value.apply(this, arguments);
20641     if (v == null) this.removeAttribute(name);
20642     else this.setAttribute(name, v);
20643   };
20644 }
20645
20646 function attrFunctionNS(fullname, value) {
20647   return function() {
20648     var v = value.apply(this, arguments);
20649     if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
20650     else this.setAttributeNS(fullname.space, fullname.local, v);
20651   };
20652 }
20653
20654 var selection_attr = function(name, value) {
20655   var fullname = namespace(name);
20656
20657   if (arguments.length < 2) {
20658     var node = this.node();
20659     return fullname.local
20660         ? node.getAttributeNS(fullname.space, fullname.local)
20661         : node.getAttribute(fullname);
20662   }
20663
20664   return this.each((value == null
20665       ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function"
20666       ? (fullname.local ? attrFunctionNS : attrFunction)
20667       : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));
20668 };
20669
20670 var defaultView = function(node) {
20671   return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
20672       || (node.document && node) // node is a Window
20673       || node.defaultView; // node is a Document
20674 };
20675
20676 function styleRemove(name) {
20677   return function() {
20678     this.style.removeProperty(name);
20679   };
20680 }
20681
20682 function styleConstant(name, value, priority) {
20683   return function() {
20684     this.style.setProperty(name, value, priority);
20685   };
20686 }
20687
20688 function styleFunction(name, value, priority) {
20689   return function() {
20690     var v = value.apply(this, arguments);
20691     if (v == null) this.style.removeProperty(name);
20692     else this.style.setProperty(name, v, priority);
20693   };
20694 }
20695
20696 var selection_style = function(name, value, priority) {
20697   return arguments.length > 1
20698       ? this.each((value == null
20699             ? styleRemove : typeof value === "function"
20700             ? styleFunction
20701             : styleConstant)(name, value, priority == null ? "" : priority))
20702       : styleValue(this.node(), name);
20703 };
20704
20705 function styleValue(node, name) {
20706   return node.style.getPropertyValue(name)
20707       || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
20708 }
20709
20710 function propertyRemove(name) {
20711   return function() {
20712     delete this[name];
20713   };
20714 }
20715
20716 function propertyConstant(name, value) {
20717   return function() {
20718     this[name] = value;
20719   };
20720 }
20721
20722 function propertyFunction(name, value) {
20723   return function() {
20724     var v = value.apply(this, arguments);
20725     if (v == null) delete this[name];
20726     else this[name] = v;
20727   };
20728 }
20729
20730 var selection_property = function(name, value) {
20731   return arguments.length > 1
20732       ? this.each((value == null
20733           ? propertyRemove : typeof value === "function"
20734           ? propertyFunction
20735           : propertyConstant)(name, value))
20736       : this.node()[name];
20737 };
20738
20739 function classArray(string) {
20740   return string.trim().split(/^|\s+/);
20741 }
20742
20743 function classList(node) {
20744   return node.classList || new ClassList(node);
20745 }
20746
20747 function ClassList(node) {
20748   this._node = node;
20749   this._names = classArray(node.getAttribute("class") || "");
20750 }
20751
20752 ClassList.prototype = {
20753   add: function(name) {
20754     var i = this._names.indexOf(name);
20755     if (i < 0) {
20756       this._names.push(name);
20757       this._node.setAttribute("class", this._names.join(" "));
20758     }
20759   },
20760   remove: function(name) {
20761     var i = this._names.indexOf(name);
20762     if (i >= 0) {
20763       this._names.splice(i, 1);
20764       this._node.setAttribute("class", this._names.join(" "));
20765     }
20766   },
20767   contains: function(name) {
20768     return this._names.indexOf(name) >= 0;
20769   }
20770 };
20771
20772 function classedAdd(node, names) {
20773   var list = classList(node), i = -1, n = names.length;
20774   while (++i < n) list.add(names[i]);
20775 }
20776
20777 function classedRemove(node, names) {
20778   var list = classList(node), i = -1, n = names.length;
20779   while (++i < n) list.remove(names[i]);
20780 }
20781
20782 function classedTrue(names) {
20783   return function() {
20784     classedAdd(this, names);
20785   };
20786 }
20787
20788 function classedFalse(names) {
20789   return function() {
20790     classedRemove(this, names);
20791   };
20792 }
20793
20794 function classedFunction(names, value) {
20795   return function() {
20796     (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
20797   };
20798 }
20799
20800 var selection_classed = function(name, value) {
20801   var names = classArray(name + "");
20802
20803   if (arguments.length < 2) {
20804     var list = classList(this.node()), i = -1, n = names.length;
20805     while (++i < n) if (!list.contains(names[i])) return false;
20806     return true;
20807   }
20808
20809   return this.each((typeof value === "function"
20810       ? classedFunction : value
20811       ? classedTrue
20812       : classedFalse)(names, value));
20813 };
20814
20815 function textRemove() {
20816   this.textContent = "";
20817 }
20818
20819 function textConstant(value) {
20820   return function() {
20821     this.textContent = value;
20822   };
20823 }
20824
20825 function textFunction(value) {
20826   return function() {
20827     var v = value.apply(this, arguments);
20828     this.textContent = v == null ? "" : v;
20829   };
20830 }
20831
20832 var selection_text = function(value) {
20833   return arguments.length
20834       ? this.each(value == null
20835           ? textRemove : (typeof value === "function"
20836           ? textFunction
20837           : textConstant)(value))
20838       : this.node().textContent;
20839 };
20840
20841 function htmlRemove() {
20842   this.innerHTML = "";
20843 }
20844
20845 function htmlConstant(value) {
20846   return function() {
20847     this.innerHTML = value;
20848   };
20849 }
20850
20851 function htmlFunction(value) {
20852   return function() {
20853     var v = value.apply(this, arguments);
20854     this.innerHTML = v == null ? "" : v;
20855   };
20856 }
20857
20858 var selection_html = function(value) {
20859   return arguments.length
20860       ? this.each(value == null
20861           ? htmlRemove : (typeof value === "function"
20862           ? htmlFunction
20863           : htmlConstant)(value))
20864       : this.node().innerHTML;
20865 };
20866
20867 function raise() {
20868   if (this.nextSibling) this.parentNode.appendChild(this);
20869 }
20870
20871 var selection_raise = function() {
20872   return this.each(raise);
20873 };
20874
20875 function lower() {
20876   if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
20877 }
20878
20879 var selection_lower = function() {
20880   return this.each(lower);
20881 };
20882
20883 var selection_append = function(name) {
20884   var create = typeof name === "function" ? name : creator(name);
20885   return this.select(function() {
20886     return this.appendChild(create.apply(this, arguments));
20887   });
20888 };
20889
20890 function constantNull() {
20891   return null;
20892 }
20893
20894 var selection_insert = function(name, before) {
20895   var create = typeof name === "function" ? name : creator(name),
20896       select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
20897   return this.select(function() {
20898     return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
20899   });
20900 };
20901
20902 function remove() {
20903   var parent = this.parentNode;
20904   if (parent) parent.removeChild(this);
20905 }
20906
20907 var selection_remove = function() {
20908   return this.each(remove);
20909 };
20910
20911 var selection_datum = function(value) {
20912   return arguments.length
20913       ? this.property("__data__", value)
20914       : this.node().__data__;
20915 };
20916
20917 function dispatchEvent(node, type, params) {
20918   var window = defaultView(node),
20919       event = window.CustomEvent;
20920
20921   if (typeof event === "function") {
20922     event = new event(type, params);
20923   } else {
20924     event = window.document.createEvent("Event");
20925     if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
20926     else event.initEvent(type, false, false);
20927   }
20928
20929   node.dispatchEvent(event);
20930 }
20931
20932 function dispatchConstant(type, params) {
20933   return function() {
20934     return dispatchEvent(this, type, params);
20935   };
20936 }
20937
20938 function dispatchFunction(type, params) {
20939   return function() {
20940     return dispatchEvent(this, type, params.apply(this, arguments));
20941   };
20942 }
20943
20944 var selection_dispatch = function(type, params) {
20945   return this.each((typeof params === "function"
20946       ? dispatchFunction
20947       : dispatchConstant)(type, params));
20948 };
20949
20950 var root = [null];
20951
20952 function Selection(groups, parents) {
20953   this._groups = groups;
20954   this._parents = parents;
20955 }
20956
20957 function selection() {
20958   return new Selection([[document.documentElement]], root);
20959 }
20960
20961 Selection.prototype = selection.prototype = {
20962   constructor: Selection,
20963   select: selection_select,
20964   selectAll: selection_selectAll,
20965   filter: selection_filter,
20966   data: selection_data,
20967   enter: selection_enter,
20968   exit: selection_exit,
20969   merge: selection_merge,
20970   order: selection_order,
20971   sort: selection_sort,
20972   call: selection_call,
20973   nodes: selection_nodes,
20974   node: selection_node,
20975   size: selection_size,
20976   empty: selection_empty,
20977   each: selection_each,
20978   attr: selection_attr,
20979   style: selection_style,
20980   property: selection_property,
20981   classed: selection_classed,
20982   text: selection_text,
20983   html: selection_html,
20984   raise: selection_raise,
20985   lower: selection_lower,
20986   append: selection_append,
20987   insert: selection_insert,
20988   remove: selection_remove,
20989   datum: selection_datum,
20990   on: selection_on,
20991   dispatch: selection_dispatch
20992 };
20993
20994 var select = function(selector) {
20995   return typeof selector === "string"
20996       ? new Selection([[document.querySelector(selector)]], [document.documentElement])
20997       : new Selection([[selector]], root);
20998 };
20999
21000 var selectAll = function(selector) {
21001   return typeof selector === "string"
21002       ? new Selection([document.querySelectorAll(selector)], [document.documentElement])
21003       : new Selection([selector == null ? [] : selector], root);
21004 };
21005
21006 var touch = function(node, touches, identifier) {
21007   if (arguments.length < 3) identifier = touches, touches = sourceEvent().changedTouches;
21008
21009   for (var i = 0, n = touches ? touches.length : 0, touch; i < n; ++i) {
21010     if ((touch = touches[i]).identifier === identifier) {
21011       return point(node, touch);
21012     }
21013   }
21014
21015   return null;
21016 };
21017
21018 var touches = function(node, touches) {
21019   if (touches == null) touches = sourceEvent().touches;
21020
21021   for (var i = 0, n = touches ? touches.length : 0, points = new Array(n); i < n; ++i) {
21022     points[i] = point(node, touches[i]);
21023   }
21024
21025   return points;
21026 };
21027
21028 function nopropagation() {
21029   event.stopImmediatePropagation();
21030 }
21031
21032 var noevent = function() {
21033   event.preventDefault();
21034   event.stopImmediatePropagation();
21035 };
21036
21037 var dragDisable = function(view) {
21038   var root = view.document.documentElement,
21039       selection$$1 = select(view).on("dragstart.drag", noevent, true);
21040   if ("onselectstart" in root) {
21041     selection$$1.on("selectstart.drag", noevent, true);
21042   } else {
21043     root.__noselect = root.style.MozUserSelect;
21044     root.style.MozUserSelect = "none";
21045   }
21046 };
21047
21048 function yesdrag(view, noclick) {
21049   var root = view.document.documentElement,
21050       selection$$1 = select(view).on("dragstart.drag", null);
21051   if (noclick) {
21052     selection$$1.on("click.drag", noevent, true);
21053     setTimeout(function() { selection$$1.on("click.drag", null); }, 0);
21054   }
21055   if ("onselectstart" in root) {
21056     selection$$1.on("selectstart.drag", null);
21057   } else {
21058     root.style.MozUserSelect = root.__noselect;
21059     delete root.__noselect;
21060   }
21061 }
21062
21063 var constant$2 = function(x) {
21064   return function() {
21065     return x;
21066   };
21067 };
21068
21069 function DragEvent(target, type, subject, id, active, x, y, dx, dy, dispatch) {
21070   this.target = target;
21071   this.type = type;
21072   this.subject = subject;
21073   this.identifier = id;
21074   this.active = active;
21075   this.x = x;
21076   this.y = y;
21077   this.dx = dx;
21078   this.dy = dy;
21079   this._ = dispatch;
21080 }
21081
21082 DragEvent.prototype.on = function() {
21083   var value = this._.on.apply(this._, arguments);
21084   return value === this._ ? this : value;
21085 };
21086
21087 // Ignore right-click, since that should open the context menu.
21088 function defaultFilter$1() {
21089   return !event.button;
21090 }
21091
21092 function defaultContainer() {
21093   return this.parentNode;
21094 }
21095
21096 function defaultSubject(d) {
21097   return d == null ? {x: event.x, y: event.y} : d;
21098 }
21099
21100 var drag = function() {
21101   var filter = defaultFilter$1,
21102       container = defaultContainer,
21103       subject = defaultSubject,
21104       gestures = {},
21105       listeners = dispatch("start", "drag", "end"),
21106       active = 0,
21107       mousedownx,
21108       mousedowny,
21109       mousemoving,
21110       touchending,
21111       clickDistance2 = 0;
21112
21113   function drag(selection) {
21114     selection
21115         .on("mousedown.drag", mousedowned)
21116         .on("touchstart.drag", touchstarted)
21117         .on("touchmove.drag", touchmoved)
21118         .on("touchend.drag touchcancel.drag", touchended)
21119         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
21120   }
21121
21122   function mousedowned() {
21123     if (touchending || !filter.apply(this, arguments)) return;
21124     var gesture = beforestart("mouse", container.apply(this, arguments), mouse, this, arguments);
21125     if (!gesture) return;
21126     select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
21127     dragDisable(event.view);
21128     nopropagation();
21129     mousemoving = false;
21130     mousedownx = event.clientX;
21131     mousedowny = event.clientY;
21132     gesture("start");
21133   }
21134
21135   function mousemoved() {
21136     noevent();
21137     if (!mousemoving) {
21138       var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny;
21139       mousemoving = dx * dx + dy * dy > clickDistance2;
21140     }
21141     gestures.mouse("drag");
21142   }
21143
21144   function mouseupped() {
21145     select(event.view).on("mousemove.drag mouseup.drag", null);
21146     yesdrag(event.view, mousemoving);
21147     noevent();
21148     gestures.mouse("end");
21149   }
21150
21151   function touchstarted() {
21152     if (!filter.apply(this, arguments)) return;
21153     var touches$$1 = event.changedTouches,
21154         c = container.apply(this, arguments),
21155         n = touches$$1.length, i, gesture;
21156
21157     for (i = 0; i < n; ++i) {
21158       if (gesture = beforestart(touches$$1[i].identifier, c, touch, this, arguments)) {
21159         nopropagation();
21160         gesture("start");
21161       }
21162     }
21163   }
21164
21165   function touchmoved() {
21166     var touches$$1 = event.changedTouches,
21167         n = touches$$1.length, i, gesture;
21168
21169     for (i = 0; i < n; ++i) {
21170       if (gesture = gestures[touches$$1[i].identifier]) {
21171         noevent();
21172         gesture("drag");
21173       }
21174     }
21175   }
21176
21177   function touchended() {
21178     var touches$$1 = event.changedTouches,
21179         n = touches$$1.length, i, gesture;
21180
21181     if (touchending) clearTimeout(touchending);
21182     touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
21183     for (i = 0; i < n; ++i) {
21184       if (gesture = gestures[touches$$1[i].identifier]) {
21185         nopropagation();
21186         gesture("end");
21187       }
21188     }
21189   }
21190
21191   function beforestart(id, container, point, that, args) {
21192     var p = point(container, id), s, dx, dy,
21193         sublisteners = listeners.copy();
21194
21195     if (!customEvent(new DragEvent(drag, "beforestart", s, id, active, p[0], p[1], 0, 0, sublisteners), function() {
21196       if ((event.subject = s = subject.apply(that, args)) == null) return false;
21197       dx = s.x - p[0] || 0;
21198       dy = s.y - p[1] || 0;
21199       return true;
21200     })) return;
21201
21202     return function gesture(type) {
21203       var p0 = p, n;
21204       switch (type) {
21205         case "start": gestures[id] = gesture, n = active++; break;
21206         case "end": delete gestures[id], --active; // nobreak
21207         case "drag": p = point(container, id), n = active; break;
21208       }
21209       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]);
21210     };
21211   }
21212
21213   drag.filter = function(_) {
21214     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$2(!!_), drag) : filter;
21215   };
21216
21217   drag.container = function(_) {
21218     return arguments.length ? (container = typeof _ === "function" ? _ : constant$2(_), drag) : container;
21219   };
21220
21221   drag.subject = function(_) {
21222     return arguments.length ? (subject = typeof _ === "function" ? _ : constant$2(_), drag) : subject;
21223   };
21224
21225   drag.on = function() {
21226     var value = listeners.on.apply(listeners, arguments);
21227     return value === listeners ? drag : value;
21228   };
21229
21230   drag.clickDistance = function(_) {
21231     return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
21232   };
21233
21234   return drag;
21235 };
21236
21237 var define = function(constructor, factory, prototype) {
21238   constructor.prototype = factory.prototype = prototype;
21239   prototype.constructor = constructor;
21240 };
21241
21242 function extend(parent, definition) {
21243   var prototype = Object.create(parent.prototype);
21244   for (var key in definition) prototype[key] = definition[key];
21245   return prototype;
21246 }
21247
21248 function Color() {}
21249
21250 var darker = 0.7;
21251 var brighter = 1 / darker;
21252
21253 var reI = "\\s*([+-]?\\d+)\\s*";
21254 var reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*";
21255 var reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*";
21256 var reHex3 = /^#([0-9a-f]{3})$/;
21257 var reHex6 = /^#([0-9a-f]{6})$/;
21258 var reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$");
21259 var reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$");
21260 var reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$");
21261 var reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$");
21262 var reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$");
21263 var reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
21264
21265 var named = {
21266   aliceblue: 0xf0f8ff,
21267   antiquewhite: 0xfaebd7,
21268   aqua: 0x00ffff,
21269   aquamarine: 0x7fffd4,
21270   azure: 0xf0ffff,
21271   beige: 0xf5f5dc,
21272   bisque: 0xffe4c4,
21273   black: 0x000000,
21274   blanchedalmond: 0xffebcd,
21275   blue: 0x0000ff,
21276   blueviolet: 0x8a2be2,
21277   brown: 0xa52a2a,
21278   burlywood: 0xdeb887,
21279   cadetblue: 0x5f9ea0,
21280   chartreuse: 0x7fff00,
21281   chocolate: 0xd2691e,
21282   coral: 0xff7f50,
21283   cornflowerblue: 0x6495ed,
21284   cornsilk: 0xfff8dc,
21285   crimson: 0xdc143c,
21286   cyan: 0x00ffff,
21287   darkblue: 0x00008b,
21288   darkcyan: 0x008b8b,
21289   darkgoldenrod: 0xb8860b,
21290   darkgray: 0xa9a9a9,
21291   darkgreen: 0x006400,
21292   darkgrey: 0xa9a9a9,
21293   darkkhaki: 0xbdb76b,
21294   darkmagenta: 0x8b008b,
21295   darkolivegreen: 0x556b2f,
21296   darkorange: 0xff8c00,
21297   darkorchid: 0x9932cc,
21298   darkred: 0x8b0000,
21299   darksalmon: 0xe9967a,
21300   darkseagreen: 0x8fbc8f,
21301   darkslateblue: 0x483d8b,
21302   darkslategray: 0x2f4f4f,
21303   darkslategrey: 0x2f4f4f,
21304   darkturquoise: 0x00ced1,
21305   darkviolet: 0x9400d3,
21306   deeppink: 0xff1493,
21307   deepskyblue: 0x00bfff,
21308   dimgray: 0x696969,
21309   dimgrey: 0x696969,
21310   dodgerblue: 0x1e90ff,
21311   firebrick: 0xb22222,
21312   floralwhite: 0xfffaf0,
21313   forestgreen: 0x228b22,
21314   fuchsia: 0xff00ff,
21315   gainsboro: 0xdcdcdc,
21316   ghostwhite: 0xf8f8ff,
21317   gold: 0xffd700,
21318   goldenrod: 0xdaa520,
21319   gray: 0x808080,
21320   green: 0x008000,
21321   greenyellow: 0xadff2f,
21322   grey: 0x808080,
21323   honeydew: 0xf0fff0,
21324   hotpink: 0xff69b4,
21325   indianred: 0xcd5c5c,
21326   indigo: 0x4b0082,
21327   ivory: 0xfffff0,
21328   khaki: 0xf0e68c,
21329   lavender: 0xe6e6fa,
21330   lavenderblush: 0xfff0f5,
21331   lawngreen: 0x7cfc00,
21332   lemonchiffon: 0xfffacd,
21333   lightblue: 0xadd8e6,
21334   lightcoral: 0xf08080,
21335   lightcyan: 0xe0ffff,
21336   lightgoldenrodyellow: 0xfafad2,
21337   lightgray: 0xd3d3d3,
21338   lightgreen: 0x90ee90,
21339   lightgrey: 0xd3d3d3,
21340   lightpink: 0xffb6c1,
21341   lightsalmon: 0xffa07a,
21342   lightseagreen: 0x20b2aa,
21343   lightskyblue: 0x87cefa,
21344   lightslategray: 0x778899,
21345   lightslategrey: 0x778899,
21346   lightsteelblue: 0xb0c4de,
21347   lightyellow: 0xffffe0,
21348   lime: 0x00ff00,
21349   limegreen: 0x32cd32,
21350   linen: 0xfaf0e6,
21351   magenta: 0xff00ff,
21352   maroon: 0x800000,
21353   mediumaquamarine: 0x66cdaa,
21354   mediumblue: 0x0000cd,
21355   mediumorchid: 0xba55d3,
21356   mediumpurple: 0x9370db,
21357   mediumseagreen: 0x3cb371,
21358   mediumslateblue: 0x7b68ee,
21359   mediumspringgreen: 0x00fa9a,
21360   mediumturquoise: 0x48d1cc,
21361   mediumvioletred: 0xc71585,
21362   midnightblue: 0x191970,
21363   mintcream: 0xf5fffa,
21364   mistyrose: 0xffe4e1,
21365   moccasin: 0xffe4b5,
21366   navajowhite: 0xffdead,
21367   navy: 0x000080,
21368   oldlace: 0xfdf5e6,
21369   olive: 0x808000,
21370   olivedrab: 0x6b8e23,
21371   orange: 0xffa500,
21372   orangered: 0xff4500,
21373   orchid: 0xda70d6,
21374   palegoldenrod: 0xeee8aa,
21375   palegreen: 0x98fb98,
21376   paleturquoise: 0xafeeee,
21377   palevioletred: 0xdb7093,
21378   papayawhip: 0xffefd5,
21379   peachpuff: 0xffdab9,
21380   peru: 0xcd853f,
21381   pink: 0xffc0cb,
21382   plum: 0xdda0dd,
21383   powderblue: 0xb0e0e6,
21384   purple: 0x800080,
21385   rebeccapurple: 0x663399,
21386   red: 0xff0000,
21387   rosybrown: 0xbc8f8f,
21388   royalblue: 0x4169e1,
21389   saddlebrown: 0x8b4513,
21390   salmon: 0xfa8072,
21391   sandybrown: 0xf4a460,
21392   seagreen: 0x2e8b57,
21393   seashell: 0xfff5ee,
21394   sienna: 0xa0522d,
21395   silver: 0xc0c0c0,
21396   skyblue: 0x87ceeb,
21397   slateblue: 0x6a5acd,
21398   slategray: 0x708090,
21399   slategrey: 0x708090,
21400   snow: 0xfffafa,
21401   springgreen: 0x00ff7f,
21402   steelblue: 0x4682b4,
21403   tan: 0xd2b48c,
21404   teal: 0x008080,
21405   thistle: 0xd8bfd8,
21406   tomato: 0xff6347,
21407   turquoise: 0x40e0d0,
21408   violet: 0xee82ee,
21409   wheat: 0xf5deb3,
21410   white: 0xffffff,
21411   whitesmoke: 0xf5f5f5,
21412   yellow: 0xffff00,
21413   yellowgreen: 0x9acd32
21414 };
21415
21416 define(Color, color, {
21417   displayable: function() {
21418     return this.rgb().displayable();
21419   },
21420   toString: function() {
21421     return this.rgb() + "";
21422   }
21423 });
21424
21425 function color(format) {
21426   var m;
21427   format = (format + "").trim().toLowerCase();
21428   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
21429       : (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000
21430       : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
21431       : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
21432       : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
21433       : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
21434       : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
21435       : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
21436       : named.hasOwnProperty(format) ? rgbn(named[format])
21437       : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
21438       : null;
21439 }
21440
21441 function rgbn(n) {
21442   return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
21443 }
21444
21445 function rgba(r, g, b, a) {
21446   if (a <= 0) r = g = b = NaN;
21447   return new Rgb(r, g, b, a);
21448 }
21449
21450 function rgbConvert(o) {
21451   if (!(o instanceof Color)) o = color(o);
21452   if (!o) return new Rgb;
21453   o = o.rgb();
21454   return new Rgb(o.r, o.g, o.b, o.opacity);
21455 }
21456
21457 function rgb(r, g, b, opacity) {
21458   return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
21459 }
21460
21461 function Rgb(r, g, b, opacity) {
21462   this.r = +r;
21463   this.g = +g;
21464   this.b = +b;
21465   this.opacity = +opacity;
21466 }
21467
21468 define(Rgb, rgb, extend(Color, {
21469   brighter: function(k) {
21470     k = k == null ? brighter : Math.pow(brighter, k);
21471     return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
21472   },
21473   darker: function(k) {
21474     k = k == null ? darker : Math.pow(darker, k);
21475     return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
21476   },
21477   rgb: function() {
21478     return this;
21479   },
21480   displayable: function() {
21481     return (0 <= this.r && this.r <= 255)
21482         && (0 <= this.g && this.g <= 255)
21483         && (0 <= this.b && this.b <= 255)
21484         && (0 <= this.opacity && this.opacity <= 1);
21485   },
21486   toString: function() {
21487     var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
21488     return (a === 1 ? "rgb(" : "rgba(")
21489         + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
21490         + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
21491         + Math.max(0, Math.min(255, Math.round(this.b) || 0))
21492         + (a === 1 ? ")" : ", " + a + ")");
21493   }
21494 }));
21495
21496 function hsla(h, s, l, a) {
21497   if (a <= 0) h = s = l = NaN;
21498   else if (l <= 0 || l >= 1) h = s = NaN;
21499   else if (s <= 0) h = NaN;
21500   return new Hsl(h, s, l, a);
21501 }
21502
21503 function hslConvert(o) {
21504   if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
21505   if (!(o instanceof Color)) o = color(o);
21506   if (!o) return new Hsl;
21507   if (o instanceof Hsl) return o;
21508   o = o.rgb();
21509   var r = o.r / 255,
21510       g = o.g / 255,
21511       b = o.b / 255,
21512       min = Math.min(r, g, b),
21513       max = Math.max(r, g, b),
21514       h = NaN,
21515       s = max - min,
21516       l = (max + min) / 2;
21517   if (s) {
21518     if (r === max) h = (g - b) / s + (g < b) * 6;
21519     else if (g === max) h = (b - r) / s + 2;
21520     else h = (r - g) / s + 4;
21521     s /= l < 0.5 ? max + min : 2 - max - min;
21522     h *= 60;
21523   } else {
21524     s = l > 0 && l < 1 ? 0 : h;
21525   }
21526   return new Hsl(h, s, l, o.opacity);
21527 }
21528
21529 function hsl(h, s, l, opacity) {
21530   return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
21531 }
21532
21533 function Hsl(h, s, l, opacity) {
21534   this.h = +h;
21535   this.s = +s;
21536   this.l = +l;
21537   this.opacity = +opacity;
21538 }
21539
21540 define(Hsl, hsl, extend(Color, {
21541   brighter: function(k) {
21542     k = k == null ? brighter : Math.pow(brighter, k);
21543     return new Hsl(this.h, this.s, this.l * k, this.opacity);
21544   },
21545   darker: function(k) {
21546     k = k == null ? darker : Math.pow(darker, k);
21547     return new Hsl(this.h, this.s, this.l * k, this.opacity);
21548   },
21549   rgb: function() {
21550     var h = this.h % 360 + (this.h < 0) * 360,
21551         s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
21552         l = this.l,
21553         m2 = l + (l < 0.5 ? l : 1 - l) * s,
21554         m1 = 2 * l - m2;
21555     return new Rgb(
21556       hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
21557       hsl2rgb(h, m1, m2),
21558       hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
21559       this.opacity
21560     );
21561   },
21562   displayable: function() {
21563     return (0 <= this.s && this.s <= 1 || isNaN(this.s))
21564         && (0 <= this.l && this.l <= 1)
21565         && (0 <= this.opacity && this.opacity <= 1);
21566   }
21567 }));
21568
21569 /* From FvD 13.37, CSS Color Module Level 3 */
21570 function hsl2rgb(h, m1, m2) {
21571   return (h < 60 ? m1 + (m2 - m1) * h / 60
21572       : h < 180 ? m2
21573       : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60
21574       : m1) * 255;
21575 }
21576
21577 var deg2rad = Math.PI / 180;
21578 var rad2deg = 180 / Math.PI;
21579
21580 var Kn = 18;
21581 var Xn = 0.950470;
21582 var Yn = 1;
21583 var Zn = 1.088830;
21584 var t0 = 4 / 29;
21585 var t1 = 6 / 29;
21586 var t2 = 3 * t1 * t1;
21587 var t3 = t1 * t1 * t1;
21588
21589 function labConvert(o) {
21590   if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
21591   if (o instanceof Hcl) {
21592     var h = o.h * deg2rad;
21593     return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
21594   }
21595   if (!(o instanceof Rgb)) o = rgbConvert(o);
21596   var b = rgb2xyz(o.r),
21597       a = rgb2xyz(o.g),
21598       l = rgb2xyz(o.b),
21599       x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn),
21600       y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn),
21601       z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn);
21602   return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
21603 }
21604
21605 function lab(l, a, b, opacity) {
21606   return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
21607 }
21608
21609 function Lab(l, a, b, opacity) {
21610   this.l = +l;
21611   this.a = +a;
21612   this.b = +b;
21613   this.opacity = +opacity;
21614 }
21615
21616 define(Lab, lab, extend(Color, {
21617   brighter: function(k) {
21618     return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
21619   },
21620   darker: function(k) {
21621     return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
21622   },
21623   rgb: function() {
21624     var y = (this.l + 16) / 116,
21625         x = isNaN(this.a) ? y : y + this.a / 500,
21626         z = isNaN(this.b) ? y : y - this.b / 200;
21627     y = Yn * lab2xyz(y);
21628     x = Xn * lab2xyz(x);
21629     z = Zn * lab2xyz(z);
21630     return new Rgb(
21631       xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB
21632       xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
21633       xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z),
21634       this.opacity
21635     );
21636   }
21637 }));
21638
21639 function xyz2lab(t) {
21640   return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
21641 }
21642
21643 function lab2xyz(t) {
21644   return t > t1 ? t * t * t : t2 * (t - t0);
21645 }
21646
21647 function xyz2rgb(x) {
21648   return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
21649 }
21650
21651 function rgb2xyz(x) {
21652   return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
21653 }
21654
21655 function hclConvert(o) {
21656   if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
21657   if (!(o instanceof Lab)) o = labConvert(o);
21658   var h = Math.atan2(o.b, o.a) * rad2deg;
21659   return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
21660 }
21661
21662 function hcl(h, c, l, opacity) {
21663   return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
21664 }
21665
21666 function Hcl(h, c, l, opacity) {
21667   this.h = +h;
21668   this.c = +c;
21669   this.l = +l;
21670   this.opacity = +opacity;
21671 }
21672
21673 define(Hcl, hcl, extend(Color, {
21674   brighter: function(k) {
21675     return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity);
21676   },
21677   darker: function(k) {
21678     return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity);
21679   },
21680   rgb: function() {
21681     return labConvert(this).rgb();
21682   }
21683 }));
21684
21685 var A = -0.14861;
21686 var B = +1.78277;
21687 var C = -0.29227;
21688 var D = -0.90649;
21689 var E = +1.97294;
21690 var ED = E * D;
21691 var EB = E * B;
21692 var BC_DA = B * C - D * A;
21693
21694 function cubehelixConvert(o) {
21695   if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
21696   if (!(o instanceof Rgb)) o = rgbConvert(o);
21697   var r = o.r / 255,
21698       g = o.g / 255,
21699       b = o.b / 255,
21700       l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
21701       bl = b - l,
21702       k = (E * (g - l) - C * bl) / D,
21703       s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
21704       h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
21705   return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
21706 }
21707
21708 function cubehelix(h, s, l, opacity) {
21709   return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
21710 }
21711
21712 function Cubehelix(h, s, l, opacity) {
21713   this.h = +h;
21714   this.s = +s;
21715   this.l = +l;
21716   this.opacity = +opacity;
21717 }
21718
21719 define(Cubehelix, cubehelix, extend(Color, {
21720   brighter: function(k) {
21721     k = k == null ? brighter : Math.pow(brighter, k);
21722     return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
21723   },
21724   darker: function(k) {
21725     k = k == null ? darker : Math.pow(darker, k);
21726     return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
21727   },
21728   rgb: function() {
21729     var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,
21730         l = +this.l,
21731         a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
21732         cosh = Math.cos(h),
21733         sinh = Math.sin(h);
21734     return new Rgb(
21735       255 * (l + a * (A * cosh + B * sinh)),
21736       255 * (l + a * (C * cosh + D * sinh)),
21737       255 * (l + a * (E * cosh)),
21738       this.opacity
21739     );
21740   }
21741 }));
21742
21743 function basis(t1, v0, v1, v2, v3) {
21744   var t2 = t1 * t1, t3 = t2 * t1;
21745   return ((1 - 3 * t1 + 3 * t2 - t3) * v0
21746       + (4 - 6 * t2 + 3 * t3) * v1
21747       + (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
21748       + t3 * v3) / 6;
21749 }
21750
21751 var basis$1 = function(values) {
21752   var n = values.length - 1;
21753   return function(t) {
21754     var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),
21755         v1 = values[i],
21756         v2 = values[i + 1],
21757         v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,
21758         v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
21759     return basis((t - i / n) * n, v0, v1, v2, v3);
21760   };
21761 };
21762
21763 var basisClosed = function(values) {
21764   var n = values.length;
21765   return function(t) {
21766     var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),
21767         v0 = values[(i + n - 1) % n],
21768         v1 = values[i % n],
21769         v2 = values[(i + 1) % n],
21770         v3 = values[(i + 2) % n];
21771     return basis((t - i / n) * n, v0, v1, v2, v3);
21772   };
21773 };
21774
21775 var constant$3 = function(x) {
21776   return function() {
21777     return x;
21778   };
21779 };
21780
21781 function linear(a, d) {
21782   return function(t) {
21783     return a + t * d;
21784   };
21785 }
21786
21787 function exponential(a, b, y) {
21788   return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
21789     return Math.pow(a + t * b, y);
21790   };
21791 }
21792
21793 function hue(a, b) {
21794   var d = b - a;
21795   return d ? linear(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$3(isNaN(a) ? b : a);
21796 }
21797
21798 function gamma(y) {
21799   return (y = +y) === 1 ? nogamma : function(a, b) {
21800     return b - a ? exponential(a, b, y) : constant$3(isNaN(a) ? b : a);
21801   };
21802 }
21803
21804 function nogamma(a, b) {
21805   var d = b - a;
21806   return d ? linear(a, d) : constant$3(isNaN(a) ? b : a);
21807 }
21808
21809 var interpolateRgb = ((function rgbGamma(y) {
21810   var color$$1 = gamma(y);
21811
21812   function rgb$$1(start, end) {
21813     var r = color$$1((start = rgb(start)).r, (end = rgb(end)).r),
21814         g = color$$1(start.g, end.g),
21815         b = color$$1(start.b, end.b),
21816         opacity = nogamma(start.opacity, end.opacity);
21817     return function(t) {
21818       start.r = r(t);
21819       start.g = g(t);
21820       start.b = b(t);
21821       start.opacity = opacity(t);
21822       return start + "";
21823     };
21824   }
21825
21826   rgb$$1.gamma = rgbGamma;
21827
21828   return rgb$$1;
21829 }))(1);
21830
21831 function rgbSpline(spline) {
21832   return function(colors) {
21833     var n = colors.length,
21834         r = new Array(n),
21835         g = new Array(n),
21836         b = new Array(n),
21837         i, color$$1;
21838     for (i = 0; i < n; ++i) {
21839       color$$1 = rgb(colors[i]);
21840       r[i] = color$$1.r || 0;
21841       g[i] = color$$1.g || 0;
21842       b[i] = color$$1.b || 0;
21843     }
21844     r = spline(r);
21845     g = spline(g);
21846     b = spline(b);
21847     color$$1.opacity = 1;
21848     return function(t) {
21849       color$$1.r = r(t);
21850       color$$1.g = g(t);
21851       color$$1.b = b(t);
21852       return color$$1 + "";
21853     };
21854   };
21855 }
21856
21857 var rgbBasis = rgbSpline(basis$1);
21858 var rgbBasisClosed = rgbSpline(basisClosed);
21859
21860 var array$1 = function(a, b) {
21861   var nb = b ? b.length : 0,
21862       na = a ? Math.min(nb, a.length) : 0,
21863       x = new Array(nb),
21864       c = new Array(nb),
21865       i;
21866
21867   for (i = 0; i < na; ++i) x[i] = interpolateValue(a[i], b[i]);
21868   for (; i < nb; ++i) c[i] = b[i];
21869
21870   return function(t) {
21871     for (i = 0; i < na; ++i) c[i] = x[i](t);
21872     return c;
21873   };
21874 };
21875
21876 var date = function(a, b) {
21877   var d = new Date;
21878   return a = +a, b -= a, function(t) {
21879     return d.setTime(a + b * t), d;
21880   };
21881 };
21882
21883 var reinterpolate = function(a, b) {
21884   return a = +a, b -= a, function(t) {
21885     return a + b * t;
21886   };
21887 };
21888
21889 var object = function(a, b) {
21890   var i = {},
21891       c = {},
21892       k;
21893
21894   if (a === null || typeof a !== "object") a = {};
21895   if (b === null || typeof b !== "object") b = {};
21896
21897   for (k in b) {
21898     if (k in a) {
21899       i[k] = interpolateValue(a[k], b[k]);
21900     } else {
21901       c[k] = b[k];
21902     }
21903   }
21904
21905   return function(t) {
21906     for (k in i) c[k] = i[k](t);
21907     return c;
21908   };
21909 };
21910
21911 var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
21912 var reB = new RegExp(reA.source, "g");
21913
21914 function zero(b) {
21915   return function() {
21916     return b;
21917   };
21918 }
21919
21920 function one(b) {
21921   return function(t) {
21922     return b(t) + "";
21923   };
21924 }
21925
21926 var interpolateString = function(a, b) {
21927   var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
21928       am, // current match in a
21929       bm, // current match in b
21930       bs, // string preceding current number in b, if any
21931       i = -1, // index in s
21932       s = [], // string constants and placeholders
21933       q = []; // number interpolators
21934
21935   // Coerce inputs to strings.
21936   a = a + "", b = b + "";
21937
21938   // Interpolate pairs of numbers in a & b.
21939   while ((am = reA.exec(a))
21940       && (bm = reB.exec(b))) {
21941     if ((bs = bm.index) > bi) { // a string precedes the next number in b
21942       bs = b.slice(bi, bs);
21943       if (s[i]) s[i] += bs; // coalesce with previous string
21944       else s[++i] = bs;
21945     }
21946     if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
21947       if (s[i]) s[i] += bm; // coalesce with previous string
21948       else s[++i] = bm;
21949     } else { // interpolate non-matching numbers
21950       s[++i] = null;
21951       q.push({i: i, x: reinterpolate(am, bm)});
21952     }
21953     bi = reB.lastIndex;
21954   }
21955
21956   // Add remains of b.
21957   if (bi < b.length) {
21958     bs = b.slice(bi);
21959     if (s[i]) s[i] += bs; // coalesce with previous string
21960     else s[++i] = bs;
21961   }
21962
21963   // Special optimization for only a single match.
21964   // Otherwise, interpolate each of the numbers and rejoin the string.
21965   return s.length < 2 ? (q[0]
21966       ? one(q[0].x)
21967       : zero(b))
21968       : (b = q.length, function(t) {
21969           for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
21970           return s.join("");
21971         });
21972 };
21973
21974 var interpolateValue = function(a, b) {
21975   var t = typeof b, c;
21976   return b == null || t === "boolean" ? constant$3(b)
21977       : (t === "number" ? reinterpolate
21978       : t === "string" ? ((c = color(b)) ? (b = c, interpolateRgb) : interpolateString)
21979       : b instanceof color ? interpolateRgb
21980       : b instanceof Date ? date
21981       : Array.isArray(b) ? array$1
21982       : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object
21983       : reinterpolate)(a, b);
21984 };
21985
21986 var interpolateRound = function(a, b) {
21987   return a = +a, b -= a, function(t) {
21988     return Math.round(a + b * t);
21989   };
21990 };
21991
21992 var degrees = 180 / Math.PI;
21993
21994 var identity$2 = {
21995   translateX: 0,
21996   translateY: 0,
21997   rotate: 0,
21998   skewX: 0,
21999   scaleX: 1,
22000   scaleY: 1
22001 };
22002
22003 var decompose = function(a, b, c, d, e, f) {
22004   var scaleX, scaleY, skewX;
22005   if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
22006   if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
22007   if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
22008   if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
22009   return {
22010     translateX: e,
22011     translateY: f,
22012     rotate: Math.atan2(b, a) * degrees,
22013     skewX: Math.atan(skewX) * degrees,
22014     scaleX: scaleX,
22015     scaleY: scaleY
22016   };
22017 };
22018
22019 var cssNode;
22020 var cssRoot;
22021 var cssView;
22022 var svgNode;
22023
22024 function parseCss(value) {
22025   if (value === "none") return identity$2;
22026   if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView;
22027   cssNode.style.transform = value;
22028   value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform");
22029   cssRoot.removeChild(cssNode);
22030   value = value.slice(7, -1).split(",");
22031   return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]);
22032 }
22033
22034 function parseSvg(value) {
22035   if (value == null) return identity$2;
22036   if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
22037   svgNode.setAttribute("transform", value);
22038   if (!(value = svgNode.transform.baseVal.consolidate())) return identity$2;
22039   value = value.matrix;
22040   return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
22041 }
22042
22043 function interpolateTransform(parse, pxComma, pxParen, degParen) {
22044
22045   function pop(s) {
22046     return s.length ? s.pop() + " " : "";
22047   }
22048
22049   function translate(xa, ya, xb, yb, s, q) {
22050     if (xa !== xb || ya !== yb) {
22051       var i = s.push("translate(", null, pxComma, null, pxParen);
22052       q.push({i: i - 4, x: reinterpolate(xa, xb)}, {i: i - 2, x: reinterpolate(ya, yb)});
22053     } else if (xb || yb) {
22054       s.push("translate(" + xb + pxComma + yb + pxParen);
22055     }
22056   }
22057
22058   function rotate(a, b, s, q) {
22059     if (a !== b) {
22060       if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path
22061       q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: reinterpolate(a, b)});
22062     } else if (b) {
22063       s.push(pop(s) + "rotate(" + b + degParen);
22064     }
22065   }
22066
22067   function skewX(a, b, s, q) {
22068     if (a !== b) {
22069       q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: reinterpolate(a, b)});
22070     } else if (b) {
22071       s.push(pop(s) + "skewX(" + b + degParen);
22072     }
22073   }
22074
22075   function scale(xa, ya, xb, yb, s, q) {
22076     if (xa !== xb || ya !== yb) {
22077       var i = s.push(pop(s) + "scale(", null, ",", null, ")");
22078       q.push({i: i - 4, x: reinterpolate(xa, xb)}, {i: i - 2, x: reinterpolate(ya, yb)});
22079     } else if (xb !== 1 || yb !== 1) {
22080       s.push(pop(s) + "scale(" + xb + "," + yb + ")");
22081     }
22082   }
22083
22084   return function(a, b) {
22085     var s = [], // string constants and placeholders
22086         q = []; // number interpolators
22087     a = parse(a), b = parse(b);
22088     translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
22089     rotate(a.rotate, b.rotate, s, q);
22090     skewX(a.skewX, b.skewX, s, q);
22091     scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
22092     a = b = null; // gc
22093     return function(t) {
22094       var i = -1, n = q.length, o;
22095       while (++i < n) s[(o = q[i]).i] = o.x(t);
22096       return s.join("");
22097     };
22098   };
22099 }
22100
22101 var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
22102 var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
22103
22104 var rho = Math.SQRT2;
22105 var rho2 = 2;
22106 var rho4 = 4;
22107 var epsilon2 = 1e-12;
22108
22109 function cosh(x) {
22110   return ((x = Math.exp(x)) + 1 / x) / 2;
22111 }
22112
22113 function sinh(x) {
22114   return ((x = Math.exp(x)) - 1 / x) / 2;
22115 }
22116
22117 function tanh(x) {
22118   return ((x = Math.exp(2 * x)) - 1) / (x + 1);
22119 }
22120
22121 // p0 = [ux0, uy0, w0]
22122 // p1 = [ux1, uy1, w1]
22123 var interpolateZoom = function(p0, p1) {
22124   var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
22125       ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
22126       dx = ux1 - ux0,
22127       dy = uy1 - uy0,
22128       d2 = dx * dx + dy * dy,
22129       i,
22130       S;
22131
22132   // Special case for u0 ≅ u1.
22133   if (d2 < epsilon2) {
22134     S = Math.log(w1 / w0) / rho;
22135     i = function(t) {
22136       return [
22137         ux0 + t * dx,
22138         uy0 + t * dy,
22139         w0 * Math.exp(rho * t * S)
22140       ];
22141     };
22142   }
22143
22144   // General case.
22145   else {
22146     var d1 = Math.sqrt(d2),
22147         b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
22148         b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
22149         r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
22150         r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
22151     S = (r1 - r0) / rho;
22152     i = function(t) {
22153       var s = t * S,
22154           coshr0 = cosh(r0),
22155           u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
22156       return [
22157         ux0 + u * dx,
22158         uy0 + u * dy,
22159         w0 * coshr0 / cosh(rho * s + r0)
22160       ];
22161     };
22162   }
22163
22164   i.duration = S * 1000;
22165
22166   return i;
22167 };
22168
22169 function hsl$1(hue$$1) {
22170   return function(start, end) {
22171     var h = hue$$1((start = hsl(start)).h, (end = hsl(end)).h),
22172         s = nogamma(start.s, end.s),
22173         l = nogamma(start.l, end.l),
22174         opacity = nogamma(start.opacity, end.opacity);
22175     return function(t) {
22176       start.h = h(t);
22177       start.s = s(t);
22178       start.l = l(t);
22179       start.opacity = opacity(t);
22180       return start + "";
22181     };
22182   }
22183 }
22184
22185 var hsl$2 = hsl$1(hue);
22186 var hslLong = hsl$1(nogamma);
22187
22188 function lab$1(start, end) {
22189   var l = nogamma((start = lab(start)).l, (end = lab(end)).l),
22190       a = nogamma(start.a, end.a),
22191       b = nogamma(start.b, end.b),
22192       opacity = nogamma(start.opacity, end.opacity);
22193   return function(t) {
22194     start.l = l(t);
22195     start.a = a(t);
22196     start.b = b(t);
22197     start.opacity = opacity(t);
22198     return start + "";
22199   };
22200 }
22201
22202 function hcl$1(hue$$1) {
22203   return function(start, end) {
22204     var h = hue$$1((start = hcl(start)).h, (end = hcl(end)).h),
22205         c = nogamma(start.c, end.c),
22206         l = nogamma(start.l, end.l),
22207         opacity = nogamma(start.opacity, end.opacity);
22208     return function(t) {
22209       start.h = h(t);
22210       start.c = c(t);
22211       start.l = l(t);
22212       start.opacity = opacity(t);
22213       return start + "";
22214     };
22215   }
22216 }
22217
22218 var hcl$2 = hcl$1(hue);
22219 var hclLong = hcl$1(nogamma);
22220
22221 function cubehelix$1(hue$$1) {
22222   return (function cubehelixGamma(y) {
22223     y = +y;
22224
22225     function cubehelix$$1(start, end) {
22226       var h = hue$$1((start = cubehelix(start)).h, (end = cubehelix(end)).h),
22227           s = nogamma(start.s, end.s),
22228           l = nogamma(start.l, end.l),
22229           opacity = nogamma(start.opacity, end.opacity);
22230       return function(t) {
22231         start.h = h(t);
22232         start.s = s(t);
22233         start.l = l(Math.pow(t, y));
22234         start.opacity = opacity(t);
22235         return start + "";
22236       };
22237     }
22238
22239     cubehelix$$1.gamma = cubehelixGamma;
22240
22241     return cubehelix$$1;
22242   })(1);
22243 }
22244
22245 var cubehelix$2 = cubehelix$1(hue);
22246 var cubehelixLong = cubehelix$1(nogamma);
22247
22248 var quantize = function(interpolator, n) {
22249   var samples = new Array(n);
22250   for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));
22251   return samples;
22252 };
22253
22254 var frame = 0;
22255 var timeout = 0;
22256 var interval = 0;
22257 var pokeDelay = 1000;
22258 var taskHead;
22259 var taskTail;
22260 var clockLast = 0;
22261 var clockNow = 0;
22262 var clockSkew = 0;
22263 var clock = typeof performance === "object" && performance.now ? performance : Date;
22264 var setFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : function(f) { setTimeout(f, 17); };
22265
22266 function now() {
22267   return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
22268 }
22269
22270 function clearNow() {
22271   clockNow = 0;
22272 }
22273
22274 function Timer() {
22275   this._call =
22276   this._time =
22277   this._next = null;
22278 }
22279
22280 Timer.prototype = timer.prototype = {
22281   constructor: Timer,
22282   restart: function(callback, delay, time) {
22283     if (typeof callback !== "function") throw new TypeError("callback is not a function");
22284     time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
22285     if (!this._next && taskTail !== this) {
22286       if (taskTail) taskTail._next = this;
22287       else taskHead = this;
22288       taskTail = this;
22289     }
22290     this._call = callback;
22291     this._time = time;
22292     sleep();
22293   },
22294   stop: function() {
22295     if (this._call) {
22296       this._call = null;
22297       this._time = Infinity;
22298       sleep();
22299     }
22300   }
22301 };
22302
22303 function timer(callback, delay, time) {
22304   var t = new Timer;
22305   t.restart(callback, delay, time);
22306   return t;
22307 }
22308
22309 function timerFlush() {
22310   now(); // Get the current time, if not already set.
22311   ++frame; // Pretend we’ve set an alarm, if we haven’t already.
22312   var t = taskHead, e;
22313   while (t) {
22314     if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
22315     t = t._next;
22316   }
22317   --frame;
22318 }
22319
22320 function wake() {
22321   clockNow = (clockLast = clock.now()) + clockSkew;
22322   frame = timeout = 0;
22323   try {
22324     timerFlush();
22325   } finally {
22326     frame = 0;
22327     nap();
22328     clockNow = 0;
22329   }
22330 }
22331
22332 function poke() {
22333   var now = clock.now(), delay = now - clockLast;
22334   if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
22335 }
22336
22337 function nap() {
22338   var t0, t1 = taskHead, t2, time = Infinity;
22339   while (t1) {
22340     if (t1._call) {
22341       if (time > t1._time) time = t1._time;
22342       t0 = t1, t1 = t1._next;
22343     } else {
22344       t2 = t1._next, t1._next = null;
22345       t1 = t0 ? t0._next = t2 : taskHead = t2;
22346     }
22347   }
22348   taskTail = t0;
22349   sleep(time);
22350 }
22351
22352 function sleep(time) {
22353   if (frame) return; // Soonest alarm already set, or will be.
22354   if (timeout) timeout = clearTimeout(timeout);
22355   var delay = time - clockNow;
22356   if (delay > 24) {
22357     if (time < Infinity) timeout = setTimeout(wake, delay);
22358     if (interval) interval = clearInterval(interval);
22359   } else {
22360     if (!interval) clockLast = clockNow, interval = setInterval(poke, pokeDelay);
22361     frame = 1, setFrame(wake);
22362   }
22363 }
22364
22365 var timeout$1 = function(callback, delay, time) {
22366   var t = new Timer;
22367   delay = delay == null ? 0 : +delay;
22368   t.restart(function(elapsed) {
22369     t.stop();
22370     callback(elapsed + delay);
22371   }, delay, time);
22372   return t;
22373 };
22374
22375 var interval$1 = function(callback, delay, time) {
22376   var t = new Timer, total = delay;
22377   if (delay == null) return t.restart(callback, delay, time), t;
22378   delay = +delay, time = time == null ? now() : +time;
22379   t.restart(function tick(elapsed) {
22380     elapsed += total;
22381     t.restart(tick, total += delay, time);
22382     callback(elapsed);
22383   }, delay, time);
22384   return t;
22385 };
22386
22387 var emptyOn = dispatch("start", "end", "interrupt");
22388 var emptyTween = [];
22389
22390 var CREATED = 0;
22391 var SCHEDULED = 1;
22392 var STARTING = 2;
22393 var STARTED = 3;
22394 var RUNNING = 4;
22395 var ENDING = 5;
22396 var ENDED = 6;
22397
22398 var schedule = function(node, name, id, index, group, timing) {
22399   var schedules = node.__transition;
22400   if (!schedules) node.__transition = {};
22401   else if (id in schedules) return;
22402   create(node, id, {
22403     name: name,
22404     index: index, // For context during callback.
22405     group: group, // For context during callback.
22406     on: emptyOn,
22407     tween: emptyTween,
22408     time: timing.time,
22409     delay: timing.delay,
22410     duration: timing.duration,
22411     ease: timing.ease,
22412     timer: null,
22413     state: CREATED
22414   });
22415 };
22416
22417 function init(node, id) {
22418   var schedule = node.__transition;
22419   if (!schedule || !(schedule = schedule[id]) || schedule.state > CREATED) throw new Error("too late");
22420   return schedule;
22421 }
22422
22423 function set$1(node, id) {
22424   var schedule = node.__transition;
22425   if (!schedule || !(schedule = schedule[id]) || schedule.state > STARTING) throw new Error("too late");
22426   return schedule;
22427 }
22428
22429 function get$1(node, id) {
22430   var schedule = node.__transition;
22431   if (!schedule || !(schedule = schedule[id])) throw new Error("too late");
22432   return schedule;
22433 }
22434
22435 function create(node, id, self) {
22436   var schedules = node.__transition,
22437       tween;
22438
22439   // Initialize the self timer when the transition is created.
22440   // Note the actual delay is not known until the first callback!
22441   schedules[id] = self;
22442   self.timer = timer(schedule, 0, self.time);
22443
22444   function schedule(elapsed) {
22445     self.state = SCHEDULED;
22446     self.timer.restart(start, self.delay, self.time);
22447
22448     // If the elapsed delay is less than our first sleep, start immediately.
22449     if (self.delay <= elapsed) start(elapsed - self.delay);
22450   }
22451
22452   function start(elapsed) {
22453     var i, j, n, o;
22454
22455     // If the state is not SCHEDULED, then we previously errored on start.
22456     if (self.state !== SCHEDULED) return stop();
22457
22458     for (i in schedules) {
22459       o = schedules[i];
22460       if (o.name !== self.name) continue;
22461
22462       // While this element already has a starting transition during this frame,
22463       // defer starting an interrupting transition until that transition has a
22464       // chance to tick (and possibly end); see d3/d3-transition#54!
22465       if (o.state === STARTED) return timeout$1(start);
22466
22467       // Interrupt the active transition, if any.
22468       // Dispatch the interrupt event.
22469       if (o.state === RUNNING) {
22470         o.state = ENDED;
22471         o.timer.stop();
22472         o.on.call("interrupt", node, node.__data__, o.index, o.group);
22473         delete schedules[i];
22474       }
22475
22476       // Cancel any pre-empted transitions. No interrupt event is dispatched
22477       // because the cancelled transitions never started. Note that this also
22478       // removes this transition from the pending list!
22479       else if (+i < id) {
22480         o.state = ENDED;
22481         o.timer.stop();
22482         delete schedules[i];
22483       }
22484     }
22485
22486     // Defer the first tick to end of the current frame; see d3/d3#1576.
22487     // Note the transition may be canceled after start and before the first tick!
22488     // Note this must be scheduled before the start event; see d3/d3-transition#16!
22489     // Assuming this is successful, subsequent callbacks go straight to tick.
22490     timeout$1(function() {
22491       if (self.state === STARTED) {
22492         self.state = RUNNING;
22493         self.timer.restart(tick, self.delay, self.time);
22494         tick(elapsed);
22495       }
22496     });
22497
22498     // Dispatch the start event.
22499     // Note this must be done before the tween are initialized.
22500     self.state = STARTING;
22501     self.on.call("start", node, node.__data__, self.index, self.group);
22502     if (self.state !== STARTING) return; // interrupted
22503     self.state = STARTED;
22504
22505     // Initialize the tween, deleting null tween.
22506     tween = new Array(n = self.tween.length);
22507     for (i = 0, j = -1; i < n; ++i) {
22508       if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
22509         tween[++j] = o;
22510       }
22511     }
22512     tween.length = j + 1;
22513   }
22514
22515   function tick(elapsed) {
22516     var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
22517         i = -1,
22518         n = tween.length;
22519
22520     while (++i < n) {
22521       tween[i].call(null, t);
22522     }
22523
22524     // Dispatch the end event.
22525     if (self.state === ENDING) {
22526       self.on.call("end", node, node.__data__, self.index, self.group);
22527       stop();
22528     }
22529   }
22530
22531   function stop() {
22532     self.state = ENDED;
22533     self.timer.stop();
22534     delete schedules[id];
22535     for (var i in schedules) return; // eslint-disable-line no-unused-vars
22536     delete node.__transition;
22537   }
22538 }
22539
22540 var interrupt = function(node, name) {
22541   var schedules = node.__transition,
22542       schedule$$1,
22543       active,
22544       empty = true,
22545       i;
22546
22547   if (!schedules) return;
22548
22549   name = name == null ? null : name + "";
22550
22551   for (i in schedules) {
22552     if ((schedule$$1 = schedules[i]).name !== name) { empty = false; continue; }
22553     active = schedule$$1.state > STARTING && schedule$$1.state < ENDING;
22554     schedule$$1.state = ENDED;
22555     schedule$$1.timer.stop();
22556     if (active) schedule$$1.on.call("interrupt", node, node.__data__, schedule$$1.index, schedule$$1.group);
22557     delete schedules[i];
22558   }
22559
22560   if (empty) delete node.__transition;
22561 };
22562
22563 var selection_interrupt = function(name) {
22564   return this.each(function() {
22565     interrupt(this, name);
22566   });
22567 };
22568
22569 function tweenRemove(id, name) {
22570   var tween0, tween1;
22571   return function() {
22572     var schedule$$1 = set$1(this, id),
22573         tween = schedule$$1.tween;
22574
22575     // If this node shared tween with the previous node,
22576     // just assign the updated shared tween and we’re done!
22577     // Otherwise, copy-on-write.
22578     if (tween !== tween0) {
22579       tween1 = tween0 = tween;
22580       for (var i = 0, n = tween1.length; i < n; ++i) {
22581         if (tween1[i].name === name) {
22582           tween1 = tween1.slice();
22583           tween1.splice(i, 1);
22584           break;
22585         }
22586       }
22587     }
22588
22589     schedule$$1.tween = tween1;
22590   };
22591 }
22592
22593 function tweenFunction(id, name, value) {
22594   var tween0, tween1;
22595   if (typeof value !== "function") throw new Error;
22596   return function() {
22597     var schedule$$1 = set$1(this, id),
22598         tween = schedule$$1.tween;
22599
22600     // If this node shared tween with the previous node,
22601     // just assign the updated shared tween and we’re done!
22602     // Otherwise, copy-on-write.
22603     if (tween !== tween0) {
22604       tween1 = (tween0 = tween).slice();
22605       for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) {
22606         if (tween1[i].name === name) {
22607           tween1[i] = t;
22608           break;
22609         }
22610       }
22611       if (i === n) tween1.push(t);
22612     }
22613
22614     schedule$$1.tween = tween1;
22615   };
22616 }
22617
22618 var transition_tween = function(name, value) {
22619   var id = this._id;
22620
22621   name += "";
22622
22623   if (arguments.length < 2) {
22624     var tween = get$1(this.node(), id).tween;
22625     for (var i = 0, n = tween.length, t; i < n; ++i) {
22626       if ((t = tween[i]).name === name) {
22627         return t.value;
22628       }
22629     }
22630     return null;
22631   }
22632
22633   return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
22634 };
22635
22636 function tweenValue(transition, name, value) {
22637   var id = transition._id;
22638
22639   transition.each(function() {
22640     var schedule$$1 = set$1(this, id);
22641     (schedule$$1.value || (schedule$$1.value = {}))[name] = value.apply(this, arguments);
22642   });
22643
22644   return function(node) {
22645     return get$1(node, id).value[name];
22646   };
22647 }
22648
22649 var interpolate = function(a, b) {
22650   var c;
22651   return (typeof b === "number" ? reinterpolate
22652       : b instanceof color ? interpolateRgb
22653       : (c = color(b)) ? (b = c, interpolateRgb)
22654       : interpolateString)(a, b);
22655 };
22656
22657 function attrRemove$1(name) {
22658   return function() {
22659     this.removeAttribute(name);
22660   };
22661 }
22662
22663 function attrRemoveNS$1(fullname) {
22664   return function() {
22665     this.removeAttributeNS(fullname.space, fullname.local);
22666   };
22667 }
22668
22669 function attrConstant$1(name, interpolate$$1, value1) {
22670   var value00,
22671       interpolate0;
22672   return function() {
22673     var value0 = this.getAttribute(name);
22674     return value0 === value1 ? null
22675         : value0 === value00 ? interpolate0
22676         : interpolate0 = interpolate$$1(value00 = value0, value1);
22677   };
22678 }
22679
22680 function attrConstantNS$1(fullname, interpolate$$1, value1) {
22681   var value00,
22682       interpolate0;
22683   return function() {
22684     var value0 = this.getAttributeNS(fullname.space, fullname.local);
22685     return value0 === value1 ? null
22686         : value0 === value00 ? interpolate0
22687         : interpolate0 = interpolate$$1(value00 = value0, value1);
22688   };
22689 }
22690
22691 function attrFunction$1(name, interpolate$$1, value) {
22692   var value00,
22693       value10,
22694       interpolate0;
22695   return function() {
22696     var value0, value1 = value(this);
22697     if (value1 == null) return void this.removeAttribute(name);
22698     value0 = this.getAttribute(name);
22699     return value0 === value1 ? null
22700         : value0 === value00 && value1 === value10 ? interpolate0
22701         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22702   };
22703 }
22704
22705 function attrFunctionNS$1(fullname, interpolate$$1, value) {
22706   var value00,
22707       value10,
22708       interpolate0;
22709   return function() {
22710     var value0, value1 = value(this);
22711     if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
22712     value0 = this.getAttributeNS(fullname.space, fullname.local);
22713     return value0 === value1 ? null
22714         : value0 === value00 && value1 === value10 ? interpolate0
22715         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22716   };
22717 }
22718
22719 var transition_attr = function(name, value) {
22720   var fullname = namespace(name), i = fullname === "transform" ? interpolateTransformSvg : interpolate;
22721   return this.attrTween(name, typeof value === "function"
22722       ? (fullname.local ? attrFunctionNS$1 : attrFunction$1)(fullname, i, tweenValue(this, "attr." + name, value))
22723       : value == null ? (fullname.local ? attrRemoveNS$1 : attrRemove$1)(fullname)
22724       : (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value + ""));
22725 };
22726
22727 function attrTweenNS(fullname, value) {
22728   function tween() {
22729     var node = this, i = value.apply(node, arguments);
22730     return i && function(t) {
22731       node.setAttributeNS(fullname.space, fullname.local, i(t));
22732     };
22733   }
22734   tween._value = value;
22735   return tween;
22736 }
22737
22738 function attrTween(name, value) {
22739   function tween() {
22740     var node = this, i = value.apply(node, arguments);
22741     return i && function(t) {
22742       node.setAttribute(name, i(t));
22743     };
22744   }
22745   tween._value = value;
22746   return tween;
22747 }
22748
22749 var transition_attrTween = function(name, value) {
22750   var key = "attr." + name;
22751   if (arguments.length < 2) return (key = this.tween(key)) && key._value;
22752   if (value == null) return this.tween(key, null);
22753   if (typeof value !== "function") throw new Error;
22754   var fullname = namespace(name);
22755   return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
22756 };
22757
22758 function delayFunction(id, value) {
22759   return function() {
22760     init(this, id).delay = +value.apply(this, arguments);
22761   };
22762 }
22763
22764 function delayConstant(id, value) {
22765   return value = +value, function() {
22766     init(this, id).delay = value;
22767   };
22768 }
22769
22770 var transition_delay = function(value) {
22771   var id = this._id;
22772
22773   return arguments.length
22774       ? this.each((typeof value === "function"
22775           ? delayFunction
22776           : delayConstant)(id, value))
22777       : get$1(this.node(), id).delay;
22778 };
22779
22780 function durationFunction(id, value) {
22781   return function() {
22782     set$1(this, id).duration = +value.apply(this, arguments);
22783   };
22784 }
22785
22786 function durationConstant(id, value) {
22787   return value = +value, function() {
22788     set$1(this, id).duration = value;
22789   };
22790 }
22791
22792 var transition_duration = function(value) {
22793   var id = this._id;
22794
22795   return arguments.length
22796       ? this.each((typeof value === "function"
22797           ? durationFunction
22798           : durationConstant)(id, value))
22799       : get$1(this.node(), id).duration;
22800 };
22801
22802 function easeConstant(id, value) {
22803   if (typeof value !== "function") throw new Error;
22804   return function() {
22805     set$1(this, id).ease = value;
22806   };
22807 }
22808
22809 var transition_ease = function(value) {
22810   var id = this._id;
22811
22812   return arguments.length
22813       ? this.each(easeConstant(id, value))
22814       : get$1(this.node(), id).ease;
22815 };
22816
22817 var transition_filter = function(match) {
22818   if (typeof match !== "function") match = matcher$1(match);
22819
22820   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
22821     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
22822       if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
22823         subgroup.push(node);
22824       }
22825     }
22826   }
22827
22828   return new Transition(subgroups, this._parents, this._name, this._id);
22829 };
22830
22831 var transition_merge = function(transition$$1) {
22832   if (transition$$1._id !== this._id) throw new Error;
22833
22834   for (var groups0 = this._groups, groups1 = transition$$1._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
22835     for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
22836       if (node = group0[i] || group1[i]) {
22837         merge[i] = node;
22838       }
22839     }
22840   }
22841
22842   for (; j < m0; ++j) {
22843     merges[j] = groups0[j];
22844   }
22845
22846   return new Transition(merges, this._parents, this._name, this._id);
22847 };
22848
22849 function start(name) {
22850   return (name + "").trim().split(/^|\s+/).every(function(t) {
22851     var i = t.indexOf(".");
22852     if (i >= 0) t = t.slice(0, i);
22853     return !t || t === "start";
22854   });
22855 }
22856
22857 function onFunction(id, name, listener) {
22858   var on0, on1, sit = start(name) ? init : set$1;
22859   return function() {
22860     var schedule$$1 = sit(this, id),
22861         on = schedule$$1.on;
22862
22863     // If this node shared a dispatch with the previous node,
22864     // just assign the updated shared dispatch and we’re done!
22865     // Otherwise, copy-on-write.
22866     if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
22867
22868     schedule$$1.on = on1;
22869   };
22870 }
22871
22872 var transition_on = function(name, listener) {
22873   var id = this._id;
22874
22875   return arguments.length < 2
22876       ? get$1(this.node(), id).on.on(name)
22877       : this.each(onFunction(id, name, listener));
22878 };
22879
22880 function removeFunction(id) {
22881   return function() {
22882     var parent = this.parentNode;
22883     for (var i in this.__transition) if (+i !== id) return;
22884     if (parent) parent.removeChild(this);
22885   };
22886 }
22887
22888 var transition_remove = function() {
22889   return this.on("end.remove", removeFunction(this._id));
22890 };
22891
22892 var transition_select = function(select$$1) {
22893   var name = this._name,
22894       id = this._id;
22895
22896   if (typeof select$$1 !== "function") select$$1 = selector(select$$1);
22897
22898   for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
22899     for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
22900       if ((node = group[i]) && (subnode = select$$1.call(node, node.__data__, i, group))) {
22901         if ("__data__" in node) subnode.__data__ = node.__data__;
22902         subgroup[i] = subnode;
22903         schedule(subgroup[i], name, id, i, subgroup, get$1(node, id));
22904       }
22905     }
22906   }
22907
22908   return new Transition(subgroups, this._parents, name, id);
22909 };
22910
22911 var transition_selectAll = function(select$$1) {
22912   var name = this._name,
22913       id = this._id;
22914
22915   if (typeof select$$1 !== "function") select$$1 = selectorAll(select$$1);
22916
22917   for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
22918     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
22919       if (node = group[i]) {
22920         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) {
22921           if (child = children[k]) {
22922             schedule(child, name, id, k, children, inherit);
22923           }
22924         }
22925         subgroups.push(children);
22926         parents.push(node);
22927       }
22928     }
22929   }
22930
22931   return new Transition(subgroups, parents, name, id);
22932 };
22933
22934 var Selection$1 = selection.prototype.constructor;
22935
22936 var transition_selection = function() {
22937   return new Selection$1(this._groups, this._parents);
22938 };
22939
22940 function styleRemove$1(name, interpolate$$1) {
22941   var value00,
22942       value10,
22943       interpolate0;
22944   return function() {
22945     var value0 = styleValue(this, name),
22946         value1 = (this.style.removeProperty(name), styleValue(this, name));
22947     return value0 === value1 ? null
22948         : value0 === value00 && value1 === value10 ? interpolate0
22949         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22950   };
22951 }
22952
22953 function styleRemoveEnd(name) {
22954   return function() {
22955     this.style.removeProperty(name);
22956   };
22957 }
22958
22959 function styleConstant$1(name, interpolate$$1, value1) {
22960   var value00,
22961       interpolate0;
22962   return function() {
22963     var value0 = styleValue(this, name);
22964     return value0 === value1 ? null
22965         : value0 === value00 ? interpolate0
22966         : interpolate0 = interpolate$$1(value00 = value0, value1);
22967   };
22968 }
22969
22970 function styleFunction$1(name, interpolate$$1, value) {
22971   var value00,
22972       value10,
22973       interpolate0;
22974   return function() {
22975     var value0 = styleValue(this, name),
22976         value1 = value(this);
22977     if (value1 == null) value1 = (this.style.removeProperty(name), styleValue(this, name));
22978     return value0 === value1 ? null
22979         : value0 === value00 && value1 === value10 ? interpolate0
22980         : interpolate0 = interpolate$$1(value00 = value0, value10 = value1);
22981   };
22982 }
22983
22984 var transition_style = function(name, value, priority) {
22985   var i = (name += "") === "transform" ? interpolateTransformCss : interpolate;
22986   return value == null ? this
22987           .styleTween(name, styleRemove$1(name, i))
22988           .on("end.style." + name, styleRemoveEnd(name))
22989       : this.styleTween(name, typeof value === "function"
22990           ? styleFunction$1(name, i, tweenValue(this, "style." + name, value))
22991           : styleConstant$1(name, i, value + ""), priority);
22992 };
22993
22994 function styleTween(name, value, priority) {
22995   function tween() {
22996     var node = this, i = value.apply(node, arguments);
22997     return i && function(t) {
22998       node.style.setProperty(name, i(t), priority);
22999     };
23000   }
23001   tween._value = value;
23002   return tween;
23003 }
23004
23005 var transition_styleTween = function(name, value, priority) {
23006   var key = "style." + (name += "");
23007   if (arguments.length < 2) return (key = this.tween(key)) && key._value;
23008   if (value == null) return this.tween(key, null);
23009   if (typeof value !== "function") throw new Error;
23010   return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
23011 };
23012
23013 function textConstant$1(value) {
23014   return function() {
23015     this.textContent = value;
23016   };
23017 }
23018
23019 function textFunction$1(value) {
23020   return function() {
23021     var value1 = value(this);
23022     this.textContent = value1 == null ? "" : value1;
23023   };
23024 }
23025
23026 var transition_text = function(value) {
23027   return this.tween("text", typeof value === "function"
23028       ? textFunction$1(tweenValue(this, "text", value))
23029       : textConstant$1(value == null ? "" : value + ""));
23030 };
23031
23032 var transition_transition = function() {
23033   var name = this._name,
23034       id0 = this._id,
23035       id1 = newId();
23036
23037   for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
23038     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
23039       if (node = group[i]) {
23040         var inherit = get$1(node, id0);
23041         schedule(node, name, id1, i, group, {
23042           time: inherit.time + inherit.delay + inherit.duration,
23043           delay: 0,
23044           duration: inherit.duration,
23045           ease: inherit.ease
23046         });
23047       }
23048     }
23049   }
23050
23051   return new Transition(groups, this._parents, name, id1);
23052 };
23053
23054 var id = 0;
23055
23056 function Transition(groups, parents, name, id) {
23057   this._groups = groups;
23058   this._parents = parents;
23059   this._name = name;
23060   this._id = id;
23061 }
23062
23063 function transition(name) {
23064   return selection().transition(name);
23065 }
23066
23067 function newId() {
23068   return ++id;
23069 }
23070
23071 var selection_prototype = selection.prototype;
23072
23073 Transition.prototype = transition.prototype = {
23074   constructor: Transition,
23075   select: transition_select,
23076   selectAll: transition_selectAll,
23077   filter: transition_filter,
23078   merge: transition_merge,
23079   selection: transition_selection,
23080   transition: transition_transition,
23081   call: selection_prototype.call,
23082   nodes: selection_prototype.nodes,
23083   node: selection_prototype.node,
23084   size: selection_prototype.size,
23085   empty: selection_prototype.empty,
23086   each: selection_prototype.each,
23087   on: transition_on,
23088   attr: transition_attr,
23089   attrTween: transition_attrTween,
23090   style: transition_style,
23091   styleTween: transition_styleTween,
23092   text: transition_text,
23093   remove: transition_remove,
23094   tween: transition_tween,
23095   delay: transition_delay,
23096   duration: transition_duration,
23097   ease: transition_ease
23098 };
23099
23100 function linear$1(t) {
23101   return +t;
23102 }
23103
23104 function quadIn(t) {
23105   return t * t;
23106 }
23107
23108 function quadOut(t) {
23109   return t * (2 - t);
23110 }
23111
23112 function quadInOut(t) {
23113   return ((t *= 2) <= 1 ? t * t : --t * (2 - t) + 1) / 2;
23114 }
23115
23116 function cubicIn(t) {
23117   return t * t * t;
23118 }
23119
23120 function cubicOut(t) {
23121   return --t * t * t + 1;
23122 }
23123
23124 function cubicInOut(t) {
23125   return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
23126 }
23127
23128 var exponent = 3;
23129
23130 var polyIn = (function custom(e) {
23131   e = +e;
23132
23133   function polyIn(t) {
23134     return Math.pow(t, e);
23135   }
23136
23137   polyIn.exponent = custom;
23138
23139   return polyIn;
23140 })(exponent);
23141
23142 var polyOut = (function custom(e) {
23143   e = +e;
23144
23145   function polyOut(t) {
23146     return 1 - Math.pow(1 - t, e);
23147   }
23148
23149   polyOut.exponent = custom;
23150
23151   return polyOut;
23152 })(exponent);
23153
23154 var polyInOut = (function custom(e) {
23155   e = +e;
23156
23157   function polyInOut(t) {
23158     return ((t *= 2) <= 1 ? Math.pow(t, e) : 2 - Math.pow(2 - t, e)) / 2;
23159   }
23160
23161   polyInOut.exponent = custom;
23162
23163   return polyInOut;
23164 })(exponent);
23165
23166 var pi = Math.PI;
23167 var halfPi = pi / 2;
23168
23169 function sinIn(t) {
23170   return 1 - Math.cos(t * halfPi);
23171 }
23172
23173 function sinOut(t) {
23174   return Math.sin(t * halfPi);
23175 }
23176
23177 function sinInOut(t) {
23178   return (1 - Math.cos(pi * t)) / 2;
23179 }
23180
23181 function expIn(t) {
23182   return Math.pow(2, 10 * t - 10);
23183 }
23184
23185 function expOut(t) {
23186   return 1 - Math.pow(2, -10 * t);
23187 }
23188
23189 function expInOut(t) {
23190   return ((t *= 2) <= 1 ? Math.pow(2, 10 * t - 10) : 2 - Math.pow(2, 10 - 10 * t)) / 2;
23191 }
23192
23193 function circleIn(t) {
23194   return 1 - Math.sqrt(1 - t * t);
23195 }
23196
23197 function circleOut(t) {
23198   return Math.sqrt(1 - --t * t);
23199 }
23200
23201 function circleInOut(t) {
23202   return ((t *= 2) <= 1 ? 1 - Math.sqrt(1 - t * t) : Math.sqrt(1 - (t -= 2) * t) + 1) / 2;
23203 }
23204
23205 var b1 = 4 / 11;
23206 var b2 = 6 / 11;
23207 var b3 = 8 / 11;
23208 var b4 = 3 / 4;
23209 var b5 = 9 / 11;
23210 var b6 = 10 / 11;
23211 var b7 = 15 / 16;
23212 var b8 = 21 / 22;
23213 var b9 = 63 / 64;
23214 var b0 = 1 / b1 / b1;
23215
23216 function bounceIn(t) {
23217   return 1 - bounceOut(1 - t);
23218 }
23219
23220 function bounceOut(t) {
23221   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;
23222 }
23223
23224 function bounceInOut(t) {
23225   return ((t *= 2) <= 1 ? 1 - bounceOut(1 - t) : bounceOut(t - 1) + 1) / 2;
23226 }
23227
23228 var overshoot = 1.70158;
23229
23230 var backIn = (function custom(s) {
23231   s = +s;
23232
23233   function backIn(t) {
23234     return t * t * ((s + 1) * t - s);
23235   }
23236
23237   backIn.overshoot = custom;
23238
23239   return backIn;
23240 })(overshoot);
23241
23242 var backOut = (function custom(s) {
23243   s = +s;
23244
23245   function backOut(t) {
23246     return --t * t * ((s + 1) * t + s) + 1;
23247   }
23248
23249   backOut.overshoot = custom;
23250
23251   return backOut;
23252 })(overshoot);
23253
23254 var backInOut = (function custom(s) {
23255   s = +s;
23256
23257   function backInOut(t) {
23258     return ((t *= 2) < 1 ? t * t * ((s + 1) * t - s) : (t -= 2) * t * ((s + 1) * t + s) + 2) / 2;
23259   }
23260
23261   backInOut.overshoot = custom;
23262
23263   return backInOut;
23264 })(overshoot);
23265
23266 var tau = 2 * Math.PI;
23267 var amplitude = 1;
23268 var period = 0.3;
23269
23270 var elasticIn = (function custom(a, p) {
23271   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23272
23273   function elasticIn(t) {
23274     return a * Math.pow(2, 10 * --t) * Math.sin((s - t) / p);
23275   }
23276
23277   elasticIn.amplitude = function(a) { return custom(a, p * tau); };
23278   elasticIn.period = function(p) { return custom(a, p); };
23279
23280   return elasticIn;
23281 })(amplitude, period);
23282
23283 var elasticOut = (function custom(a, p) {
23284   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23285
23286   function elasticOut(t) {
23287     return 1 - a * Math.pow(2, -10 * (t = +t)) * Math.sin((t + s) / p);
23288   }
23289
23290   elasticOut.amplitude = function(a) { return custom(a, p * tau); };
23291   elasticOut.period = function(p) { return custom(a, p); };
23292
23293   return elasticOut;
23294 })(amplitude, period);
23295
23296 var elasticInOut = (function custom(a, p) {
23297   var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
23298
23299   function elasticInOut(t) {
23300     return ((t = t * 2 - 1) < 0
23301         ? a * Math.pow(2, 10 * t) * Math.sin((s - t) / p)
23302         : 2 - a * Math.pow(2, -10 * t) * Math.sin((s + t) / p)) / 2;
23303   }
23304
23305   elasticInOut.amplitude = function(a) { return custom(a, p * tau); };
23306   elasticInOut.period = function(p) { return custom(a, p); };
23307
23308   return elasticInOut;
23309 })(amplitude, period);
23310
23311 var defaultTiming = {
23312   time: null, // Set on use.
23313   delay: 0,
23314   duration: 250,
23315   ease: cubicInOut
23316 };
23317
23318 function inherit(node, id) {
23319   var timing;
23320   while (!(timing = node.__transition) || !(timing = timing[id])) {
23321     if (!(node = node.parentNode)) {
23322       return defaultTiming.time = now(), defaultTiming;
23323     }
23324   }
23325   return timing;
23326 }
23327
23328 var selection_transition = function(name) {
23329   var id,
23330       timing;
23331
23332   if (name instanceof Transition) {
23333     id = name._id, name = name._name;
23334   } else {
23335     id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
23336   }
23337
23338   for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
23339     for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
23340       if (node = group[i]) {
23341         schedule(node, name, id, i, group, timing || inherit(node, id));
23342       }
23343     }
23344   }
23345
23346   return new Transition(groups, this._parents, name, id);
23347 };
23348
23349 selection.prototype.interrupt = selection_interrupt;
23350 selection.prototype.transition = selection_transition;
23351
23352 var root$1 = [null];
23353
23354 var active = function(node, name) {
23355   var schedules = node.__transition,
23356       schedule$$1,
23357       i;
23358
23359   if (schedules) {
23360     name = name == null ? null : name + "";
23361     for (i in schedules) {
23362       if ((schedule$$1 = schedules[i]).state > SCHEDULED && schedule$$1.name === name) {
23363         return new Transition([[node]], root$1, name, +i);
23364       }
23365     }
23366   }
23367
23368   return null;
23369 };
23370
23371 var constant$4 = function(x) {
23372   return function() {
23373     return x;
23374   };
23375 };
23376
23377 var BrushEvent = function(target, type, selection) {
23378   this.target = target;
23379   this.type = type;
23380   this.selection = selection;
23381 };
23382
23383 function nopropagation$1() {
23384   event.stopImmediatePropagation();
23385 }
23386
23387 var noevent$1 = function() {
23388   event.preventDefault();
23389   event.stopImmediatePropagation();
23390 };
23391
23392 var MODE_DRAG = {name: "drag"};
23393 var MODE_SPACE = {name: "space"};
23394 var MODE_HANDLE = {name: "handle"};
23395 var MODE_CENTER = {name: "center"};
23396
23397 var X = {
23398   name: "x",
23399   handles: ["e", "w"].map(type$2),
23400   input: function(x, e) { return x && [[x[0], e[0][1]], [x[1], e[1][1]]]; },
23401   output: function(xy) { return xy && [xy[0][0], xy[1][0]]; }
23402 };
23403
23404 var Y = {
23405   name: "y",
23406   handles: ["n", "s"].map(type$2),
23407   input: function(y, e) { return y && [[e[0][0], y[0]], [e[1][0], y[1]]]; },
23408   output: function(xy) { return xy && [xy[0][1], xy[1][1]]; }
23409 };
23410
23411 var XY = {
23412   name: "xy",
23413   handles: ["n", "e", "s", "w", "nw", "ne", "se", "sw"].map(type$2),
23414   input: function(xy) { return xy; },
23415   output: function(xy) { return xy; }
23416 };
23417
23418 var cursors = {
23419   overlay: "crosshair",
23420   selection: "move",
23421   n: "ns-resize",
23422   e: "ew-resize",
23423   s: "ns-resize",
23424   w: "ew-resize",
23425   nw: "nwse-resize",
23426   ne: "nesw-resize",
23427   se: "nwse-resize",
23428   sw: "nesw-resize"
23429 };
23430
23431 var flipX = {
23432   e: "w",
23433   w: "e",
23434   nw: "ne",
23435   ne: "nw",
23436   se: "sw",
23437   sw: "se"
23438 };
23439
23440 var flipY = {
23441   n: "s",
23442   s: "n",
23443   nw: "sw",
23444   ne: "se",
23445   se: "ne",
23446   sw: "nw"
23447 };
23448
23449 var signsX = {
23450   overlay: +1,
23451   selection: +1,
23452   n: null,
23453   e: +1,
23454   s: null,
23455   w: -1,
23456   nw: -1,
23457   ne: +1,
23458   se: +1,
23459   sw: -1
23460 };
23461
23462 var signsY = {
23463   overlay: +1,
23464   selection: +1,
23465   n: -1,
23466   e: null,
23467   s: +1,
23468   w: null,
23469   nw: -1,
23470   ne: -1,
23471   se: +1,
23472   sw: +1
23473 };
23474
23475 function type$2(t) {
23476   return {type: t};
23477 }
23478
23479 // Ignore right-click, since that should open the context menu.
23480 function defaultFilter() {
23481   return !event.button;
23482 }
23483
23484 function defaultExtent() {
23485   var svg = this.ownerSVGElement || this;
23486   return [[0, 0], [svg.width.baseVal.value, svg.height.baseVal.value]];
23487 }
23488
23489 // Like d3.local, but with the name “__brush” rather than auto-generated.
23490 function local$$1(node) {
23491   while (!node.__brush) if (!(node = node.parentNode)) return;
23492   return node.__brush;
23493 }
23494
23495 function empty(extent) {
23496   return extent[0][0] === extent[1][0]
23497       || extent[0][1] === extent[1][1];
23498 }
23499
23500 function brushSelection(node) {
23501   var state = node.__brush;
23502   return state ? state.dim.output(state.selection) : null;
23503 }
23504
23505 function brushX() {
23506   return brush$1(X);
23507 }
23508
23509 function brushY() {
23510   return brush$1(Y);
23511 }
23512
23513 var brush = function() {
23514   return brush$1(XY);
23515 };
23516
23517 function brush$1(dim) {
23518   var extent = defaultExtent,
23519       filter = defaultFilter,
23520       listeners = dispatch(brush, "start", "brush", "end"),
23521       handleSize = 6,
23522       touchending;
23523
23524   function brush(group) {
23525     var overlay = group
23526         .property("__brush", initialize)
23527       .selectAll(".overlay")
23528       .data([type$2("overlay")]);
23529
23530     overlay.enter().append("rect")
23531         .attr("class", "overlay")
23532         .attr("pointer-events", "all")
23533         .attr("cursor", cursors.overlay)
23534       .merge(overlay)
23535         .each(function() {
23536           var extent = local$$1(this).extent;
23537           select(this)
23538               .attr("x", extent[0][0])
23539               .attr("y", extent[0][1])
23540               .attr("width", extent[1][0] - extent[0][0])
23541               .attr("height", extent[1][1] - extent[0][1]);
23542         });
23543
23544     group.selectAll(".selection")
23545       .data([type$2("selection")])
23546       .enter().append("rect")
23547         .attr("class", "selection")
23548         .attr("cursor", cursors.selection)
23549         .attr("fill", "#777")
23550         .attr("fill-opacity", 0.3)
23551         .attr("stroke", "#fff")
23552         .attr("shape-rendering", "crispEdges");
23553
23554     var handle = group.selectAll(".handle")
23555       .data(dim.handles, function(d) { return d.type; });
23556
23557     handle.exit().remove();
23558
23559     handle.enter().append("rect")
23560         .attr("class", function(d) { return "handle handle--" + d.type; })
23561         .attr("cursor", function(d) { return cursors[d.type]; });
23562
23563     group
23564         .each(redraw)
23565         .attr("fill", "none")
23566         .attr("pointer-events", "all")
23567         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
23568         .on("mousedown.brush touchstart.brush", started);
23569   }
23570
23571   brush.move = function(group, selection) {
23572     if (group.selection) {
23573       group
23574           .on("start.brush", function() { emitter(this, arguments).beforestart().start(); })
23575           .on("interrupt.brush end.brush", function() { emitter(this, arguments).end(); })
23576           .tween("brush", function() {
23577             var that = this,
23578                 state = that.__brush,
23579                 emit = emitter(that, arguments),
23580                 selection0 = state.selection,
23581                 selection1 = dim.input(typeof selection === "function" ? selection.apply(this, arguments) : selection, state.extent),
23582                 i = interpolateValue(selection0, selection1);
23583
23584             function tween(t) {
23585               state.selection = t === 1 && empty(selection1) ? null : i(t);
23586               redraw.call(that);
23587               emit.brush();
23588             }
23589
23590             return selection0 && selection1 ? tween : tween(1);
23591           });
23592     } else {
23593       group
23594           .each(function() {
23595             var that = this,
23596                 args = arguments,
23597                 state = that.__brush,
23598                 selection1 = dim.input(typeof selection === "function" ? selection.apply(that, args) : selection, state.extent),
23599                 emit = emitter(that, args).beforestart();
23600
23601             interrupt(that);
23602             state.selection = selection1 == null || empty(selection1) ? null : selection1;
23603             redraw.call(that);
23604             emit.start().brush().end();
23605           });
23606     }
23607   };
23608
23609   function redraw() {
23610     var group = select(this),
23611         selection = local$$1(this).selection;
23612
23613     if (selection) {
23614       group.selectAll(".selection")
23615           .style("display", null)
23616           .attr("x", selection[0][0])
23617           .attr("y", selection[0][1])
23618           .attr("width", selection[1][0] - selection[0][0])
23619           .attr("height", selection[1][1] - selection[0][1]);
23620
23621       group.selectAll(".handle")
23622           .style("display", null)
23623           .attr("x", function(d) { return d.type[d.type.length - 1] === "e" ? selection[1][0] - handleSize / 2 : selection[0][0] - handleSize / 2; })
23624           .attr("y", function(d) { return d.type[0] === "s" ? selection[1][1] - handleSize / 2 : selection[0][1] - handleSize / 2; })
23625           .attr("width", function(d) { return d.type === "n" || d.type === "s" ? selection[1][0] - selection[0][0] + handleSize : handleSize; })
23626           .attr("height", function(d) { return d.type === "e" || d.type === "w" ? selection[1][1] - selection[0][1] + handleSize : handleSize; });
23627     }
23628
23629     else {
23630       group.selectAll(".selection,.handle")
23631           .style("display", "none")
23632           .attr("x", null)
23633           .attr("y", null)
23634           .attr("width", null)
23635           .attr("height", null);
23636     }
23637   }
23638
23639   function emitter(that, args) {
23640     return that.__brush.emitter || new Emitter(that, args);
23641   }
23642
23643   function Emitter(that, args) {
23644     this.that = that;
23645     this.args = args;
23646     this.state = that.__brush;
23647     this.active = 0;
23648   }
23649
23650   Emitter.prototype = {
23651     beforestart: function() {
23652       if (++this.active === 1) this.state.emitter = this, this.starting = true;
23653       return this;
23654     },
23655     start: function() {
23656       if (this.starting) this.starting = false, this.emit("start");
23657       return this;
23658     },
23659     brush: function() {
23660       this.emit("brush");
23661       return this;
23662     },
23663     end: function() {
23664       if (--this.active === 0) delete this.state.emitter, this.emit("end");
23665       return this;
23666     },
23667     emit: function(type) {
23668       customEvent(new BrushEvent(brush, type, dim.output(this.state.selection)), listeners.apply, listeners, [type, this.that, this.args]);
23669     }
23670   };
23671
23672   function started() {
23673     if (event.touches) { if (event.changedTouches.length < event.touches.length) return noevent$1(); }
23674     else if (touchending) return;
23675     if (!filter.apply(this, arguments)) return;
23676
23677     var that = this,
23678         type = event.target.__data__.type,
23679         mode = (event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (event.altKey ? MODE_CENTER : MODE_HANDLE),
23680         signX = dim === Y ? null : signsX[type],
23681         signY = dim === X ? null : signsY[type],
23682         state = local$$1(that),
23683         extent = state.extent,
23684         selection = state.selection,
23685         W = extent[0][0], w0, w1,
23686         N = extent[0][1], n0, n1,
23687         E = extent[1][0], e0, e1,
23688         S = extent[1][1], s0, s1,
23689         dx,
23690         dy,
23691         moving,
23692         shifting = signX && signY && event.shiftKey,
23693         lockX,
23694         lockY,
23695         point0 = mouse(that),
23696         point = point0,
23697         emit = emitter(that, arguments).beforestart();
23698
23699     if (type === "overlay") {
23700       state.selection = selection = [
23701         [w0 = dim === Y ? W : point0[0], n0 = dim === X ? N : point0[1]],
23702         [e0 = dim === Y ? E : w0, s0 = dim === X ? S : n0]
23703       ];
23704     } else {
23705       w0 = selection[0][0];
23706       n0 = selection[0][1];
23707       e0 = selection[1][0];
23708       s0 = selection[1][1];
23709     }
23710
23711     w1 = w0;
23712     n1 = n0;
23713     e1 = e0;
23714     s1 = s0;
23715
23716     var group = select(that)
23717         .attr("pointer-events", "none");
23718
23719     var overlay = group.selectAll(".overlay")
23720         .attr("cursor", cursors[type]);
23721
23722     if (event.touches) {
23723       group
23724           .on("touchmove.brush", moved, true)
23725           .on("touchend.brush touchcancel.brush", ended, true);
23726     } else {
23727       var view = select(event.view)
23728           .on("keydown.brush", keydowned, true)
23729           .on("keyup.brush", keyupped, true)
23730           .on("mousemove.brush", moved, true)
23731           .on("mouseup.brush", ended, true);
23732
23733       dragDisable(event.view);
23734     }
23735
23736     nopropagation$1();
23737     interrupt(that);
23738     redraw.call(that);
23739     emit.start();
23740
23741     function moved() {
23742       var point1 = mouse(that);
23743       if (shifting && !lockX && !lockY) {
23744         if (Math.abs(point1[0] - point[0]) > Math.abs(point1[1] - point[1])) lockY = true;
23745         else lockX = true;
23746       }
23747       point = point1;
23748       moving = true;
23749       noevent$1();
23750       move();
23751     }
23752
23753     function move() {
23754       var t;
23755
23756       dx = point[0] - point0[0];
23757       dy = point[1] - point0[1];
23758
23759       switch (mode) {
23760         case MODE_SPACE:
23761         case MODE_DRAG: {
23762           if (signX) dx = Math.max(W - w0, Math.min(E - e0, dx)), w1 = w0 + dx, e1 = e0 + dx;
23763           if (signY) dy = Math.max(N - n0, Math.min(S - s0, dy)), n1 = n0 + dy, s1 = s0 + dy;
23764           break;
23765         }
23766         case MODE_HANDLE: {
23767           if (signX < 0) dx = Math.max(W - w0, Math.min(E - w0, dx)), w1 = w0 + dx, e1 = e0;
23768           else if (signX > 0) dx = Math.max(W - e0, Math.min(E - e0, dx)), w1 = w0, e1 = e0 + dx;
23769           if (signY < 0) dy = Math.max(N - n0, Math.min(S - n0, dy)), n1 = n0 + dy, s1 = s0;
23770           else if (signY > 0) dy = Math.max(N - s0, Math.min(S - s0, dy)), n1 = n0, s1 = s0 + dy;
23771           break;
23772         }
23773         case MODE_CENTER: {
23774           if (signX) w1 = Math.max(W, Math.min(E, w0 - dx * signX)), e1 = Math.max(W, Math.min(E, e0 + dx * signX));
23775           if (signY) n1 = Math.max(N, Math.min(S, n0 - dy * signY)), s1 = Math.max(N, Math.min(S, s0 + dy * signY));
23776           break;
23777         }
23778       }
23779
23780       if (e1 < w1) {
23781         signX *= -1;
23782         t = w0, w0 = e0, e0 = t;
23783         t = w1, w1 = e1, e1 = t;
23784         if (type in flipX) overlay.attr("cursor", cursors[type = flipX[type]]);
23785       }
23786
23787       if (s1 < n1) {
23788         signY *= -1;
23789         t = n0, n0 = s0, s0 = t;
23790         t = n1, n1 = s1, s1 = t;
23791         if (type in flipY) overlay.attr("cursor", cursors[type = flipY[type]]);
23792       }
23793
23794       if (state.selection) selection = state.selection; // May be set by brush.move!
23795       if (lockX) w1 = selection[0][0], e1 = selection[1][0];
23796       if (lockY) n1 = selection[0][1], s1 = selection[1][1];
23797
23798       if (selection[0][0] !== w1
23799           || selection[0][1] !== n1
23800           || selection[1][0] !== e1
23801           || selection[1][1] !== s1) {
23802         state.selection = [[w1, n1], [e1, s1]];
23803         redraw.call(that);
23804         emit.brush();
23805       }
23806     }
23807
23808     function ended() {
23809       nopropagation$1();
23810       if (event.touches) {
23811         if (event.touches.length) return;
23812         if (touchending) clearTimeout(touchending);
23813         touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
23814         group.on("touchmove.brush touchend.brush touchcancel.brush", null);
23815       } else {
23816         yesdrag(event.view, moving);
23817         view.on("keydown.brush keyup.brush mousemove.brush mouseup.brush", null);
23818       }
23819       group.attr("pointer-events", "all");
23820       overlay.attr("cursor", cursors.overlay);
23821       if (state.selection) selection = state.selection; // May be set by brush.move (on start)!
23822       if (empty(selection)) state.selection = null, redraw.call(that);
23823       emit.end();
23824     }
23825
23826     function keydowned() {
23827       switch (event.keyCode) {
23828         case 16: { // SHIFT
23829           shifting = signX && signY;
23830           break;
23831         }
23832         case 18: { // ALT
23833           if (mode === MODE_HANDLE) {
23834             if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
23835             if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
23836             mode = MODE_CENTER;
23837             move();
23838           }
23839           break;
23840         }
23841         case 32: { // SPACE; takes priority over ALT
23842           if (mode === MODE_HANDLE || mode === MODE_CENTER) {
23843             if (signX < 0) e0 = e1 - dx; else if (signX > 0) w0 = w1 - dx;
23844             if (signY < 0) s0 = s1 - dy; else if (signY > 0) n0 = n1 - dy;
23845             mode = MODE_SPACE;
23846             overlay.attr("cursor", cursors.selection);
23847             move();
23848           }
23849           break;
23850         }
23851         default: return;
23852       }
23853       noevent$1();
23854     }
23855
23856     function keyupped() {
23857       switch (event.keyCode) {
23858         case 16: { // SHIFT
23859           if (shifting) {
23860             lockX = lockY = shifting = false;
23861             move();
23862           }
23863           break;
23864         }
23865         case 18: { // ALT
23866           if (mode === MODE_CENTER) {
23867             if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
23868             if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
23869             mode = MODE_HANDLE;
23870             move();
23871           }
23872           break;
23873         }
23874         case 32: { // SPACE
23875           if (mode === MODE_SPACE) {
23876             if (event.altKey) {
23877               if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
23878               if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
23879               mode = MODE_CENTER;
23880             } else {
23881               if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
23882               if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
23883               mode = MODE_HANDLE;
23884             }
23885             overlay.attr("cursor", cursors[type]);
23886             move();
23887           }
23888           break;
23889         }
23890         default: return;
23891       }
23892       noevent$1();
23893     }
23894   }
23895
23896   function initialize() {
23897     var state = this.__brush || {selection: null};
23898     state.extent = extent.apply(this, arguments);
23899     state.dim = dim;
23900     return state;
23901   }
23902
23903   brush.extent = function(_) {
23904     return arguments.length ? (extent = typeof _ === "function" ? _ : constant$4([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), brush) : extent;
23905   };
23906
23907   brush.filter = function(_) {
23908     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$4(!!_), brush) : filter;
23909   };
23910
23911   brush.handleSize = function(_) {
23912     return arguments.length ? (handleSize = +_, brush) : handleSize;
23913   };
23914
23915   brush.on = function() {
23916     var value = listeners.on.apply(listeners, arguments);
23917     return value === listeners ? brush : value;
23918   };
23919
23920   return brush;
23921 }
23922
23923 var cos = Math.cos;
23924 var sin = Math.sin;
23925 var pi$1 = Math.PI;
23926 var halfPi$1 = pi$1 / 2;
23927 var tau$1 = pi$1 * 2;
23928 var max$1 = Math.max;
23929
23930 function compareValue(compare) {
23931   return function(a, b) {
23932     return compare(
23933       a.source.value + a.target.value,
23934       b.source.value + b.target.value
23935     );
23936   };
23937 }
23938
23939 var chord = function() {
23940   var padAngle = 0,
23941       sortGroups = null,
23942       sortSubgroups = null,
23943       sortChords = null;
23944
23945   function chord(matrix) {
23946     var n = matrix.length,
23947         groupSums = [],
23948         groupIndex = sequence(n),
23949         subgroupIndex = [],
23950         chords = [],
23951         groups = chords.groups = new Array(n),
23952         subgroups = new Array(n * n),
23953         k,
23954         x,
23955         x0,
23956         dx,
23957         i,
23958         j;
23959
23960     // Compute the sum.
23961     k = 0, i = -1; while (++i < n) {
23962       x = 0, j = -1; while (++j < n) {
23963         x += matrix[i][j];
23964       }
23965       groupSums.push(x);
23966       subgroupIndex.push(sequence(n));
23967       k += x;
23968     }
23969
23970     // Sort groups…
23971     if (sortGroups) groupIndex.sort(function(a, b) {
23972       return sortGroups(groupSums[a], groupSums[b]);
23973     });
23974
23975     // Sort subgroups…
23976     if (sortSubgroups) subgroupIndex.forEach(function(d, i) {
23977       d.sort(function(a, b) {
23978         return sortSubgroups(matrix[i][a], matrix[i][b]);
23979       });
23980     });
23981
23982     // Convert the sum to scaling factor for [0, 2pi].
23983     // TODO Allow start and end angle to be specified?
23984     // TODO Allow padding to be specified as percentage?
23985     k = max$1(0, tau$1 - padAngle * n) / k;
23986     dx = k ? padAngle : tau$1 / n;
23987
23988     // Compute the start and end angle for each group and subgroup.
23989     // Note: Opera has a bug reordering object literal properties!
23990     x = 0, i = -1; while (++i < n) {
23991       x0 = x, j = -1; while (++j < n) {
23992         var di = groupIndex[i],
23993             dj = subgroupIndex[di][j],
23994             v = matrix[di][dj],
23995             a0 = x,
23996             a1 = x += v * k;
23997         subgroups[dj * n + di] = {
23998           index: di,
23999           subindex: dj,
24000           startAngle: a0,
24001           endAngle: a1,
24002           value: v
24003         };
24004       }
24005       groups[di] = {
24006         index: di,
24007         startAngle: x0,
24008         endAngle: x,
24009         value: groupSums[di]
24010       };
24011       x += dx;
24012     }
24013
24014     // Generate chords for each (non-empty) subgroup-subgroup link.
24015     i = -1; while (++i < n) {
24016       j = i - 1; while (++j < n) {
24017         var source = subgroups[j * n + i],
24018             target = subgroups[i * n + j];
24019         if (source.value || target.value) {
24020           chords.push(source.value < target.value
24021               ? {source: target, target: source}
24022               : {source: source, target: target});
24023         }
24024       }
24025     }
24026
24027     return sortChords ? chords.sort(sortChords) : chords;
24028   }
24029
24030   chord.padAngle = function(_) {
24031     return arguments.length ? (padAngle = max$1(0, _), chord) : padAngle;
24032   };
24033
24034   chord.sortGroups = function(_) {
24035     return arguments.length ? (sortGroups = _, chord) : sortGroups;
24036   };
24037
24038   chord.sortSubgroups = function(_) {
24039     return arguments.length ? (sortSubgroups = _, chord) : sortSubgroups;
24040   };
24041
24042   chord.sortChords = function(_) {
24043     return arguments.length ? (_ == null ? sortChords = null : (sortChords = compareValue(_))._ = _, chord) : sortChords && sortChords._;
24044   };
24045
24046   return chord;
24047 };
24048
24049 var slice$2 = Array.prototype.slice;
24050
24051 var constant$5 = function(x) {
24052   return function() {
24053     return x;
24054   };
24055 };
24056
24057 var pi$2 = Math.PI;
24058 var tau$2 = 2 * pi$2;
24059 var epsilon$1 = 1e-6;
24060 var tauEpsilon = tau$2 - epsilon$1;
24061
24062 function Path() {
24063   this._x0 = this._y0 = // start of current subpath
24064   this._x1 = this._y1 = null; // end of current subpath
24065   this._ = "";
24066 }
24067
24068 function path() {
24069   return new Path;
24070 }
24071
24072 Path.prototype = path.prototype = {
24073   constructor: Path,
24074   moveTo: function(x, y) {
24075     this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y);
24076   },
24077   closePath: function() {
24078     if (this._x1 !== null) {
24079       this._x1 = this._x0, this._y1 = this._y0;
24080       this._ += "Z";
24081     }
24082   },
24083   lineTo: function(x, y) {
24084     this._ += "L" + (this._x1 = +x) + "," + (this._y1 = +y);
24085   },
24086   quadraticCurveTo: function(x1, y1, x, y) {
24087     this._ += "Q" + (+x1) + "," + (+y1) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
24088   },
24089   bezierCurveTo: function(x1, y1, x2, y2, x, y) {
24090     this._ += "C" + (+x1) + "," + (+y1) + "," + (+x2) + "," + (+y2) + "," + (this._x1 = +x) + "," + (this._y1 = +y);
24091   },
24092   arcTo: function(x1, y1, x2, y2, r) {
24093     x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;
24094     var x0 = this._x1,
24095         y0 = this._y1,
24096         x21 = x2 - x1,
24097         y21 = y2 - y1,
24098         x01 = x0 - x1,
24099         y01 = y0 - y1,
24100         l01_2 = x01 * x01 + y01 * y01;
24101
24102     // Is the radius negative? Error.
24103     if (r < 0) throw new Error("negative radius: " + r);
24104
24105     // Is this path empty? Move to (x1,y1).
24106     if (this._x1 === null) {
24107       this._ += "M" + (this._x1 = x1) + "," + (this._y1 = y1);
24108     }
24109
24110     // Or, is (x1,y1) coincident with (x0,y0)? Do nothing.
24111     else if (!(l01_2 > epsilon$1)) {}
24112
24113     // Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?
24114     // Equivalently, is (x1,y1) coincident with (x2,y2)?
24115     // Or, is the radius zero? Line to (x1,y1).
24116     else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon$1) || !r) {
24117       this._ += "L" + (this._x1 = x1) + "," + (this._y1 = y1);
24118     }
24119
24120     // Otherwise, draw an arc!
24121     else {
24122       var x20 = x2 - x0,
24123           y20 = y2 - y0,
24124           l21_2 = x21 * x21 + y21 * y21,
24125           l20_2 = x20 * x20 + y20 * y20,
24126           l21 = Math.sqrt(l21_2),
24127           l01 = Math.sqrt(l01_2),
24128           l = r * Math.tan((pi$2 - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),
24129           t01 = l / l01,
24130           t21 = l / l21;
24131
24132       // If the start tangent is not coincident with (x0,y0), line to.
24133       if (Math.abs(t01 - 1) > epsilon$1) {
24134         this._ += "L" + (x1 + t01 * x01) + "," + (y1 + t01 * y01);
24135       }
24136
24137       this._ += "A" + r + "," + r + ",0,0," + (+(y01 * x20 > x01 * y20)) + "," + (this._x1 = x1 + t21 * x21) + "," + (this._y1 = y1 + t21 * y21);
24138     }
24139   },
24140   arc: function(x, y, r, a0, a1, ccw) {
24141     x = +x, y = +y, r = +r;
24142     var dx = r * Math.cos(a0),
24143         dy = r * Math.sin(a0),
24144         x0 = x + dx,
24145         y0 = y + dy,
24146         cw = 1 ^ ccw,
24147         da = ccw ? a0 - a1 : a1 - a0;
24148
24149     // Is the radius negative? Error.
24150     if (r < 0) throw new Error("negative radius: " + r);
24151
24152     // Is this path empty? Move to (x0,y0).
24153     if (this._x1 === null) {
24154       this._ += "M" + x0 + "," + y0;
24155     }
24156
24157     // Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).
24158     else if (Math.abs(this._x1 - x0) > epsilon$1 || Math.abs(this._y1 - y0) > epsilon$1) {
24159       this._ += "L" + x0 + "," + y0;
24160     }
24161
24162     // Is this arc empty? We’re done.
24163     if (!r) return;
24164
24165     // Does the angle go the wrong way? Flip the direction.
24166     if (da < 0) da = da % tau$2 + tau$2;
24167
24168     // Is this a complete circle? Draw two arcs to complete the circle.
24169     if (da > tauEpsilon) {
24170       this._ += "A" + r + "," + r + ",0,1," + cw + "," + (x - dx) + "," + (y - dy) + "A" + r + "," + r + ",0,1," + cw + "," + (this._x1 = x0) + "," + (this._y1 = y0);
24171     }
24172
24173     // Is this arc non-empty? Draw an arc!
24174     else if (da > epsilon$1) {
24175       this._ += "A" + r + "," + r + ",0," + (+(da >= pi$2)) + "," + cw + "," + (this._x1 = x + r * Math.cos(a1)) + "," + (this._y1 = y + r * Math.sin(a1));
24176     }
24177   },
24178   rect: function(x, y, w, h) {
24179     this._ += "M" + (this._x0 = this._x1 = +x) + "," + (this._y0 = this._y1 = +y) + "h" + (+w) + "v" + (+h) + "h" + (-w) + "Z";
24180   },
24181   toString: function() {
24182     return this._;
24183   }
24184 };
24185
24186 function defaultSource(d) {
24187   return d.source;
24188 }
24189
24190 function defaultTarget(d) {
24191   return d.target;
24192 }
24193
24194 function defaultRadius(d) {
24195   return d.radius;
24196 }
24197
24198 function defaultStartAngle(d) {
24199   return d.startAngle;
24200 }
24201
24202 function defaultEndAngle(d) {
24203   return d.endAngle;
24204 }
24205
24206 var ribbon = function() {
24207   var source = defaultSource,
24208       target = defaultTarget,
24209       radius = defaultRadius,
24210       startAngle = defaultStartAngle,
24211       endAngle = defaultEndAngle,
24212       context = null;
24213
24214   function ribbon() {
24215     var buffer,
24216         argv = slice$2.call(arguments),
24217         s = source.apply(this, argv),
24218         t = target.apply(this, argv),
24219         sr = +radius.apply(this, (argv[0] = s, argv)),
24220         sa0 = startAngle.apply(this, argv) - halfPi$1,
24221         sa1 = endAngle.apply(this, argv) - halfPi$1,
24222         sx0 = sr * cos(sa0),
24223         sy0 = sr * sin(sa0),
24224         tr = +radius.apply(this, (argv[0] = t, argv)),
24225         ta0 = startAngle.apply(this, argv) - halfPi$1,
24226         ta1 = endAngle.apply(this, argv) - halfPi$1;
24227
24228     if (!context) context = buffer = path();
24229
24230     context.moveTo(sx0, sy0);
24231     context.arc(0, 0, sr, sa0, sa1);
24232     if (sa0 !== ta0 || sa1 !== ta1) { // TODO sr !== tr?
24233       context.quadraticCurveTo(0, 0, tr * cos(ta0), tr * sin(ta0));
24234       context.arc(0, 0, tr, ta0, ta1);
24235     }
24236     context.quadraticCurveTo(0, 0, sx0, sy0);
24237     context.closePath();
24238
24239     if (buffer) return context = null, buffer + "" || null;
24240   }
24241
24242   ribbon.radius = function(_) {
24243     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$5(+_), ribbon) : radius;
24244   };
24245
24246   ribbon.startAngle = function(_) {
24247     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : startAngle;
24248   };
24249
24250   ribbon.endAngle = function(_) {
24251     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$5(+_), ribbon) : endAngle;
24252   };
24253
24254   ribbon.source = function(_) {
24255     return arguments.length ? (source = _, ribbon) : source;
24256   };
24257
24258   ribbon.target = function(_) {
24259     return arguments.length ? (target = _, ribbon) : target;
24260   };
24261
24262   ribbon.context = function(_) {
24263     return arguments.length ? ((context = _ == null ? null : _), ribbon) : context;
24264   };
24265
24266   return ribbon;
24267 };
24268
24269 var prefix = "$";
24270
24271 function Map() {}
24272
24273 Map.prototype = map$1.prototype = {
24274   constructor: Map,
24275   has: function(key) {
24276     return (prefix + key) in this;
24277   },
24278   get: function(key) {
24279     return this[prefix + key];
24280   },
24281   set: function(key, value) {
24282     this[prefix + key] = value;
24283     return this;
24284   },
24285   remove: function(key) {
24286     var property = prefix + key;
24287     return property in this && delete this[property];
24288   },
24289   clear: function() {
24290     for (var property in this) if (property[0] === prefix) delete this[property];
24291   },
24292   keys: function() {
24293     var keys = [];
24294     for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));
24295     return keys;
24296   },
24297   values: function() {
24298     var values = [];
24299     for (var property in this) if (property[0] === prefix) values.push(this[property]);
24300     return values;
24301   },
24302   entries: function() {
24303     var entries = [];
24304     for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});
24305     return entries;
24306   },
24307   size: function() {
24308     var size = 0;
24309     for (var property in this) if (property[0] === prefix) ++size;
24310     return size;
24311   },
24312   empty: function() {
24313     for (var property in this) if (property[0] === prefix) return false;
24314     return true;
24315   },
24316   each: function(f) {
24317     for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);
24318   }
24319 };
24320
24321 function map$1(object, f) {
24322   var map = new Map;
24323
24324   // Copy constructor.
24325   if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });
24326
24327   // Index array by numeric index or specified key function.
24328   else if (Array.isArray(object)) {
24329     var i = -1,
24330         n = object.length,
24331         o;
24332
24333     if (f == null) while (++i < n) map.set(i, object[i]);
24334     else while (++i < n) map.set(f(o = object[i], i, object), o);
24335   }
24336
24337   // Convert object to map.
24338   else if (object) for (var key in object) map.set(key, object[key]);
24339
24340   return map;
24341 }
24342
24343 var nest = function() {
24344   var keys = [],
24345       sortKeys = [],
24346       sortValues,
24347       rollup,
24348       nest;
24349
24350   function apply(array, depth, createResult, setResult) {
24351     if (depth >= keys.length) return rollup != null
24352         ? rollup(array) : (sortValues != null
24353         ? array.sort(sortValues)
24354         : array);
24355
24356     var i = -1,
24357         n = array.length,
24358         key = keys[depth++],
24359         keyValue,
24360         value,
24361         valuesByKey = map$1(),
24362         values,
24363         result = createResult();
24364
24365     while (++i < n) {
24366       if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) {
24367         values.push(value);
24368       } else {
24369         valuesByKey.set(keyValue, [value]);
24370       }
24371     }
24372
24373     valuesByKey.each(function(values, key) {
24374       setResult(result, key, apply(values, depth, createResult, setResult));
24375     });
24376
24377     return result;
24378   }
24379
24380   function entries(map, depth) {
24381     if (++depth > keys.length) return map;
24382     var array, sortKey = sortKeys[depth - 1];
24383     if (rollup != null && depth >= keys.length) array = map.entries();
24384     else array = [], map.each(function(v, k) { array.push({key: k, values: entries(v, depth)}); });
24385     return sortKey != null ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array;
24386   }
24387
24388   return nest = {
24389     object: function(array) { return apply(array, 0, createObject, setObject); },
24390     map: function(array) { return apply(array, 0, createMap, setMap); },
24391     entries: function(array) { return entries(apply(array, 0, createMap, setMap), 0); },
24392     key: function(d) { keys.push(d); return nest; },
24393     sortKeys: function(order) { sortKeys[keys.length - 1] = order; return nest; },
24394     sortValues: function(order) { sortValues = order; return nest; },
24395     rollup: function(f) { rollup = f; return nest; }
24396   };
24397 };
24398
24399 function createObject() {
24400   return {};
24401 }
24402
24403 function setObject(object, key, value) {
24404   object[key] = value;
24405 }
24406
24407 function createMap() {
24408   return map$1();
24409 }
24410
24411 function setMap(map, key, value) {
24412   map.set(key, value);
24413 }
24414
24415 function Set() {}
24416
24417 var proto = map$1.prototype;
24418
24419 Set.prototype = set$2.prototype = {
24420   constructor: Set,
24421   has: proto.has,
24422   add: function(value) {
24423     value += "";
24424     this[prefix + value] = value;
24425     return this;
24426   },
24427   remove: proto.remove,
24428   clear: proto.clear,
24429   values: proto.keys,
24430   size: proto.size,
24431   empty: proto.empty,
24432   each: proto.each
24433 };
24434
24435 function set$2(object, f) {
24436   var set = new Set;
24437
24438   // Copy constructor.
24439   if (object instanceof Set) object.each(function(value) { set.add(value); });
24440
24441   // Otherwise, assume it’s an array.
24442   else if (object) {
24443     var i = -1, n = object.length;
24444     if (f == null) while (++i < n) set.add(object[i]);
24445     else while (++i < n) set.add(f(object[i], i, object));
24446   }
24447
24448   return set;
24449 }
24450
24451 var keys = function(map) {
24452   var keys = [];
24453   for (var key in map) keys.push(key);
24454   return keys;
24455 };
24456
24457 var values = function(map) {
24458   var values = [];
24459   for (var key in map) values.push(map[key]);
24460   return values;
24461 };
24462
24463 var entries = function(map) {
24464   var entries = [];
24465   for (var key in map) entries.push({key: key, value: map[key]});
24466   return entries;
24467 };
24468
24469 function objectConverter(columns) {
24470   return new Function("d", "return {" + columns.map(function(name, i) {
24471     return JSON.stringify(name) + ": d[" + i + "]";
24472   }).join(",") + "}");
24473 }
24474
24475 function customConverter(columns, f) {
24476   var object = objectConverter(columns);
24477   return function(row, i) {
24478     return f(object(row), i, columns);
24479   };
24480 }
24481
24482 // Compute unique columns in order of discovery.
24483 function inferColumns(rows) {
24484   var columnSet = Object.create(null),
24485       columns = [];
24486
24487   rows.forEach(function(row) {
24488     for (var column in row) {
24489       if (!(column in columnSet)) {
24490         columns.push(columnSet[column] = column);
24491       }
24492     }
24493   });
24494
24495   return columns;
24496 }
24497
24498 var dsv = function(delimiter) {
24499   var reFormat = new RegExp("[\"" + delimiter + "\n\r]"),
24500       delimiterCode = delimiter.charCodeAt(0);
24501
24502   function parse(text, f) {
24503     var convert, columns, rows = parseRows(text, function(row, i) {
24504       if (convert) return convert(row, i - 1);
24505       columns = row, convert = f ? customConverter(row, f) : objectConverter(row);
24506     });
24507     rows.columns = columns;
24508     return rows;
24509   }
24510
24511   function parseRows(text, f) {
24512     var EOL = {}, // sentinel value for end-of-line
24513         EOF = {}, // sentinel value for end-of-file
24514         rows = [], // output rows
24515         N = text.length,
24516         I = 0, // current character index
24517         n = 0, // the current line number
24518         t, // the current token
24519         eol; // is the current token followed by EOL?
24520
24521     function token() {
24522       if (I >= N) return EOF; // special case: end of file
24523       if (eol) return eol = false, EOL; // special case: end of line
24524
24525       // special case: quotes
24526       var j = I, c;
24527       if (text.charCodeAt(j) === 34) {
24528         var i = j;
24529         while (i++ < N) {
24530           if (text.charCodeAt(i) === 34) {
24531             if (text.charCodeAt(i + 1) !== 34) break;
24532             ++i;
24533           }
24534         }
24535         I = i + 2;
24536         c = text.charCodeAt(i + 1);
24537         if (c === 13) {
24538           eol = true;
24539           if (text.charCodeAt(i + 2) === 10) ++I;
24540         } else if (c === 10) {
24541           eol = true;
24542         }
24543         return text.slice(j + 1, i).replace(/""/g, "\"");
24544       }
24545
24546       // common case: find next delimiter or newline
24547       while (I < N) {
24548         var k = 1;
24549         c = text.charCodeAt(I++);
24550         if (c === 10) eol = true; // \n
24551         else if (c === 13) { eol = true; if (text.charCodeAt(I) === 10) ++I, ++k; } // \r|\r\n
24552         else if (c !== delimiterCode) continue;
24553         return text.slice(j, I - k);
24554       }
24555
24556       // special case: last token before EOF
24557       return text.slice(j);
24558     }
24559
24560     while ((t = token()) !== EOF) {
24561       var a = [];
24562       while (t !== EOL && t !== EOF) {
24563         a.push(t);
24564         t = token();
24565       }
24566       if (f && (a = f(a, n++)) == null) continue;
24567       rows.push(a);
24568     }
24569
24570     return rows;
24571   }
24572
24573   function format(rows, columns) {
24574     if (columns == null) columns = inferColumns(rows);
24575     return [columns.map(formatValue).join(delimiter)].concat(rows.map(function(row) {
24576       return columns.map(function(column) {
24577         return formatValue(row[column]);
24578       }).join(delimiter);
24579     })).join("\n");
24580   }
24581
24582   function formatRows(rows) {
24583     return rows.map(formatRow).join("\n");
24584   }
24585
24586   function formatRow(row) {
24587     return row.map(formatValue).join(delimiter);
24588   }
24589
24590   function formatValue(text) {
24591     return text == null ? ""
24592         : reFormat.test(text += "") ? "\"" + text.replace(/\"/g, "\"\"") + "\""
24593         : text;
24594   }
24595
24596   return {
24597     parse: parse,
24598     parseRows: parseRows,
24599     format: format,
24600     formatRows: formatRows
24601   };
24602 };
24603
24604 var csv = dsv(",");
24605
24606 var csvParse = csv.parse;
24607 var csvParseRows = csv.parseRows;
24608 var csvFormat = csv.format;
24609 var csvFormatRows = csv.formatRows;
24610
24611 var tsv = dsv("\t");
24612
24613 var tsvParse = tsv.parse;
24614 var tsvParseRows = tsv.parseRows;
24615 var tsvFormat = tsv.format;
24616 var tsvFormatRows = tsv.formatRows;
24617
24618 var center$1 = function(x, y) {
24619   var nodes;
24620
24621   if (x == null) x = 0;
24622   if (y == null) y = 0;
24623
24624   function force() {
24625     var i,
24626         n = nodes.length,
24627         node,
24628         sx = 0,
24629         sy = 0;
24630
24631     for (i = 0; i < n; ++i) {
24632       node = nodes[i], sx += node.x, sy += node.y;
24633     }
24634
24635     for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) {
24636       node = nodes[i], node.x -= sx, node.y -= sy;
24637     }
24638   }
24639
24640   force.initialize = function(_) {
24641     nodes = _;
24642   };
24643
24644   force.x = function(_) {
24645     return arguments.length ? (x = +_, force) : x;
24646   };
24647
24648   force.y = function(_) {
24649     return arguments.length ? (y = +_, force) : y;
24650   };
24651
24652   return force;
24653 };
24654
24655 var constant$6 = function(x) {
24656   return function() {
24657     return x;
24658   };
24659 };
24660
24661 var jiggle = function() {
24662   return (Math.random() - 0.5) * 1e-6;
24663 };
24664
24665 var tree_add = function(d) {
24666   var x = +this._x.call(null, d),
24667       y = +this._y.call(null, d);
24668   return add(this.cover(x, y), x, y, d);
24669 };
24670
24671 function add(tree, x, y, d) {
24672   if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points
24673
24674   var parent,
24675       node = tree._root,
24676       leaf = {data: d},
24677       x0 = tree._x0,
24678       y0 = tree._y0,
24679       x1 = tree._x1,
24680       y1 = tree._y1,
24681       xm,
24682       ym,
24683       xp,
24684       yp,
24685       right,
24686       bottom,
24687       i,
24688       j;
24689
24690   // If the tree is empty, initialize the root as a leaf.
24691   if (!node) return tree._root = leaf, tree;
24692
24693   // Find the existing leaf for the new point, or add it.
24694   while (node.length) {
24695     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24696     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24697     if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree;
24698   }
24699
24700   // Is the new point is exactly coincident with the existing point?
24701   xp = +tree._x.call(null, node.data);
24702   yp = +tree._y.call(null, node.data);
24703   if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree;
24704
24705   // Otherwise, split the leaf node until the old and new point are separated.
24706   do {
24707     parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4);
24708     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24709     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24710   } while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm)));
24711   return parent[j] = node, parent[i] = leaf, tree;
24712 }
24713
24714 function addAll(data) {
24715   var d, i, n = data.length,
24716       x,
24717       y,
24718       xz = new Array(n),
24719       yz = new Array(n),
24720       x0 = Infinity,
24721       y0 = Infinity,
24722       x1 = -Infinity,
24723       y1 = -Infinity;
24724
24725   // Compute the points and their extent.
24726   for (i = 0; i < n; ++i) {
24727     if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue;
24728     xz[i] = x;
24729     yz[i] = y;
24730     if (x < x0) x0 = x;
24731     if (x > x1) x1 = x;
24732     if (y < y0) y0 = y;
24733     if (y > y1) y1 = y;
24734   }
24735
24736   // If there were no (valid) points, inherit the existing extent.
24737   if (x1 < x0) x0 = this._x0, x1 = this._x1;
24738   if (y1 < y0) y0 = this._y0, y1 = this._y1;
24739
24740   // Expand the tree to cover the new points.
24741   this.cover(x0, y0).cover(x1, y1);
24742
24743   // Add the new points.
24744   for (i = 0; i < n; ++i) {
24745     add(this, xz[i], yz[i], data[i]);
24746   }
24747
24748   return this;
24749 }
24750
24751 var tree_cover = function(x, y) {
24752   if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points
24753
24754   var x0 = this._x0,
24755       y0 = this._y0,
24756       x1 = this._x1,
24757       y1 = this._y1;
24758
24759   // If the quadtree has no extent, initialize them.
24760   // Integer extent are necessary so that if we later double the extent,
24761   // the existing quadrant boundaries don’t change due to floating point error!
24762   if (isNaN(x0)) {
24763     x1 = (x0 = Math.floor(x)) + 1;
24764     y1 = (y0 = Math.floor(y)) + 1;
24765   }
24766
24767   // Otherwise, double repeatedly to cover.
24768   else if (x0 > x || x > x1 || y0 > y || y > y1) {
24769     var z = x1 - x0,
24770         node = this._root,
24771         parent,
24772         i;
24773
24774     switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) {
24775       case 0: {
24776         do parent = new Array(4), parent[i] = node, node = parent;
24777         while (z *= 2, x1 = x0 + z, y1 = y0 + z, x > x1 || y > y1);
24778         break;
24779       }
24780       case 1: {
24781         do parent = new Array(4), parent[i] = node, node = parent;
24782         while (z *= 2, x0 = x1 - z, y1 = y0 + z, x0 > x || y > y1);
24783         break;
24784       }
24785       case 2: {
24786         do parent = new Array(4), parent[i] = node, node = parent;
24787         while (z *= 2, x1 = x0 + z, y0 = y1 - z, x > x1 || y0 > y);
24788         break;
24789       }
24790       case 3: {
24791         do parent = new Array(4), parent[i] = node, node = parent;
24792         while (z *= 2, x0 = x1 - z, y0 = y1 - z, x0 > x || y0 > y);
24793         break;
24794       }
24795     }
24796
24797     if (this._root && this._root.length) this._root = node;
24798   }
24799
24800   // If the quadtree covers the point already, just return.
24801   else return this;
24802
24803   this._x0 = x0;
24804   this._y0 = y0;
24805   this._x1 = x1;
24806   this._y1 = y1;
24807   return this;
24808 };
24809
24810 var tree_data = function() {
24811   var data = [];
24812   this.visit(function(node) {
24813     if (!node.length) do data.push(node.data); while (node = node.next)
24814   });
24815   return data;
24816 };
24817
24818 var tree_extent = function(_) {
24819   return arguments.length
24820       ? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1])
24821       : isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]];
24822 };
24823
24824 var Quad = function(node, x0, y0, x1, y1) {
24825   this.node = node;
24826   this.x0 = x0;
24827   this.y0 = y0;
24828   this.x1 = x1;
24829   this.y1 = y1;
24830 };
24831
24832 var tree_find = function(x, y, radius) {
24833   var data,
24834       x0 = this._x0,
24835       y0 = this._y0,
24836       x1,
24837       y1,
24838       x2,
24839       y2,
24840       x3 = this._x1,
24841       y3 = this._y1,
24842       quads = [],
24843       node = this._root,
24844       q,
24845       i;
24846
24847   if (node) quads.push(new Quad(node, x0, y0, x3, y3));
24848   if (radius == null) radius = Infinity;
24849   else {
24850     x0 = x - radius, y0 = y - radius;
24851     x3 = x + radius, y3 = y + radius;
24852     radius *= radius;
24853   }
24854
24855   while (q = quads.pop()) {
24856
24857     // Stop searching if this quadrant can’t contain a closer node.
24858     if (!(node = q.node)
24859         || (x1 = q.x0) > x3
24860         || (y1 = q.y0) > y3
24861         || (x2 = q.x1) < x0
24862         || (y2 = q.y1) < y0) continue;
24863
24864     // Bisect the current quadrant.
24865     if (node.length) {
24866       var xm = (x1 + x2) / 2,
24867           ym = (y1 + y2) / 2;
24868
24869       quads.push(
24870         new Quad(node[3], xm, ym, x2, y2),
24871         new Quad(node[2], x1, ym, xm, y2),
24872         new Quad(node[1], xm, y1, x2, ym),
24873         new Quad(node[0], x1, y1, xm, ym)
24874       );
24875
24876       // Visit the closest quadrant first.
24877       if (i = (y >= ym) << 1 | (x >= xm)) {
24878         q = quads[quads.length - 1];
24879         quads[quads.length - 1] = quads[quads.length - 1 - i];
24880         quads[quads.length - 1 - i] = q;
24881       }
24882     }
24883
24884     // Visit this point. (Visiting coincident points isn’t necessary!)
24885     else {
24886       var dx = x - +this._x.call(null, node.data),
24887           dy = y - +this._y.call(null, node.data),
24888           d2 = dx * dx + dy * dy;
24889       if (d2 < radius) {
24890         var d = Math.sqrt(radius = d2);
24891         x0 = x - d, y0 = y - d;
24892         x3 = x + d, y3 = y + d;
24893         data = node.data;
24894       }
24895     }
24896   }
24897
24898   return data;
24899 };
24900
24901 var tree_remove = function(d) {
24902   if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points
24903
24904   var parent,
24905       node = this._root,
24906       retainer,
24907       previous,
24908       next,
24909       x0 = this._x0,
24910       y0 = this._y0,
24911       x1 = this._x1,
24912       y1 = this._y1,
24913       x,
24914       y,
24915       xm,
24916       ym,
24917       right,
24918       bottom,
24919       i,
24920       j;
24921
24922   // If the tree is empty, initialize the root as a leaf.
24923   if (!node) return this;
24924
24925   // Find the leaf node for the point.
24926   // While descending, also retain the deepest parent with a non-removed sibling.
24927   if (node.length) while (true) {
24928     if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
24929     if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
24930     if (!(parent = node, node = node[i = bottom << 1 | right])) return this;
24931     if (!node.length) break;
24932     if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i;
24933   }
24934
24935   // Find the point to remove.
24936   while (node.data !== d) if (!(previous = node, node = node.next)) return this;
24937   if (next = node.next) delete node.next;
24938
24939   // If there are multiple coincident points, remove just the point.
24940   if (previous) return (next ? previous.next = next : delete previous.next), this;
24941
24942   // If this is the root point, remove it.
24943   if (!parent) return this._root = next, this;
24944
24945   // Remove this leaf.
24946   next ? parent[i] = next : delete parent[i];
24947
24948   // If the parent now contains exactly one leaf, collapse superfluous parents.
24949   if ((node = parent[0] || parent[1] || parent[2] || parent[3])
24950       && node === (parent[3] || parent[2] || parent[1] || parent[0])
24951       && !node.length) {
24952     if (retainer) retainer[j] = node;
24953     else this._root = node;
24954   }
24955
24956   return this;
24957 };
24958
24959 function removeAll(data) {
24960   for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]);
24961   return this;
24962 }
24963
24964 var tree_root = function() {
24965   return this._root;
24966 };
24967
24968 var tree_size = function() {
24969   var size = 0;
24970   this.visit(function(node) {
24971     if (!node.length) do ++size; while (node = node.next)
24972   });
24973   return size;
24974 };
24975
24976 var tree_visit = function(callback) {
24977   var quads = [], q, node = this._root, child, x0, y0, x1, y1;
24978   if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1));
24979   while (q = quads.pop()) {
24980     if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) {
24981       var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
24982       if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
24983       if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
24984       if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
24985       if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
24986     }
24987   }
24988   return this;
24989 };
24990
24991 var tree_visitAfter = function(callback) {
24992   var quads = [], next = [], q;
24993   if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1));
24994   while (q = quads.pop()) {
24995     var node = q.node;
24996     if (node.length) {
24997       var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
24998       if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
24999       if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
25000       if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
25001       if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
25002     }
25003     next.push(q);
25004   }
25005   while (q = next.pop()) {
25006     callback(q.node, q.x0, q.y0, q.x1, q.y1);
25007   }
25008   return this;
25009 };
25010
25011 function defaultX(d) {
25012   return d[0];
25013 }
25014
25015 var tree_x = function(_) {
25016   return arguments.length ? (this._x = _, this) : this._x;
25017 };
25018
25019 function defaultY(d) {
25020   return d[1];
25021 }
25022
25023 var tree_y = function(_) {
25024   return arguments.length ? (this._y = _, this) : this._y;
25025 };
25026
25027 function quadtree(nodes, x, y) {
25028   var tree = new Quadtree(x == null ? defaultX : x, y == null ? defaultY : y, NaN, NaN, NaN, NaN);
25029   return nodes == null ? tree : tree.addAll(nodes);
25030 }
25031
25032 function Quadtree(x, y, x0, y0, x1, y1) {
25033   this._x = x;
25034   this._y = y;
25035   this._x0 = x0;
25036   this._y0 = y0;
25037   this._x1 = x1;
25038   this._y1 = y1;
25039   this._root = undefined;
25040 }
25041
25042 function leaf_copy(leaf) {
25043   var copy = {data: leaf.data}, next = copy;
25044   while (leaf = leaf.next) next = next.next = {data: leaf.data};
25045   return copy;
25046 }
25047
25048 var treeProto = quadtree.prototype = Quadtree.prototype;
25049
25050 treeProto.copy = function() {
25051   var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1),
25052       node = this._root,
25053       nodes,
25054       child;
25055
25056   if (!node) return copy;
25057
25058   if (!node.length) return copy._root = leaf_copy(node), copy;
25059
25060   nodes = [{source: node, target: copy._root = new Array(4)}];
25061   while (node = nodes.pop()) {
25062     for (var i = 0; i < 4; ++i) {
25063       if (child = node.source[i]) {
25064         if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)});
25065         else node.target[i] = leaf_copy(child);
25066       }
25067     }
25068   }
25069
25070   return copy;
25071 };
25072
25073 treeProto.add = tree_add;
25074 treeProto.addAll = addAll;
25075 treeProto.cover = tree_cover;
25076 treeProto.data = tree_data;
25077 treeProto.extent = tree_extent;
25078 treeProto.find = tree_find;
25079 treeProto.remove = tree_remove;
25080 treeProto.removeAll = removeAll;
25081 treeProto.root = tree_root;
25082 treeProto.size = tree_size;
25083 treeProto.visit = tree_visit;
25084 treeProto.visitAfter = tree_visitAfter;
25085 treeProto.x = tree_x;
25086 treeProto.y = tree_y;
25087
25088 function x(d) {
25089   return d.x + d.vx;
25090 }
25091
25092 function y(d) {
25093   return d.y + d.vy;
25094 }
25095
25096 var collide = function(radius) {
25097   var nodes,
25098       radii,
25099       strength = 1,
25100       iterations = 1;
25101
25102   if (typeof radius !== "function") radius = constant$6(radius == null ? 1 : +radius);
25103
25104   function force() {
25105     var i, n = nodes.length,
25106         tree,
25107         node,
25108         xi,
25109         yi,
25110         ri,
25111         ri2;
25112
25113     for (var k = 0; k < iterations; ++k) {
25114       tree = quadtree(nodes, x, y).visitAfter(prepare);
25115       for (i = 0; i < n; ++i) {
25116         node = nodes[i];
25117         ri = radii[node.index], ri2 = ri * ri;
25118         xi = node.x + node.vx;
25119         yi = node.y + node.vy;
25120         tree.visit(apply);
25121       }
25122     }
25123
25124     function apply(quad, x0, y0, x1, y1) {
25125       var data = quad.data, rj = quad.r, r = ri + rj;
25126       if (data) {
25127         if (data.index > node.index) {
25128           var x = xi - data.x - data.vx,
25129               y = yi - data.y - data.vy,
25130               l = x * x + y * y;
25131           if (l < r * r) {
25132             if (x === 0) x = jiggle(), l += x * x;
25133             if (y === 0) y = jiggle(), l += y * y;
25134             l = (r - (l = Math.sqrt(l))) / l * strength;
25135             node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
25136             node.vy += (y *= l) * r;
25137             data.vx -= x * (r = 1 - r);
25138             data.vy -= y * r;
25139           }
25140         }
25141         return;
25142       }
25143       return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r;
25144     }
25145   }
25146
25147   function prepare(quad) {
25148     if (quad.data) return quad.r = radii[quad.data.index];
25149     for (var i = quad.r = 0; i < 4; ++i) {
25150       if (quad[i] && quad[i].r > quad.r) {
25151         quad.r = quad[i].r;
25152       }
25153     }
25154   }
25155
25156   function initialize() {
25157     if (!nodes) return;
25158     var i, n = nodes.length, node;
25159     radii = new Array(n);
25160     for (i = 0; i < n; ++i) node = nodes[i], radii[node.index] = +radius(node, i, nodes);
25161   }
25162
25163   force.initialize = function(_) {
25164     nodes = _;
25165     initialize();
25166   };
25167
25168   force.iterations = function(_) {
25169     return arguments.length ? (iterations = +_, force) : iterations;
25170   };
25171
25172   force.strength = function(_) {
25173     return arguments.length ? (strength = +_, force) : strength;
25174   };
25175
25176   force.radius = function(_) {
25177     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : radius;
25178   };
25179
25180   return force;
25181 };
25182
25183 function index$3(d) {
25184   return d.index;
25185 }
25186
25187 function find(nodeById, nodeId) {
25188   var node = nodeById.get(nodeId);
25189   if (!node) throw new Error("missing: " + nodeId);
25190   return node;
25191 }
25192
25193 var link = function(links) {
25194   var id = index$3,
25195       strength = defaultStrength,
25196       strengths,
25197       distance = constant$6(30),
25198       distances,
25199       nodes,
25200       count,
25201       bias,
25202       iterations = 1;
25203
25204   if (links == null) links = [];
25205
25206   function defaultStrength(link) {
25207     return 1 / Math.min(count[link.source.index], count[link.target.index]);
25208   }
25209
25210   function force(alpha) {
25211     for (var k = 0, n = links.length; k < iterations; ++k) {
25212       for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) {
25213         link = links[i], source = link.source, target = link.target;
25214         x = target.x + target.vx - source.x - source.vx || jiggle();
25215         y = target.y + target.vy - source.y - source.vy || jiggle();
25216         l = Math.sqrt(x * x + y * y);
25217         l = (l - distances[i]) / l * alpha * strengths[i];
25218         x *= l, y *= l;
25219         target.vx -= x * (b = bias[i]);
25220         target.vy -= y * b;
25221         source.vx += x * (b = 1 - b);
25222         source.vy += y * b;
25223       }
25224     }
25225   }
25226
25227   function initialize() {
25228     if (!nodes) return;
25229
25230     var i,
25231         n = nodes.length,
25232         m = links.length,
25233         nodeById = map$1(nodes, id),
25234         link;
25235
25236     for (i = 0, count = new Array(n); i < m; ++i) {
25237       link = links[i], link.index = i;
25238       if (typeof link.source !== "object") link.source = find(nodeById, link.source);
25239       if (typeof link.target !== "object") link.target = find(nodeById, link.target);
25240       count[link.source.index] = (count[link.source.index] || 0) + 1;
25241       count[link.target.index] = (count[link.target.index] || 0) + 1;
25242     }
25243
25244     for (i = 0, bias = new Array(m); i < m; ++i) {
25245       link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]);
25246     }
25247
25248     strengths = new Array(m), initializeStrength();
25249     distances = new Array(m), initializeDistance();
25250   }
25251
25252   function initializeStrength() {
25253     if (!nodes) return;
25254
25255     for (var i = 0, n = links.length; i < n; ++i) {
25256       strengths[i] = +strength(links[i], i, links);
25257     }
25258   }
25259
25260   function initializeDistance() {
25261     if (!nodes) return;
25262
25263     for (var i = 0, n = links.length; i < n; ++i) {
25264       distances[i] = +distance(links[i], i, links);
25265     }
25266   }
25267
25268   force.initialize = function(_) {
25269     nodes = _;
25270     initialize();
25271   };
25272
25273   force.links = function(_) {
25274     return arguments.length ? (links = _, initialize(), force) : links;
25275   };
25276
25277   force.id = function(_) {
25278     return arguments.length ? (id = _, force) : id;
25279   };
25280
25281   force.iterations = function(_) {
25282     return arguments.length ? (iterations = +_, force) : iterations;
25283   };
25284
25285   force.strength = function(_) {
25286     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initializeStrength(), force) : strength;
25287   };
25288
25289   force.distance = function(_) {
25290     return arguments.length ? (distance = typeof _ === "function" ? _ : constant$6(+_), initializeDistance(), force) : distance;
25291   };
25292
25293   return force;
25294 };
25295
25296 function x$1(d) {
25297   return d.x;
25298 }
25299
25300 function y$1(d) {
25301   return d.y;
25302 }
25303
25304 var initialRadius = 10;
25305 var initialAngle = Math.PI * (3 - Math.sqrt(5));
25306
25307 var simulation = function(nodes) {
25308   var simulation,
25309       alpha = 1,
25310       alphaMin = 0.001,
25311       alphaDecay = 1 - Math.pow(alphaMin, 1 / 300),
25312       alphaTarget = 0,
25313       velocityDecay = 0.6,
25314       forces = map$1(),
25315       stepper = timer(step),
25316       event = dispatch("tick", "end");
25317
25318   if (nodes == null) nodes = [];
25319
25320   function step() {
25321     tick();
25322     event.call("tick", simulation);
25323     if (alpha < alphaMin) {
25324       stepper.stop();
25325       event.call("end", simulation);
25326     }
25327   }
25328
25329   function tick() {
25330     var i, n = nodes.length, node;
25331
25332     alpha += (alphaTarget - alpha) * alphaDecay;
25333
25334     forces.each(function(force) {
25335       force(alpha);
25336     });
25337
25338     for (i = 0; i < n; ++i) {
25339       node = nodes[i];
25340       if (node.fx == null) node.x += node.vx *= velocityDecay;
25341       else node.x = node.fx, node.vx = 0;
25342       if (node.fy == null) node.y += node.vy *= velocityDecay;
25343       else node.y = node.fy, node.vy = 0;
25344     }
25345   }
25346
25347   function initializeNodes() {
25348     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25349       node = nodes[i], node.index = i;
25350       if (isNaN(node.x) || isNaN(node.y)) {
25351         var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle;
25352         node.x = radius * Math.cos(angle);
25353         node.y = radius * Math.sin(angle);
25354       }
25355       if (isNaN(node.vx) || isNaN(node.vy)) {
25356         node.vx = node.vy = 0;
25357       }
25358     }
25359   }
25360
25361   function initializeForce(force) {
25362     if (force.initialize) force.initialize(nodes);
25363     return force;
25364   }
25365
25366   initializeNodes();
25367
25368   return simulation = {
25369     tick: tick,
25370
25371     restart: function() {
25372       return stepper.restart(step), simulation;
25373     },
25374
25375     stop: function() {
25376       return stepper.stop(), simulation;
25377     },
25378
25379     nodes: function(_) {
25380       return arguments.length ? (nodes = _, initializeNodes(), forces.each(initializeForce), simulation) : nodes;
25381     },
25382
25383     alpha: function(_) {
25384       return arguments.length ? (alpha = +_, simulation) : alpha;
25385     },
25386
25387     alphaMin: function(_) {
25388       return arguments.length ? (alphaMin = +_, simulation) : alphaMin;
25389     },
25390
25391     alphaDecay: function(_) {
25392       return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay;
25393     },
25394
25395     alphaTarget: function(_) {
25396       return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget;
25397     },
25398
25399     velocityDecay: function(_) {
25400       return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay;
25401     },
25402
25403     force: function(name, _) {
25404       return arguments.length > 1 ? ((_ == null ? forces.remove(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name);
25405     },
25406
25407     find: function(x, y, radius) {
25408       var i = 0,
25409           n = nodes.length,
25410           dx,
25411           dy,
25412           d2,
25413           node,
25414           closest;
25415
25416       if (radius == null) radius = Infinity;
25417       else radius *= radius;
25418
25419       for (i = 0; i < n; ++i) {
25420         node = nodes[i];
25421         dx = x - node.x;
25422         dy = y - node.y;
25423         d2 = dx * dx + dy * dy;
25424         if (d2 < radius) closest = node, radius = d2;
25425       }
25426
25427       return closest;
25428     },
25429
25430     on: function(name, _) {
25431       return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name);
25432     }
25433   };
25434 };
25435
25436 var manyBody = function() {
25437   var nodes,
25438       node,
25439       alpha,
25440       strength = constant$6(-30),
25441       strengths,
25442       distanceMin2 = 1,
25443       distanceMax2 = Infinity,
25444       theta2 = 0.81;
25445
25446   function force(_) {
25447     var i, n = nodes.length, tree = quadtree(nodes, x$1, y$1).visitAfter(accumulate);
25448     for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
25449   }
25450
25451   function initialize() {
25452     if (!nodes) return;
25453     var i, n = nodes.length, node;
25454     strengths = new Array(n);
25455     for (i = 0; i < n; ++i) node = nodes[i], strengths[node.index] = +strength(node, i, nodes);
25456   }
25457
25458   function accumulate(quad) {
25459     var strength = 0, q, c, x, y, i;
25460
25461     // For internal nodes, accumulate forces from child quadrants.
25462     if (quad.length) {
25463       for (x = y = i = 0; i < 4; ++i) {
25464         if ((q = quad[i]) && (c = q.value)) {
25465           strength += c, x += c * q.x, y += c * q.y;
25466         }
25467       }
25468       quad.x = x / strength;
25469       quad.y = y / strength;
25470     }
25471
25472     // For leaf nodes, accumulate forces from coincident quadrants.
25473     else {
25474       q = quad;
25475       q.x = q.data.x;
25476       q.y = q.data.y;
25477       do strength += strengths[q.data.index];
25478       while (q = q.next);
25479     }
25480
25481     quad.value = strength;
25482   }
25483
25484   function apply(quad, x1, _, x2) {
25485     if (!quad.value) return true;
25486
25487     var x = quad.x - node.x,
25488         y = quad.y - node.y,
25489         w = x2 - x1,
25490         l = x * x + y * y;
25491
25492     // Apply the Barnes-Hut approximation if possible.
25493     // Limit forces for very close nodes; randomize direction if coincident.
25494     if (w * w / theta2 < l) {
25495       if (l < distanceMax2) {
25496         if (x === 0) x = jiggle(), l += x * x;
25497         if (y === 0) y = jiggle(), l += y * y;
25498         if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
25499         node.vx += x * quad.value * alpha / l;
25500         node.vy += y * quad.value * alpha / l;
25501       }
25502       return true;
25503     }
25504
25505     // Otherwise, process points directly.
25506     else if (quad.length || l >= distanceMax2) return;
25507
25508     // Limit forces for very close nodes; randomize direction if coincident.
25509     if (quad.data !== node || quad.next) {
25510       if (x === 0) x = jiggle(), l += x * x;
25511       if (y === 0) y = jiggle(), l += y * y;
25512       if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
25513     }
25514
25515     do if (quad.data !== node) {
25516       w = strengths[quad.data.index] * alpha / l;
25517       node.vx += x * w;
25518       node.vy += y * w;
25519     } while (quad = quad.next);
25520   }
25521
25522   force.initialize = function(_) {
25523     nodes = _;
25524     initialize();
25525   };
25526
25527   force.strength = function(_) {
25528     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25529   };
25530
25531   force.distanceMin = function(_) {
25532     return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
25533   };
25534
25535   force.distanceMax = function(_) {
25536     return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
25537   };
25538
25539   force.theta = function(_) {
25540     return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
25541   };
25542
25543   return force;
25544 };
25545
25546 var x$2 = function(x) {
25547   var strength = constant$6(0.1),
25548       nodes,
25549       strengths,
25550       xz;
25551
25552   if (typeof x !== "function") x = constant$6(x == null ? 0 : +x);
25553
25554   function force(alpha) {
25555     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25556       node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha;
25557     }
25558   }
25559
25560   function initialize() {
25561     if (!nodes) return;
25562     var i, n = nodes.length;
25563     strengths = new Array(n);
25564     xz = new Array(n);
25565     for (i = 0; i < n; ++i) {
25566       strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
25567     }
25568   }
25569
25570   force.initialize = function(_) {
25571     nodes = _;
25572     initialize();
25573   };
25574
25575   force.strength = function(_) {
25576     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25577   };
25578
25579   force.x = function(_) {
25580     return arguments.length ? (x = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : x;
25581   };
25582
25583   return force;
25584 };
25585
25586 var y$2 = function(y) {
25587   var strength = constant$6(0.1),
25588       nodes,
25589       strengths,
25590       yz;
25591
25592   if (typeof y !== "function") y = constant$6(y == null ? 0 : +y);
25593
25594   function force(alpha) {
25595     for (var i = 0, n = nodes.length, node; i < n; ++i) {
25596       node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha;
25597     }
25598   }
25599
25600   function initialize() {
25601     if (!nodes) return;
25602     var i, n = nodes.length;
25603     strengths = new Array(n);
25604     yz = new Array(n);
25605     for (i = 0; i < n; ++i) {
25606       strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
25607     }
25608   }
25609
25610   force.initialize = function(_) {
25611     nodes = _;
25612     initialize();
25613   };
25614
25615   force.strength = function(_) {
25616     return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
25617   };
25618
25619   force.y = function(_) {
25620     return arguments.length ? (y = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : y;
25621   };
25622
25623   return force;
25624 };
25625
25626 // Computes the decimal coefficient and exponent of the specified number x with
25627 // significant digits p, where x is positive and p is in [1, 21] or undefined.
25628 // For example, formatDecimal(1.23) returns ["123", 0].
25629 var formatDecimal = function(x, p) {
25630   if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
25631   var i, coefficient = x.slice(0, i);
25632
25633   // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
25634   // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
25635   return [
25636     coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
25637     +x.slice(i + 1)
25638   ];
25639 };
25640
25641 var exponent$1 = function(x) {
25642   return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;
25643 };
25644
25645 var formatGroup = function(grouping, thousands) {
25646   return function(value, width) {
25647     var i = value.length,
25648         t = [],
25649         j = 0,
25650         g = grouping[0],
25651         length = 0;
25652
25653     while (i > 0 && g > 0) {
25654       if (length + g + 1 > width) g = Math.max(1, width - length);
25655       t.push(value.substring(i -= g, i + g));
25656       if ((length += g + 1) > width) break;
25657       g = grouping[j = (j + 1) % grouping.length];
25658     }
25659
25660     return t.reverse().join(thousands);
25661   };
25662 };
25663
25664 var formatNumerals = function(numerals) {
25665   return function(value) {
25666     return value.replace(/[0-9]/g, function(i) {
25667       return numerals[+i];
25668     });
25669   };
25670 };
25671
25672 var formatDefault = function(x, p) {
25673   x = x.toPrecision(p);
25674
25675   out: for (var n = x.length, i = 1, i0 = -1, i1; i < n; ++i) {
25676     switch (x[i]) {
25677       case ".": i0 = i1 = i; break;
25678       case "0": if (i0 === 0) i0 = i; i1 = i; break;
25679       case "e": break out;
25680       default: if (i0 > 0) i0 = 0; break;
25681     }
25682   }
25683
25684   return i0 > 0 ? x.slice(0, i0) + x.slice(i1 + 1) : x;
25685 };
25686
25687 var prefixExponent;
25688
25689 var formatPrefixAuto = function(x, p) {
25690   var d = formatDecimal(x, p);
25691   if (!d) return x + "";
25692   var coefficient = d[0],
25693       exponent = d[1],
25694       i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
25695       n = coefficient.length;
25696   return i === n ? coefficient
25697       : i > n ? coefficient + new Array(i - n + 1).join("0")
25698       : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
25699       : "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!
25700 };
25701
25702 var formatRounded = function(x, p) {
25703   var d = formatDecimal(x, p);
25704   if (!d) return x + "";
25705   var coefficient = d[0],
25706       exponent = d[1];
25707   return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
25708       : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
25709       : coefficient + new Array(exponent - coefficient.length + 2).join("0");
25710 };
25711
25712 var formatTypes = {
25713   "": formatDefault,
25714   "%": function(x, p) { return (x * 100).toFixed(p); },
25715   "b": function(x) { return Math.round(x).toString(2); },
25716   "c": function(x) { return x + ""; },
25717   "d": function(x) { return Math.round(x).toString(10); },
25718   "e": function(x, p) { return x.toExponential(p); },
25719   "f": function(x, p) { return x.toFixed(p); },
25720   "g": function(x, p) { return x.toPrecision(p); },
25721   "o": function(x) { return Math.round(x).toString(8); },
25722   "p": function(x, p) { return formatRounded(x * 100, p); },
25723   "r": formatRounded,
25724   "s": formatPrefixAuto,
25725   "X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
25726   "x": function(x) { return Math.round(x).toString(16); }
25727 };
25728
25729 // [[fill]align][sign][symbol][0][width][,][.precision][type]
25730 var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;
25731
25732 function formatSpecifier(specifier) {
25733   return new FormatSpecifier(specifier);
25734 }
25735
25736 formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
25737
25738 function FormatSpecifier(specifier) {
25739   if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
25740
25741   var match,
25742       fill = match[1] || " ",
25743       align = match[2] || ">",
25744       sign = match[3] || "-",
25745       symbol = match[4] || "",
25746       zero = !!match[5],
25747       width = match[6] && +match[6],
25748       comma = !!match[7],
25749       precision = match[8] && +match[8].slice(1),
25750       type = match[9] || "";
25751
25752   // The "n" type is an alias for ",g".
25753   if (type === "n") comma = true, type = "g";
25754
25755   // Map invalid types to the default format.
25756   else if (!formatTypes[type]) type = "";
25757
25758   // If zero fill is specified, padding goes after sign and before digits.
25759   if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
25760
25761   this.fill = fill;
25762   this.align = align;
25763   this.sign = sign;
25764   this.symbol = symbol;
25765   this.zero = zero;
25766   this.width = width;
25767   this.comma = comma;
25768   this.precision = precision;
25769   this.type = type;
25770 }
25771
25772 FormatSpecifier.prototype.toString = function() {
25773   return this.fill
25774       + this.align
25775       + this.sign
25776       + this.symbol
25777       + (this.zero ? "0" : "")
25778       + (this.width == null ? "" : Math.max(1, this.width | 0))
25779       + (this.comma ? "," : "")
25780       + (this.precision == null ? "" : "." + Math.max(0, this.precision | 0))
25781       + this.type;
25782 };
25783
25784 var identity$3 = function(x) {
25785   return x;
25786 };
25787
25788 var prefixes = ["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];
25789
25790 var formatLocale = function(locale) {
25791   var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity$3,
25792       currency = locale.currency,
25793       decimal = locale.decimal,
25794       numerals = locale.numerals ? formatNumerals(locale.numerals) : identity$3,
25795       percent = locale.percent || "%";
25796
25797   function newFormat(specifier) {
25798     specifier = formatSpecifier(specifier);
25799
25800     var fill = specifier.fill,
25801         align = specifier.align,
25802         sign = specifier.sign,
25803         symbol = specifier.symbol,
25804         zero = specifier.zero,
25805         width = specifier.width,
25806         comma = specifier.comma,
25807         precision = specifier.precision,
25808         type = specifier.type;
25809
25810     // Compute the prefix and suffix.
25811     // For SI-prefix, the suffix is lazily computed.
25812     var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
25813         suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? percent : "";
25814
25815     // What format function should we use?
25816     // Is this an integer type?
25817     // Can this type generate exponential notation?
25818     var formatType = formatTypes[type],
25819         maybeSuffix = !type || /[defgprs%]/.test(type);
25820
25821     // Set the default precision if not specified,
25822     // or clamp the specified precision to the supported range.
25823     // For significant precision, it must be in [1, 21].
25824     // For fixed precision, it must be in [0, 20].
25825     precision = precision == null ? (type ? 6 : 12)
25826         : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
25827         : Math.max(0, Math.min(20, precision));
25828
25829     function format(value) {
25830       var valuePrefix = prefix,
25831           valueSuffix = suffix,
25832           i, n, c;
25833
25834       if (type === "c") {
25835         valueSuffix = formatType(value) + valueSuffix;
25836         value = "";
25837       } else {
25838         value = +value;
25839
25840         // Perform the initial formatting.
25841         var valueNegative = value < 0;
25842         value = formatType(Math.abs(value), precision);
25843
25844         // If a negative value rounds to zero during formatting, treat as positive.
25845         if (valueNegative && +value === 0) valueNegative = false;
25846
25847         // Compute the prefix and suffix.
25848         valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
25849         valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
25850
25851         // Break the formatted value into the integer “value” part that can be
25852         // grouped, and fractional or exponential “suffix” part that is not.
25853         if (maybeSuffix) {
25854           i = -1, n = value.length;
25855           while (++i < n) {
25856             if (c = value.charCodeAt(i), 48 > c || c > 57) {
25857               valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
25858               value = value.slice(0, i);
25859               break;
25860             }
25861           }
25862         }
25863       }
25864
25865       // If the fill character is not "0", grouping is applied before padding.
25866       if (comma && !zero) value = group(value, Infinity);
25867
25868       // Compute the padding.
25869       var length = valuePrefix.length + value.length + valueSuffix.length,
25870           padding = length < width ? new Array(width - length + 1).join(fill) : "";
25871
25872       // If the fill character is "0", grouping is applied after padding.
25873       if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
25874
25875       // Reconstruct the final output based on the desired alignment.
25876       switch (align) {
25877         case "<": value = valuePrefix + value + valueSuffix + padding; break;
25878         case "=": value = valuePrefix + padding + value + valueSuffix; break;
25879         case "^": value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length); break;
25880         default: value = padding + valuePrefix + value + valueSuffix; break;
25881       }
25882
25883       return numerals(value);
25884     }
25885
25886     format.toString = function() {
25887       return specifier + "";
25888     };
25889
25890     return format;
25891   }
25892
25893   function formatPrefix(specifier, value) {
25894     var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
25895         e = Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3,
25896         k = Math.pow(10, -e),
25897         prefix = prefixes[8 + e / 3];
25898     return function(value) {
25899       return f(k * value) + prefix;
25900     };
25901   }
25902
25903   return {
25904     format: newFormat,
25905     formatPrefix: formatPrefix
25906   };
25907 };
25908
25909 var locale$1;
25910 var format;
25911 var formatPrefix;
25912
25913 defaultLocale({
25914   decimal: ".",
25915   thousands: ",",
25916   grouping: [3],
25917   currency: ["$", ""]
25918 });
25919
25920 function defaultLocale(definition) {
25921   locale$1 = formatLocale(definition);
25922   format = locale$1.format;
25923   formatPrefix = locale$1.formatPrefix;
25924   return locale$1;
25925 }
25926
25927 var precisionFixed = function(step) {
25928   return Math.max(0, -exponent$1(Math.abs(step)));
25929 };
25930
25931 var precisionPrefix = function(step, value) {
25932   return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3 - exponent$1(Math.abs(step)));
25933 };
25934
25935 var precisionRound = function(step, max) {
25936   step = Math.abs(step), max = Math.abs(max) - step;
25937   return Math.max(0, exponent$1(max) - exponent$1(step)) + 1;
25938 };
25939
25940 // Adds floating point numbers with twice the normal precision.
25941 // Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and
25942 // Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3)
25943 // 305–363 (1997).
25944 // Code adapted from GeographicLib by Charles F. F. Karney,
25945 // http://geographiclib.sourceforge.net/
25946
25947 var adder = function() {
25948   return new Adder;
25949 };
25950
25951 function Adder() {
25952   this.reset();
25953 }
25954
25955 Adder.prototype = {
25956   constructor: Adder,
25957   reset: function() {
25958     this.s = // rounded value
25959     this.t = 0; // exact error
25960   },
25961   add: function(y) {
25962     add$1(temp, y, this.t);
25963     add$1(this, temp.s, this.s);
25964     if (this.s) this.t += temp.t;
25965     else this.s = temp.t;
25966   },
25967   valueOf: function() {
25968     return this.s;
25969   }
25970 };
25971
25972 var temp = new Adder;
25973
25974 function add$1(adder, a, b) {
25975   var x = adder.s = a + b,
25976       bv = x - a,
25977       av = x - bv;
25978   adder.t = (a - av) + (b - bv);
25979 }
25980
25981 var epsilon$2 = 1e-6;
25982 var epsilon2$1 = 1e-12;
25983 var pi$3 = Math.PI;
25984 var halfPi$2 = pi$3 / 2;
25985 var quarterPi = pi$3 / 4;
25986 var tau$3 = pi$3 * 2;
25987
25988 var degrees$1 = 180 / pi$3;
25989 var radians = pi$3 / 180;
25990
25991 var abs = Math.abs;
25992 var atan = Math.atan;
25993 var atan2 = Math.atan2;
25994 var cos$1 = Math.cos;
25995 var ceil = Math.ceil;
25996 var exp = Math.exp;
25997
25998 var log = Math.log;
25999 var pow = Math.pow;
26000 var sin$1 = Math.sin;
26001 var sign = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; };
26002 var sqrt = Math.sqrt;
26003 var tan = Math.tan;
26004
26005 function acos(x) {
26006   return x > 1 ? 0 : x < -1 ? pi$3 : Math.acos(x);
26007 }
26008
26009 function asin(x) {
26010   return x > 1 ? halfPi$2 : x < -1 ? -halfPi$2 : Math.asin(x);
26011 }
26012
26013 function haversin(x) {
26014   return (x = sin$1(x / 2)) * x;
26015 }
26016
26017 function noop$1() {}
26018
26019 function streamGeometry(geometry, stream) {
26020   if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
26021     streamGeometryType[geometry.type](geometry, stream);
26022   }
26023 }
26024
26025 var streamObjectType = {
26026   Feature: function(object, stream) {
26027     streamGeometry(object.geometry, stream);
26028   },
26029   FeatureCollection: function(object, stream) {
26030     var features = object.features, i = -1, n = features.length;
26031     while (++i < n) streamGeometry(features[i].geometry, stream);
26032   }
26033 };
26034
26035 var streamGeometryType = {
26036   Sphere: function(object, stream) {
26037     stream.sphere();
26038   },
26039   Point: function(object, stream) {
26040     object = object.coordinates;
26041     stream.point(object[0], object[1], object[2]);
26042   },
26043   MultiPoint: function(object, stream) {
26044     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26045     while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]);
26046   },
26047   LineString: function(object, stream) {
26048     streamLine(object.coordinates, stream, 0);
26049   },
26050   MultiLineString: function(object, stream) {
26051     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26052     while (++i < n) streamLine(coordinates[i], stream, 0);
26053   },
26054   Polygon: function(object, stream) {
26055     streamPolygon(object.coordinates, stream);
26056   },
26057   MultiPolygon: function(object, stream) {
26058     var coordinates = object.coordinates, i = -1, n = coordinates.length;
26059     while (++i < n) streamPolygon(coordinates[i], stream);
26060   },
26061   GeometryCollection: function(object, stream) {
26062     var geometries = object.geometries, i = -1, n = geometries.length;
26063     while (++i < n) streamGeometry(geometries[i], stream);
26064   }
26065 };
26066
26067 function streamLine(coordinates, stream, closed) {
26068   var i = -1, n = coordinates.length - closed, coordinate;
26069   stream.lineStart();
26070   while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
26071   stream.lineEnd();
26072 }
26073
26074 function streamPolygon(coordinates, stream) {
26075   var i = -1, n = coordinates.length;
26076   stream.polygonStart();
26077   while (++i < n) streamLine(coordinates[i], stream, 1);
26078   stream.polygonEnd();
26079 }
26080
26081 var geoStream = function(object, stream) {
26082   if (object && streamObjectType.hasOwnProperty(object.type)) {
26083     streamObjectType[object.type](object, stream);
26084   } else {
26085     streamGeometry(object, stream);
26086   }
26087 };
26088
26089 var areaRingSum = adder();
26090
26091 var areaSum = adder();
26092 var lambda00;
26093 var phi00;
26094 var lambda0;
26095 var cosPhi0;
26096 var sinPhi0;
26097
26098 var areaStream = {
26099   point: noop$1,
26100   lineStart: noop$1,
26101   lineEnd: noop$1,
26102   polygonStart: function() {
26103     areaRingSum.reset();
26104     areaStream.lineStart = areaRingStart;
26105     areaStream.lineEnd = areaRingEnd;
26106   },
26107   polygonEnd: function() {
26108     var areaRing = +areaRingSum;
26109     areaSum.add(areaRing < 0 ? tau$3 + areaRing : areaRing);
26110     this.lineStart = this.lineEnd = this.point = noop$1;
26111   },
26112   sphere: function() {
26113     areaSum.add(tau$3);
26114   }
26115 };
26116
26117 function areaRingStart() {
26118   areaStream.point = areaPointFirst;
26119 }
26120
26121 function areaRingEnd() {
26122   areaPoint(lambda00, phi00);
26123 }
26124
26125 function areaPointFirst(lambda, phi) {
26126   areaStream.point = areaPoint;
26127   lambda00 = lambda, phi00 = phi;
26128   lambda *= radians, phi *= radians;
26129   lambda0 = lambda, cosPhi0 = cos$1(phi = phi / 2 + quarterPi), sinPhi0 = sin$1(phi);
26130 }
26131
26132 function areaPoint(lambda, phi) {
26133   lambda *= radians, phi *= radians;
26134   phi = phi / 2 + quarterPi; // half the angular distance from south pole
26135
26136   // Spherical excess E for a spherical triangle with vertices: south pole,
26137   // previous point, current point.  Uses a formula derived from Cagnoli’s
26138   // theorem.  See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
26139   var dLambda = lambda - lambda0,
26140       sdLambda = dLambda >= 0 ? 1 : -1,
26141       adLambda = sdLambda * dLambda,
26142       cosPhi = cos$1(phi),
26143       sinPhi = sin$1(phi),
26144       k = sinPhi0 * sinPhi,
26145       u = cosPhi0 * cosPhi + k * cos$1(adLambda),
26146       v = k * sdLambda * sin$1(adLambda);
26147   areaRingSum.add(atan2(v, u));
26148
26149   // Advance the previous points.
26150   lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
26151 }
26152
26153 var area = function(object) {
26154   areaSum.reset();
26155   geoStream(object, areaStream);
26156   return areaSum * 2;
26157 };
26158
26159 function spherical(cartesian) {
26160   return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
26161 }
26162
26163 function cartesian(spherical) {
26164   var lambda = spherical[0], phi = spherical[1], cosPhi = cos$1(phi);
26165   return [cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi)];
26166 }
26167
26168 function cartesianDot(a, b) {
26169   return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
26170 }
26171
26172 function cartesianCross(a, b) {
26173   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]];
26174 }
26175
26176 // TODO return a
26177 function cartesianAddInPlace(a, b) {
26178   a[0] += b[0], a[1] += b[1], a[2] += b[2];
26179 }
26180
26181 function cartesianScale(vector, k) {
26182   return [vector[0] * k, vector[1] * k, vector[2] * k];
26183 }
26184
26185 // TODO return d
26186 function cartesianNormalizeInPlace(d) {
26187   var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
26188   d[0] /= l, d[1] /= l, d[2] /= l;
26189 }
26190
26191 var lambda0$1;
26192 var phi0;
26193 var lambda1;
26194 var phi1;
26195 var lambda2;
26196 var lambda00$1;
26197 var phi00$1;
26198 var p0;
26199 var deltaSum = adder();
26200 var ranges;
26201 var range;
26202
26203 var boundsStream = {
26204   point: boundsPoint,
26205   lineStart: boundsLineStart,
26206   lineEnd: boundsLineEnd,
26207   polygonStart: function() {
26208     boundsStream.point = boundsRingPoint;
26209     boundsStream.lineStart = boundsRingStart;
26210     boundsStream.lineEnd = boundsRingEnd;
26211     deltaSum.reset();
26212     areaStream.polygonStart();
26213   },
26214   polygonEnd: function() {
26215     areaStream.polygonEnd();
26216     boundsStream.point = boundsPoint;
26217     boundsStream.lineStart = boundsLineStart;
26218     boundsStream.lineEnd = boundsLineEnd;
26219     if (areaRingSum < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
26220     else if (deltaSum > epsilon$2) phi1 = 90;
26221     else if (deltaSum < -epsilon$2) phi0 = -90;
26222     range[0] = lambda0$1, range[1] = lambda1;
26223   }
26224 };
26225
26226 function boundsPoint(lambda, phi) {
26227   ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
26228   if (phi < phi0) phi0 = phi;
26229   if (phi > phi1) phi1 = phi;
26230 }
26231
26232 function linePoint(lambda, phi) {
26233   var p = cartesian([lambda * radians, phi * radians]);
26234   if (p0) {
26235     var normal = cartesianCross(p0, p),
26236         equatorial = [normal[1], -normal[0], 0],
26237         inflection = cartesianCross(equatorial, normal);
26238     cartesianNormalizeInPlace(inflection);
26239     inflection = spherical(inflection);
26240     var delta = lambda - lambda2,
26241         sign$$1 = delta > 0 ? 1 : -1,
26242         lambdai = inflection[0] * degrees$1 * sign$$1,
26243         phii,
26244         antimeridian = abs(delta) > 180;
26245     if (antimeridian ^ (sign$$1 * lambda2 < lambdai && lambdai < sign$$1 * lambda)) {
26246       phii = inflection[1] * degrees$1;
26247       if (phii > phi1) phi1 = phii;
26248     } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign$$1 * lambda2 < lambdai && lambdai < sign$$1 * lambda)) {
26249       phii = -inflection[1] * degrees$1;
26250       if (phii < phi0) phi0 = phii;
26251     } else {
26252       if (phi < phi0) phi0 = phi;
26253       if (phi > phi1) phi1 = phi;
26254     }
26255     if (antimeridian) {
26256       if (lambda < lambda2) {
26257         if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
26258       } else {
26259         if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
26260       }
26261     } else {
26262       if (lambda1 >= lambda0$1) {
26263         if (lambda < lambda0$1) lambda0$1 = lambda;
26264         if (lambda > lambda1) lambda1 = lambda;
26265       } else {
26266         if (lambda > lambda2) {
26267           if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
26268         } else {
26269           if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
26270         }
26271       }
26272     }
26273   } else {
26274     ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
26275   }
26276   if (phi < phi0) phi0 = phi;
26277   if (phi > phi1) phi1 = phi;
26278   p0 = p, lambda2 = lambda;
26279 }
26280
26281 function boundsLineStart() {
26282   boundsStream.point = linePoint;
26283 }
26284
26285 function boundsLineEnd() {
26286   range[0] = lambda0$1, range[1] = lambda1;
26287   boundsStream.point = boundsPoint;
26288   p0 = null;
26289 }
26290
26291 function boundsRingPoint(lambda, phi) {
26292   if (p0) {
26293     var delta = lambda - lambda2;
26294     deltaSum.add(abs(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
26295   } else {
26296     lambda00$1 = lambda, phi00$1 = phi;
26297   }
26298   areaStream.point(lambda, phi);
26299   linePoint(lambda, phi);
26300 }
26301
26302 function boundsRingStart() {
26303   areaStream.lineStart();
26304 }
26305
26306 function boundsRingEnd() {
26307   boundsRingPoint(lambda00$1, phi00$1);
26308   areaStream.lineEnd();
26309   if (abs(deltaSum) > epsilon$2) lambda0$1 = -(lambda1 = 180);
26310   range[0] = lambda0$1, range[1] = lambda1;
26311   p0 = null;
26312 }
26313
26314 // Finds the left-right distance between two longitudes.
26315 // This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
26316 // the distance between ±180° to be 360°.
26317 function angle(lambda0, lambda1) {
26318   return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
26319 }
26320
26321 function rangeCompare(a, b) {
26322   return a[0] - b[0];
26323 }
26324
26325 function rangeContains(range, x) {
26326   return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
26327 }
26328
26329 var bounds = function(feature) {
26330   var i, n, a, b, merged, deltaMax, delta;
26331
26332   phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
26333   ranges = [];
26334   geoStream(feature, boundsStream);
26335
26336   // First, sort ranges by their minimum longitudes.
26337   if (n = ranges.length) {
26338     ranges.sort(rangeCompare);
26339
26340     // Then, merge any ranges that overlap.
26341     for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
26342       b = ranges[i];
26343       if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
26344         if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
26345         if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
26346       } else {
26347         merged.push(a = b);
26348       }
26349     }
26350
26351     // Finally, find the largest gap between the merged ranges.
26352     // The final bounding box will be the inverse of this gap.
26353     for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
26354       b = merged[i];
26355       if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
26356     }
26357   }
26358
26359   ranges = range = null;
26360
26361   return lambda0$1 === Infinity || phi0 === Infinity
26362       ? [[NaN, NaN], [NaN, NaN]]
26363       : [[lambda0$1, phi0], [lambda1, phi1]];
26364 };
26365
26366 var W0;
26367 var W1;
26368 var X0;
26369 var Y0;
26370 var Z0;
26371 var X1;
26372 var Y1;
26373 var Z1;
26374 var X2;
26375 var Y2;
26376 var Z2;
26377 var lambda00$2;
26378 var phi00$2;
26379 var x0;
26380 var y0;
26381 var z0; // previous point
26382
26383 var centroidStream = {
26384   sphere: noop$1,
26385   point: centroidPoint,
26386   lineStart: centroidLineStart,
26387   lineEnd: centroidLineEnd,
26388   polygonStart: function() {
26389     centroidStream.lineStart = centroidRingStart;
26390     centroidStream.lineEnd = centroidRingEnd;
26391   },
26392   polygonEnd: function() {
26393     centroidStream.lineStart = centroidLineStart;
26394     centroidStream.lineEnd = centroidLineEnd;
26395   }
26396 };
26397
26398 // Arithmetic mean of Cartesian vectors.
26399 function centroidPoint(lambda, phi) {
26400   lambda *= radians, phi *= radians;
26401   var cosPhi = cos$1(phi);
26402   centroidPointCartesian(cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(phi));
26403 }
26404
26405 function centroidPointCartesian(x, y, z) {
26406   ++W0;
26407   X0 += (x - X0) / W0;
26408   Y0 += (y - Y0) / W0;
26409   Z0 += (z - Z0) / W0;
26410 }
26411
26412 function centroidLineStart() {
26413   centroidStream.point = centroidLinePointFirst;
26414 }
26415
26416 function centroidLinePointFirst(lambda, phi) {
26417   lambda *= radians, phi *= radians;
26418   var cosPhi = cos$1(phi);
26419   x0 = cosPhi * cos$1(lambda);
26420   y0 = cosPhi * sin$1(lambda);
26421   z0 = sin$1(phi);
26422   centroidStream.point = centroidLinePoint;
26423   centroidPointCartesian(x0, y0, z0);
26424 }
26425
26426 function centroidLinePoint(lambda, phi) {
26427   lambda *= radians, phi *= radians;
26428   var cosPhi = cos$1(phi),
26429       x = cosPhi * cos$1(lambda),
26430       y = cosPhi * sin$1(lambda),
26431       z = sin$1(phi),
26432       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);
26433   W1 += w;
26434   X1 += w * (x0 + (x0 = x));
26435   Y1 += w * (y0 + (y0 = y));
26436   Z1 += w * (z0 + (z0 = z));
26437   centroidPointCartesian(x0, y0, z0);
26438 }
26439
26440 function centroidLineEnd() {
26441   centroidStream.point = centroidPoint;
26442 }
26443
26444 // See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
26445 // J. Applied Mechanics 42, 239 (1975).
26446 function centroidRingStart() {
26447   centroidStream.point = centroidRingPointFirst;
26448 }
26449
26450 function centroidRingEnd() {
26451   centroidRingPoint(lambda00$2, phi00$2);
26452   centroidStream.point = centroidPoint;
26453 }
26454
26455 function centroidRingPointFirst(lambda, phi) {
26456   lambda00$2 = lambda, phi00$2 = phi;
26457   lambda *= radians, phi *= radians;
26458   centroidStream.point = centroidRingPoint;
26459   var cosPhi = cos$1(phi);
26460   x0 = cosPhi * cos$1(lambda);
26461   y0 = cosPhi * sin$1(lambda);
26462   z0 = sin$1(phi);
26463   centroidPointCartesian(x0, y0, z0);
26464 }
26465
26466 function centroidRingPoint(lambda, phi) {
26467   lambda *= radians, phi *= radians;
26468   var cosPhi = cos$1(phi),
26469       x = cosPhi * cos$1(lambda),
26470       y = cosPhi * sin$1(lambda),
26471       z = sin$1(phi),
26472       cx = y0 * z - z0 * y,
26473       cy = z0 * x - x0 * z,
26474       cz = x0 * y - y0 * x,
26475       m = sqrt(cx * cx + cy * cy + cz * cz),
26476       w = asin(m), // line weight = angle
26477       v = m && -w / m; // area weight multiplier
26478   X2 += v * cx;
26479   Y2 += v * cy;
26480   Z2 += v * cz;
26481   W1 += w;
26482   X1 += w * (x0 + (x0 = x));
26483   Y1 += w * (y0 + (y0 = y));
26484   Z1 += w * (z0 + (z0 = z));
26485   centroidPointCartesian(x0, y0, z0);
26486 }
26487
26488 var d3GeoCentroid = function(object) {
26489   W0 = W1 =
26490   X0 = Y0 = Z0 =
26491   X1 = Y1 = Z1 =
26492   X2 = Y2 = Z2 = 0;
26493   geoStream(object, centroidStream);
26494
26495   var x = X2,
26496       y = Y2,
26497       z = Z2,
26498       m = x * x + y * y + z * z;
26499
26500   // If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
26501   if (m < epsilon2$1) {
26502     x = X1, y = Y1, z = Z1;
26503     // If the feature has zero length, fall back to arithmetic mean of point vectors.
26504     if (W1 < epsilon$2) x = X0, y = Y0, z = Z0;
26505     m = x * x + y * y + z * z;
26506     // If the feature still has an undefined ccentroid, then return.
26507     if (m < epsilon2$1) return [NaN, NaN];
26508   }
26509
26510   return [atan2(y, x) * degrees$1, asin(z / sqrt(m)) * degrees$1];
26511 };
26512
26513 var constant$7 = function(x) {
26514   return function() {
26515     return x;
26516   };
26517 };
26518
26519 var compose = function(a, b) {
26520
26521   function compose(x, y) {
26522     return x = a(x, y), b(x[0], x[1]);
26523   }
26524
26525   if (a.invert && b.invert) compose.invert = function(x, y) {
26526     return x = b.invert(x, y), x && a.invert(x[0], x[1]);
26527   };
26528
26529   return compose;
26530 };
26531
26532 function rotationIdentity(lambda, phi) {
26533   return [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
26534 }
26535
26536 rotationIdentity.invert = rotationIdentity;
26537
26538 function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
26539   return (deltaLambda %= tau$3) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma))
26540     : rotationLambda(deltaLambda))
26541     : (deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma)
26542     : rotationIdentity);
26543 }
26544
26545 function forwardRotationLambda(deltaLambda) {
26546   return function(lambda, phi) {
26547     return lambda += deltaLambda, [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
26548   };
26549 }
26550
26551 function rotationLambda(deltaLambda) {
26552   var rotation = forwardRotationLambda(deltaLambda);
26553   rotation.invert = forwardRotationLambda(-deltaLambda);
26554   return rotation;
26555 }
26556
26557 function rotationPhiGamma(deltaPhi, deltaGamma) {
26558   var cosDeltaPhi = cos$1(deltaPhi),
26559       sinDeltaPhi = sin$1(deltaPhi),
26560       cosDeltaGamma = cos$1(deltaGamma),
26561       sinDeltaGamma = sin$1(deltaGamma);
26562
26563   function rotation(lambda, phi) {
26564     var cosPhi = cos$1(phi),
26565         x = cos$1(lambda) * cosPhi,
26566         y = sin$1(lambda) * cosPhi,
26567         z = sin$1(phi),
26568         k = z * cosDeltaPhi + x * sinDeltaPhi;
26569     return [
26570       atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi),
26571       asin(k * cosDeltaGamma + y * sinDeltaGamma)
26572     ];
26573   }
26574
26575   rotation.invert = function(lambda, phi) {
26576     var cosPhi = cos$1(phi),
26577         x = cos$1(lambda) * cosPhi,
26578         y = sin$1(lambda) * cosPhi,
26579         z = sin$1(phi),
26580         k = z * cosDeltaGamma - y * sinDeltaGamma;
26581     return [
26582       atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi),
26583       asin(k * cosDeltaPhi - x * sinDeltaPhi)
26584     ];
26585   };
26586
26587   return rotation;
26588 }
26589
26590 var rotation = function(rotate) {
26591   rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
26592
26593   function forward(coordinates) {
26594     coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
26595     return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
26596   }
26597
26598   forward.invert = function(coordinates) {
26599     coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
26600     return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
26601   };
26602
26603   return forward;
26604 };
26605
26606 // Generates a circle centered at [0°, 0°], with a given radius and precision.
26607 function circleStream(stream, radius, delta, direction, t0, t1) {
26608   if (!delta) return;
26609   var cosRadius = cos$1(radius),
26610       sinRadius = sin$1(radius),
26611       step = direction * delta;
26612   if (t0 == null) {
26613     t0 = radius + direction * tau$3;
26614     t1 = radius - step / 2;
26615   } else {
26616     t0 = circleRadius(cosRadius, t0);
26617     t1 = circleRadius(cosRadius, t1);
26618     if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau$3;
26619   }
26620   for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
26621     point = spherical([cosRadius, -sinRadius * cos$1(t), -sinRadius * sin$1(t)]);
26622     stream.point(point[0], point[1]);
26623   }
26624 }
26625
26626 // Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
26627 function circleRadius(cosRadius, point) {
26628   point = cartesian(point), point[0] -= cosRadius;
26629   cartesianNormalizeInPlace(point);
26630   var radius = acos(-point[1]);
26631   return ((-point[2] < 0 ? -radius : radius) + tau$3 - epsilon$2) % tau$3;
26632 }
26633
26634 var circle = function() {
26635   var center = constant$7([0, 0]),
26636       radius = constant$7(90),
26637       precision = constant$7(6),
26638       ring,
26639       rotate,
26640       stream = {point: point};
26641
26642   function point(x, y) {
26643     ring.push(x = rotate(x, y));
26644     x[0] *= degrees$1, x[1] *= degrees$1;
26645   }
26646
26647   function circle() {
26648     var c = center.apply(this, arguments),
26649         r = radius.apply(this, arguments) * radians,
26650         p = precision.apply(this, arguments) * radians;
26651     ring = [];
26652     rotate = rotateRadians(-c[0] * radians, -c[1] * radians, 0).invert;
26653     circleStream(stream, r, p, 1);
26654     c = {type: "Polygon", coordinates: [ring]};
26655     ring = rotate = null;
26656     return c;
26657   }
26658
26659   circle.center = function(_) {
26660     return arguments.length ? (center = typeof _ === "function" ? _ : constant$7([+_[0], +_[1]]), circle) : center;
26661   };
26662
26663   circle.radius = function(_) {
26664     return arguments.length ? (radius = typeof _ === "function" ? _ : constant$7(+_), circle) : radius;
26665   };
26666
26667   circle.precision = function(_) {
26668     return arguments.length ? (precision = typeof _ === "function" ? _ : constant$7(+_), circle) : precision;
26669   };
26670
26671   return circle;
26672 };
26673
26674 var clipBuffer = function() {
26675   var lines = [],
26676       line;
26677   return {
26678     point: function(x, y) {
26679       line.push([x, y]);
26680     },
26681     lineStart: function() {
26682       lines.push(line = []);
26683     },
26684     lineEnd: noop$1,
26685     rejoin: function() {
26686       if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
26687     },
26688     result: function() {
26689       var result = lines;
26690       lines = [];
26691       line = null;
26692       return result;
26693     }
26694   };
26695 };
26696
26697 var clipLine = function(a, b, x0, y0, x1, y1) {
26698   var ax = a[0],
26699       ay = a[1],
26700       bx = b[0],
26701       by = b[1],
26702       t0 = 0,
26703       t1 = 1,
26704       dx = bx - ax,
26705       dy = by - ay,
26706       r;
26707
26708   r = x0 - ax;
26709   if (!dx && r > 0) return;
26710   r /= dx;
26711   if (dx < 0) {
26712     if (r < t0) return;
26713     if (r < t1) t1 = r;
26714   } else if (dx > 0) {
26715     if (r > t1) return;
26716     if (r > t0) t0 = r;
26717   }
26718
26719   r = x1 - ax;
26720   if (!dx && r < 0) return;
26721   r /= dx;
26722   if (dx < 0) {
26723     if (r > t1) return;
26724     if (r > t0) t0 = r;
26725   } else if (dx > 0) {
26726     if (r < t0) return;
26727     if (r < t1) t1 = r;
26728   }
26729
26730   r = y0 - ay;
26731   if (!dy && r > 0) return;
26732   r /= dy;
26733   if (dy < 0) {
26734     if (r < t0) return;
26735     if (r < t1) t1 = r;
26736   } else if (dy > 0) {
26737     if (r > t1) return;
26738     if (r > t0) t0 = r;
26739   }
26740
26741   r = y1 - ay;
26742   if (!dy && r < 0) return;
26743   r /= dy;
26744   if (dy < 0) {
26745     if (r > t1) return;
26746     if (r > t0) t0 = r;
26747   } else if (dy > 0) {
26748     if (r < t0) return;
26749     if (r < t1) t1 = r;
26750   }
26751
26752   if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
26753   if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
26754   return true;
26755 };
26756
26757 var pointEqual = function(a, b) {
26758   return abs(a[0] - b[0]) < epsilon$2 && abs(a[1] - b[1]) < epsilon$2;
26759 };
26760
26761 function Intersection(point, points, other, entry) {
26762   this.x = point;
26763   this.z = points;
26764   this.o = other; // another intersection
26765   this.e = entry; // is an entry?
26766   this.v = false; // visited
26767   this.n = this.p = null; // next & previous
26768 }
26769
26770 // A generalized polygon clipping algorithm: given a polygon that has been cut
26771 // into its visible line segments, and rejoins the segments by interpolating
26772 // along the clip edge.
26773 var clipPolygon = function(segments, compareIntersection, startInside, interpolate, stream) {
26774   var subject = [],
26775       clip = [],
26776       i,
26777       n;
26778
26779   segments.forEach(function(segment) {
26780     if ((n = segment.length - 1) <= 0) return;
26781     var n, p0 = segment[0], p1 = segment[n], x;
26782
26783     // If the first and last points of a segment are coincident, then treat as a
26784     // closed ring. TODO if all rings are closed, then the winding order of the
26785     // exterior ring should be checked.
26786     if (pointEqual(p0, p1)) {
26787       stream.lineStart();
26788       for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]);
26789       stream.lineEnd();
26790       return;
26791     }
26792
26793     subject.push(x = new Intersection(p0, segment, null, true));
26794     clip.push(x.o = new Intersection(p0, null, x, false));
26795     subject.push(x = new Intersection(p1, segment, null, false));
26796     clip.push(x.o = new Intersection(p1, null, x, true));
26797   });
26798
26799   if (!subject.length) return;
26800
26801   clip.sort(compareIntersection);
26802   link$1(subject);
26803   link$1(clip);
26804
26805   for (i = 0, n = clip.length; i < n; ++i) {
26806     clip[i].e = startInside = !startInside;
26807   }
26808
26809   var start = subject[0],
26810       points,
26811       point;
26812
26813   while (1) {
26814     // Find first unvisited intersection.
26815     var current = start,
26816         isSubject = true;
26817     while (current.v) if ((current = current.n) === start) return;
26818     points = current.z;
26819     stream.lineStart();
26820     do {
26821       current.v = current.o.v = true;
26822       if (current.e) {
26823         if (isSubject) {
26824           for (i = 0, n = points.length; i < n; ++i) stream.point((point = points[i])[0], point[1]);
26825         } else {
26826           interpolate(current.x, current.n.x, 1, stream);
26827         }
26828         current = current.n;
26829       } else {
26830         if (isSubject) {
26831           points = current.p.z;
26832           for (i = points.length - 1; i >= 0; --i) stream.point((point = points[i])[0], point[1]);
26833         } else {
26834           interpolate(current.x, current.p.x, -1, stream);
26835         }
26836         current = current.p;
26837       }
26838       current = current.o;
26839       points = current.z;
26840       isSubject = !isSubject;
26841     } while (!current.v);
26842     stream.lineEnd();
26843   }
26844 };
26845
26846 function link$1(array) {
26847   if (!(n = array.length)) return;
26848   var n,
26849       i = 0,
26850       a = array[0],
26851       b;
26852   while (++i < n) {
26853     a.n = b = array[i];
26854     b.p = a;
26855     a = b;
26856   }
26857   a.n = b = array[0];
26858   b.p = a;
26859 }
26860
26861 var clipMax = 1e9;
26862 var clipMin = -clipMax;
26863
26864 // TODO Use d3-polygon’s polygonContains here for the ring check?
26865 // TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
26866
26867 function clipExtent(x0, y0, x1, y1) {
26868
26869   function visible(x, y) {
26870     return x0 <= x && x <= x1 && y0 <= y && y <= y1;
26871   }
26872
26873   function interpolate(from, to, direction, stream) {
26874     var a = 0, a1 = 0;
26875     if (from == null
26876         || (a = corner(from, direction)) !== (a1 = corner(to, direction))
26877         || comparePoint(from, to) < 0 ^ direction > 0) {
26878       do stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
26879       while ((a = (a + direction + 4) % 4) !== a1);
26880     } else {
26881       stream.point(to[0], to[1]);
26882     }
26883   }
26884
26885   function corner(p, direction) {
26886     return abs(p[0] - x0) < epsilon$2 ? direction > 0 ? 0 : 3
26887         : abs(p[0] - x1) < epsilon$2 ? direction > 0 ? 2 : 1
26888         : abs(p[1] - y0) < epsilon$2 ? direction > 0 ? 1 : 0
26889         : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
26890   }
26891
26892   function compareIntersection(a, b) {
26893     return comparePoint(a.x, b.x);
26894   }
26895
26896   function comparePoint(a, b) {
26897     var ca = corner(a, 1),
26898         cb = corner(b, 1);
26899     return ca !== cb ? ca - cb
26900         : ca === 0 ? b[1] - a[1]
26901         : ca === 1 ? a[0] - b[0]
26902         : ca === 2 ? a[1] - b[1]
26903         : b[0] - a[0];
26904   }
26905
26906   return function(stream) {
26907     var activeStream = stream,
26908         bufferStream = clipBuffer(),
26909         segments,
26910         polygon,
26911         ring,
26912         x__, y__, v__, // first point
26913         x_, y_, v_, // previous point
26914         first,
26915         clean;
26916
26917     var clipStream = {
26918       point: point,
26919       lineStart: lineStart,
26920       lineEnd: lineEnd,
26921       polygonStart: polygonStart,
26922       polygonEnd: polygonEnd
26923     };
26924
26925     function point(x, y) {
26926       if (visible(x, y)) activeStream.point(x, y);
26927     }
26928
26929     function polygonInside() {
26930       var winding = 0;
26931
26932       for (var i = 0, n = polygon.length; i < n; ++i) {
26933         for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
26934           a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
26935           if (a1 <= y1) { if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding; }
26936           else { if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding; }
26937         }
26938       }
26939
26940       return winding;
26941     }
26942
26943     // Buffer geometry within a polygon and then clip it en masse.
26944     function polygonStart() {
26945       activeStream = bufferStream, segments = [], polygon = [], clean = true;
26946     }
26947
26948     function polygonEnd() {
26949       var startInside = polygonInside(),
26950           cleanInside = clean && startInside,
26951           visible = (segments = merge(segments)).length;
26952       if (cleanInside || visible) {
26953         stream.polygonStart();
26954         if (cleanInside) {
26955           stream.lineStart();
26956           interpolate(null, null, 1, stream);
26957           stream.lineEnd();
26958         }
26959         if (visible) {
26960           clipPolygon(segments, compareIntersection, startInside, interpolate, stream);
26961         }
26962         stream.polygonEnd();
26963       }
26964       activeStream = stream, segments = polygon = ring = null;
26965     }
26966
26967     function lineStart() {
26968       clipStream.point = linePoint;
26969       if (polygon) polygon.push(ring = []);
26970       first = true;
26971       v_ = false;
26972       x_ = y_ = NaN;
26973     }
26974
26975     // TODO rather than special-case polygons, simply handle them separately.
26976     // Ideally, coincident intersection points should be jittered to avoid
26977     // clipping issues.
26978     function lineEnd() {
26979       if (segments) {
26980         linePoint(x__, y__);
26981         if (v__ && v_) bufferStream.rejoin();
26982         segments.push(bufferStream.result());
26983       }
26984       clipStream.point = point;
26985       if (v_) activeStream.lineEnd();
26986     }
26987
26988     function linePoint(x, y) {
26989       var v = visible(x, y);
26990       if (polygon) ring.push([x, y]);
26991       if (first) {
26992         x__ = x, y__ = y, v__ = v;
26993         first = false;
26994         if (v) {
26995           activeStream.lineStart();
26996           activeStream.point(x, y);
26997         }
26998       } else {
26999         if (v && v_) activeStream.point(x, y);
27000         else {
27001           var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
27002               b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
27003           if (clipLine(a, b, x0, y0, x1, y1)) {
27004             if (!v_) {
27005               activeStream.lineStart();
27006               activeStream.point(a[0], a[1]);
27007             }
27008             activeStream.point(b[0], b[1]);
27009             if (!v) activeStream.lineEnd();
27010             clean = false;
27011           } else if (v) {
27012             activeStream.lineStart();
27013             activeStream.point(x, y);
27014             clean = false;
27015           }
27016         }
27017       }
27018       x_ = x, y_ = y, v_ = v;
27019     }
27020
27021     return clipStream;
27022   };
27023 }
27024
27025 var extent$1 = function() {
27026   var x0 = 0,
27027       y0 = 0,
27028       x1 = 960,
27029       y1 = 500,
27030       cache,
27031       cacheStream,
27032       clip;
27033
27034   return clip = {
27035     stream: function(stream) {
27036       return cache && cacheStream === stream ? cache : cache = clipExtent(x0, y0, x1, y1)(cacheStream = stream);
27037     },
27038     extent: function(_) {
27039       return arguments.length ? (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1], cache = cacheStream = null, clip) : [[x0, y0], [x1, y1]];
27040     }
27041   };
27042 };
27043
27044 var sum$1 = adder();
27045
27046 var polygonContains = function(polygon, point) {
27047   var lambda = point[0],
27048       phi = point[1],
27049       normal = [sin$1(lambda), -cos$1(lambda), 0],
27050       angle = 0,
27051       winding = 0;
27052
27053   sum$1.reset();
27054
27055   for (var i = 0, n = polygon.length; i < n; ++i) {
27056     if (!(m = (ring = polygon[i]).length)) continue;
27057     var ring,
27058         m,
27059         point0 = ring[m - 1],
27060         lambda0 = point0[0],
27061         phi0 = point0[1] / 2 + quarterPi,
27062         sinPhi0 = sin$1(phi0),
27063         cosPhi0 = cos$1(phi0);
27064
27065     for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
27066       var point1 = ring[j],
27067           lambda1 = point1[0],
27068           phi1 = point1[1] / 2 + quarterPi,
27069           sinPhi1 = sin$1(phi1),
27070           cosPhi1 = cos$1(phi1),
27071           delta = lambda1 - lambda0,
27072           sign$$1 = delta >= 0 ? 1 : -1,
27073           absDelta = sign$$1 * delta,
27074           antimeridian = absDelta > pi$3,
27075           k = sinPhi0 * sinPhi1;
27076
27077       sum$1.add(atan2(k * sign$$1 * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta)));
27078       angle += antimeridian ? delta + sign$$1 * tau$3 : delta;
27079
27080       // Are the longitudes either side of the point’s meridian (lambda),
27081       // and are the latitudes smaller than the parallel (phi)?
27082       if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
27083         var arc = cartesianCross(cartesian(point0), cartesian(point1));
27084         cartesianNormalizeInPlace(arc);
27085         var intersection = cartesianCross(normal, arc);
27086         cartesianNormalizeInPlace(intersection);
27087         var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
27088         if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
27089           winding += antimeridian ^ delta >= 0 ? 1 : -1;
27090         }
27091       }
27092     }
27093   }
27094
27095   // First, determine whether the South pole is inside or outside:
27096   //
27097   // It is inside if:
27098   // * the polygon winds around it in a clockwise direction.
27099   // * the polygon does not (cumulatively) wind around it, but has a negative
27100   //   (counter-clockwise) area.
27101   //
27102   // Second, count the (signed) number of times a segment crosses a lambda
27103   // from the point to the South pole.  If it is zero, then the point is the
27104   // same side as the South pole.
27105
27106   return (angle < -epsilon$2 || angle < epsilon$2 && sum$1 < -epsilon$2) ^ (winding & 1);
27107 };
27108
27109 var lengthSum = adder();
27110 var lambda0$2;
27111 var sinPhi0$1;
27112 var cosPhi0$1;
27113
27114 var lengthStream = {
27115   sphere: noop$1,
27116   point: noop$1,
27117   lineStart: lengthLineStart,
27118   lineEnd: noop$1,
27119   polygonStart: noop$1,
27120   polygonEnd: noop$1
27121 };
27122
27123 function lengthLineStart() {
27124   lengthStream.point = lengthPointFirst;
27125   lengthStream.lineEnd = lengthLineEnd;
27126 }
27127
27128 function lengthLineEnd() {
27129   lengthStream.point = lengthStream.lineEnd = noop$1;
27130 }
27131
27132 function lengthPointFirst(lambda, phi) {
27133   lambda *= radians, phi *= radians;
27134   lambda0$2 = lambda, sinPhi0$1 = sin$1(phi), cosPhi0$1 = cos$1(phi);
27135   lengthStream.point = lengthPoint;
27136 }
27137
27138 function lengthPoint(lambda, phi) {
27139   lambda *= radians, phi *= radians;
27140   var sinPhi = sin$1(phi),
27141       cosPhi = cos$1(phi),
27142       delta = abs(lambda - lambda0$2),
27143       cosDelta = cos$1(delta),
27144       sinDelta = sin$1(delta),
27145       x = cosPhi * sinDelta,
27146       y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta,
27147       z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta;
27148   lengthSum.add(atan2(sqrt(x * x + y * y), z));
27149   lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi;
27150 }
27151
27152 var d3GeoLength = function(object) {
27153   lengthSum.reset();
27154   geoStream(object, lengthStream);
27155   return +lengthSum;
27156 };
27157
27158 var coordinates = [null, null];
27159 var object$1 = {type: "LineString", coordinates: coordinates};
27160
27161 var distance = function(a, b) {
27162   coordinates[0] = a;
27163   coordinates[1] = b;
27164   return d3GeoLength(object$1);
27165 };
27166
27167 var containsObjectType = {
27168   Feature: function(object, point) {
27169     return containsGeometry(object.geometry, point);
27170   },
27171   FeatureCollection: function(object, point) {
27172     var features = object.features, i = -1, n = features.length;
27173     while (++i < n) if (containsGeometry(features[i].geometry, point)) return true;
27174     return false;
27175   }
27176 };
27177
27178 var containsGeometryType = {
27179   Sphere: function() {
27180     return true;
27181   },
27182   Point: function(object, point) {
27183     return containsPoint(object.coordinates, point);
27184   },
27185   MultiPoint: function(object, point) {
27186     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27187     while (++i < n) if (containsPoint(coordinates[i], point)) return true;
27188     return false;
27189   },
27190   LineString: function(object, point) {
27191     return containsLine(object.coordinates, point);
27192   },
27193   MultiLineString: function(object, point) {
27194     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27195     while (++i < n) if (containsLine(coordinates[i], point)) return true;
27196     return false;
27197   },
27198   Polygon: function(object, point) {
27199     return containsPolygon(object.coordinates, point);
27200   },
27201   MultiPolygon: function(object, point) {
27202     var coordinates = object.coordinates, i = -1, n = coordinates.length;
27203     while (++i < n) if (containsPolygon(coordinates[i], point)) return true;
27204     return false;
27205   },
27206   GeometryCollection: function(object, point) {
27207     var geometries = object.geometries, i = -1, n = geometries.length;
27208     while (++i < n) if (containsGeometry(geometries[i], point)) return true;
27209     return false;
27210   }
27211 };
27212
27213 function containsGeometry(geometry, point) {
27214   return geometry && containsGeometryType.hasOwnProperty(geometry.type)
27215       ? containsGeometryType[geometry.type](geometry, point)
27216       : false;
27217 }
27218
27219 function containsPoint(coordinates, point) {
27220   return distance(coordinates, point) === 0;
27221 }
27222
27223 function containsLine(coordinates, point) {
27224   var ab = distance(coordinates[0], coordinates[1]),
27225       ao = distance(coordinates[0], point),
27226       ob = distance(point, coordinates[1]);
27227   return ao + ob <= ab + epsilon$2;
27228 }
27229
27230 function containsPolygon(coordinates, point) {
27231   return !!polygonContains(coordinates.map(ringRadians), pointRadians(point));
27232 }
27233
27234 function ringRadians(ring) {
27235   return ring = ring.map(pointRadians), ring.pop(), ring;
27236 }
27237
27238 function pointRadians(point) {
27239   return [point[0] * radians, point[1] * radians];
27240 }
27241
27242 var contains = function(object, point) {
27243   return (object && containsObjectType.hasOwnProperty(object.type)
27244       ? containsObjectType[object.type]
27245       : containsGeometry)(object, point);
27246 };
27247
27248 function graticuleX(y0, y1, dy) {
27249   var y = sequence(y0, y1 - epsilon$2, dy).concat(y1);
27250   return function(x) { return y.map(function(y) { return [x, y]; }); };
27251 }
27252
27253 function graticuleY(x0, x1, dx) {
27254   var x = sequence(x0, x1 - epsilon$2, dx).concat(x1);
27255   return function(y) { return x.map(function(x) { return [x, y]; }); };
27256 }
27257
27258 function graticule() {
27259   var x1, x0, X1, X0,
27260       y1, y0, Y1, Y0,
27261       dx = 10, dy = dx, DX = 90, DY = 360,
27262       x, y, X, Y,
27263       precision = 2.5;
27264
27265   function graticule() {
27266     return {type: "MultiLineString", coordinates: lines()};
27267   }
27268
27269   function lines() {
27270     return sequence(ceil(X0 / DX) * DX, X1, DX).map(X)
27271         .concat(sequence(ceil(Y0 / DY) * DY, Y1, DY).map(Y))
27272         .concat(sequence(ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return abs(x % DX) > epsilon$2; }).map(x))
27273         .concat(sequence(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs(y % DY) > epsilon$2; }).map(y));
27274   }
27275
27276   graticule.lines = function() {
27277     return lines().map(function(coordinates) { return {type: "LineString", coordinates: coordinates}; });
27278   };
27279
27280   graticule.outline = function() {
27281     return {
27282       type: "Polygon",
27283       coordinates: [
27284         X(X0).concat(
27285         Y(Y1).slice(1),
27286         X(X1).reverse().slice(1),
27287         Y(Y0).reverse().slice(1))
27288       ]
27289     };
27290   };
27291
27292   graticule.extent = function(_) {
27293     if (!arguments.length) return graticule.extentMinor();
27294     return graticule.extentMajor(_).extentMinor(_);
27295   };
27296
27297   graticule.extentMajor = function(_) {
27298     if (!arguments.length) return [[X0, Y0], [X1, Y1]];
27299     X0 = +_[0][0], X1 = +_[1][0];
27300     Y0 = +_[0][1], Y1 = +_[1][1];
27301     if (X0 > X1) _ = X0, X0 = X1, X1 = _;
27302     if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
27303     return graticule.precision(precision);
27304   };
27305
27306   graticule.extentMinor = function(_) {
27307     if (!arguments.length) return [[x0, y0], [x1, y1]];
27308     x0 = +_[0][0], x1 = +_[1][0];
27309     y0 = +_[0][1], y1 = +_[1][1];
27310     if (x0 > x1) _ = x0, x0 = x1, x1 = _;
27311     if (y0 > y1) _ = y0, y0 = y1, y1 = _;
27312     return graticule.precision(precision);
27313   };
27314
27315   graticule.step = function(_) {
27316     if (!arguments.length) return graticule.stepMinor();
27317     return graticule.stepMajor(_).stepMinor(_);
27318   };
27319
27320   graticule.stepMajor = function(_) {
27321     if (!arguments.length) return [DX, DY];
27322     DX = +_[0], DY = +_[1];
27323     return graticule;
27324   };
27325
27326   graticule.stepMinor = function(_) {
27327     if (!arguments.length) return [dx, dy];
27328     dx = +_[0], dy = +_[1];
27329     return graticule;
27330   };
27331
27332   graticule.precision = function(_) {
27333     if (!arguments.length) return precision;
27334     precision = +_;
27335     x = graticuleX(y0, y1, 90);
27336     y = graticuleY(x0, x1, precision);
27337     X = graticuleX(Y0, Y1, 90);
27338     Y = graticuleY(X0, X1, precision);
27339     return graticule;
27340   };
27341
27342   return graticule
27343       .extentMajor([[-180, -90 + epsilon$2], [180, 90 - epsilon$2]])
27344       .extentMinor([[-180, -80 - epsilon$2], [180, 80 + epsilon$2]]);
27345 }
27346
27347 function graticule10() {
27348   return graticule()();
27349 }
27350
27351 var interpolate$1 = function(a, b) {
27352   var x0 = a[0] * radians,
27353       y0 = a[1] * radians,
27354       x1 = b[0] * radians,
27355       y1 = b[1] * radians,
27356       cy0 = cos$1(y0),
27357       sy0 = sin$1(y0),
27358       cy1 = cos$1(y1),
27359       sy1 = sin$1(y1),
27360       kx0 = cy0 * cos$1(x0),
27361       ky0 = cy0 * sin$1(x0),
27362       kx1 = cy1 * cos$1(x1),
27363       ky1 = cy1 * sin$1(x1),
27364       d = 2 * asin(sqrt(haversin(y1 - y0) + cy0 * cy1 * haversin(x1 - x0))),
27365       k = sin$1(d);
27366
27367   var interpolate = d ? function(t) {
27368     var B = sin$1(t *= d) / k,
27369         A = sin$1(d - t) / k,
27370         x = A * kx0 + B * kx1,
27371         y = A * ky0 + B * ky1,
27372         z = A * sy0 + B * sy1;
27373     return [
27374       atan2(y, x) * degrees$1,
27375       atan2(z, sqrt(x * x + y * y)) * degrees$1
27376     ];
27377   } : function() {
27378     return [x0 * degrees$1, y0 * degrees$1];
27379   };
27380
27381   interpolate.distance = d;
27382
27383   return interpolate;
27384 };
27385
27386 var identity$4 = function(x) {
27387   return x;
27388 };
27389
27390 var areaSum$1 = adder();
27391 var areaRingSum$1 = adder();
27392 var x00;
27393 var y00;
27394 var x0$1;
27395 var y0$1;
27396
27397 var areaStream$1 = {
27398   point: noop$1,
27399   lineStart: noop$1,
27400   lineEnd: noop$1,
27401   polygonStart: function() {
27402     areaStream$1.lineStart = areaRingStart$1;
27403     areaStream$1.lineEnd = areaRingEnd$1;
27404   },
27405   polygonEnd: function() {
27406     areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop$1;
27407     areaSum$1.add(abs(areaRingSum$1));
27408     areaRingSum$1.reset();
27409   },
27410   result: function() {
27411     var area = areaSum$1 / 2;
27412     areaSum$1.reset();
27413     return area;
27414   }
27415 };
27416
27417 function areaRingStart$1() {
27418   areaStream$1.point = areaPointFirst$1;
27419 }
27420
27421 function areaPointFirst$1(x, y) {
27422   areaStream$1.point = areaPoint$1;
27423   x00 = x0$1 = x, y00 = y0$1 = y;
27424 }
27425
27426 function areaPoint$1(x, y) {
27427   areaRingSum$1.add(y0$1 * x - x0$1 * y);
27428   x0$1 = x, y0$1 = y;
27429 }
27430
27431 function areaRingEnd$1() {
27432   areaPoint$1(x00, y00);
27433 }
27434
27435 var x0$2 = Infinity;
27436 var y0$2 = x0$2;
27437 var x1 = -x0$2;
27438 var y1 = x1;
27439
27440 var boundsStream$1 = {
27441   point: boundsPoint$1,
27442   lineStart: noop$1,
27443   lineEnd: noop$1,
27444   polygonStart: noop$1,
27445   polygonEnd: noop$1,
27446   result: function() {
27447     var bounds = [[x0$2, y0$2], [x1, y1]];
27448     x1 = y1 = -(y0$2 = x0$2 = Infinity);
27449     return bounds;
27450   }
27451 };
27452
27453 function boundsPoint$1(x, y) {
27454   if (x < x0$2) x0$2 = x;
27455   if (x > x1) x1 = x;
27456   if (y < y0$2) y0$2 = y;
27457   if (y > y1) y1 = y;
27458 }
27459
27460 // TODO Enforce positive area for exterior, negative area for interior?
27461
27462 var X0$1 = 0;
27463 var Y0$1 = 0;
27464 var Z0$1 = 0;
27465 var X1$1 = 0;
27466 var Y1$1 = 0;
27467 var Z1$1 = 0;
27468 var X2$1 = 0;
27469 var Y2$1 = 0;
27470 var Z2$1 = 0;
27471 var x00$1;
27472 var y00$1;
27473 var x0$3;
27474 var y0$3;
27475
27476 var centroidStream$1 = {
27477   point: centroidPoint$1,
27478   lineStart: centroidLineStart$1,
27479   lineEnd: centroidLineEnd$1,
27480   polygonStart: function() {
27481     centroidStream$1.lineStart = centroidRingStart$1;
27482     centroidStream$1.lineEnd = centroidRingEnd$1;
27483   },
27484   polygonEnd: function() {
27485     centroidStream$1.point = centroidPoint$1;
27486     centroidStream$1.lineStart = centroidLineStart$1;
27487     centroidStream$1.lineEnd = centroidLineEnd$1;
27488   },
27489   result: function() {
27490     var centroid = Z2$1 ? [X2$1 / Z2$1, Y2$1 / Z2$1]
27491         : Z1$1 ? [X1$1 / Z1$1, Y1$1 / Z1$1]
27492         : Z0$1 ? [X0$1 / Z0$1, Y0$1 / Z0$1]
27493         : [NaN, NaN];
27494     X0$1 = Y0$1 = Z0$1 =
27495     X1$1 = Y1$1 = Z1$1 =
27496     X2$1 = Y2$1 = Z2$1 = 0;
27497     return centroid;
27498   }
27499 };
27500
27501 function centroidPoint$1(x, y) {
27502   X0$1 += x;
27503   Y0$1 += y;
27504   ++Z0$1;
27505 }
27506
27507 function centroidLineStart$1() {
27508   centroidStream$1.point = centroidPointFirstLine;
27509 }
27510
27511 function centroidPointFirstLine(x, y) {
27512   centroidStream$1.point = centroidPointLine;
27513   centroidPoint$1(x0$3 = x, y0$3 = y);
27514 }
27515
27516 function centroidPointLine(x, y) {
27517   var dx = x - x0$3, dy = y - y0$3, z = sqrt(dx * dx + dy * dy);
27518   X1$1 += z * (x0$3 + x) / 2;
27519   Y1$1 += z * (y0$3 + y) / 2;
27520   Z1$1 += z;
27521   centroidPoint$1(x0$3 = x, y0$3 = y);
27522 }
27523
27524 function centroidLineEnd$1() {
27525   centroidStream$1.point = centroidPoint$1;
27526 }
27527
27528 function centroidRingStart$1() {
27529   centroidStream$1.point = centroidPointFirstRing;
27530 }
27531
27532 function centroidRingEnd$1() {
27533   centroidPointRing(x00$1, y00$1);
27534 }
27535
27536 function centroidPointFirstRing(x, y) {
27537   centroidStream$1.point = centroidPointRing;
27538   centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y);
27539 }
27540
27541 function centroidPointRing(x, y) {
27542   var dx = x - x0$3,
27543       dy = y - y0$3,
27544       z = sqrt(dx * dx + dy * dy);
27545
27546   X1$1 += z * (x0$3 + x) / 2;
27547   Y1$1 += z * (y0$3 + y) / 2;
27548   Z1$1 += z;
27549
27550   z = y0$3 * x - x0$3 * y;
27551   X2$1 += z * (x0$3 + x);
27552   Y2$1 += z * (y0$3 + y);
27553   Z2$1 += z * 3;
27554   centroidPoint$1(x0$3 = x, y0$3 = y);
27555 }
27556
27557 function PathContext(context) {
27558   this._context = context;
27559 }
27560
27561 PathContext.prototype = {
27562   _radius: 4.5,
27563   pointRadius: function(_) {
27564     return this._radius = _, this;
27565   },
27566   polygonStart: function() {
27567     this._line = 0;
27568   },
27569   polygonEnd: function() {
27570     this._line = NaN;
27571   },
27572   lineStart: function() {
27573     this._point = 0;
27574   },
27575   lineEnd: function() {
27576     if (this._line === 0) this._context.closePath();
27577     this._point = NaN;
27578   },
27579   point: function(x, y) {
27580     switch (this._point) {
27581       case 0: {
27582         this._context.moveTo(x, y);
27583         this._point = 1;
27584         break;
27585       }
27586       case 1: {
27587         this._context.lineTo(x, y);
27588         break;
27589       }
27590       default: {
27591         this._context.moveTo(x + this._radius, y);
27592         this._context.arc(x, y, this._radius, 0, tau$3);
27593         break;
27594       }
27595     }
27596   },
27597   result: noop$1
27598 };
27599
27600 var lengthSum$1 = adder();
27601 var lengthRing;
27602 var x00$2;
27603 var y00$2;
27604 var x0$4;
27605 var y0$4;
27606
27607 var lengthStream$1 = {
27608   point: noop$1,
27609   lineStart: function() {
27610     lengthStream$1.point = lengthPointFirst$1;
27611   },
27612   lineEnd: function() {
27613     if (lengthRing) lengthPoint$1(x00$2, y00$2);
27614     lengthStream$1.point = noop$1;
27615   },
27616   polygonStart: function() {
27617     lengthRing = true;
27618   },
27619   polygonEnd: function() {
27620     lengthRing = null;
27621   },
27622   result: function() {
27623     var length = +lengthSum$1;
27624     lengthSum$1.reset();
27625     return length;
27626   }
27627 };
27628
27629 function lengthPointFirst$1(x, y) {
27630   lengthStream$1.point = lengthPoint$1;
27631   x00$2 = x0$4 = x, y00$2 = y0$4 = y;
27632 }
27633
27634 function lengthPoint$1(x, y) {
27635   x0$4 -= x, y0$4 -= y;
27636   lengthSum$1.add(sqrt(x0$4 * x0$4 + y0$4 * y0$4));
27637   x0$4 = x, y0$4 = y;
27638 }
27639
27640 function PathString() {
27641   this._string = [];
27642 }
27643
27644 PathString.prototype = {
27645   _radius: 4.5,
27646   _circle: circle$1(4.5),
27647   pointRadius: function(_) {
27648     if ((_ = +_) !== this._radius) this._radius = _, this._circle = null;
27649     return this;
27650   },
27651   polygonStart: function() {
27652     this._line = 0;
27653   },
27654   polygonEnd: function() {
27655     this._line = NaN;
27656   },
27657   lineStart: function() {
27658     this._point = 0;
27659   },
27660   lineEnd: function() {
27661     if (this._line === 0) this._string.push("Z");
27662     this._point = NaN;
27663   },
27664   point: function(x, y) {
27665     switch (this._point) {
27666       case 0: {
27667         this._string.push("M", x, ",", y);
27668         this._point = 1;
27669         break;
27670       }
27671       case 1: {
27672         this._string.push("L", x, ",", y);
27673         break;
27674       }
27675       default: {
27676         if (this._circle == null) this._circle = circle$1(this._radius);
27677         this._string.push("M", x, ",", y, this._circle);
27678         break;
27679       }
27680     }
27681   },
27682   result: function() {
27683     if (this._string.length) {
27684       var result = this._string.join("");
27685       this._string = [];
27686       return result;
27687     } else {
27688       return null;
27689     }
27690   }
27691 };
27692
27693 function circle$1(radius) {
27694   return "m0," + radius
27695       + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius
27696       + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius
27697       + "z";
27698 }
27699
27700 var index$4 = function(projection, context) {
27701   var pointRadius = 4.5,
27702       projectionStream,
27703       contextStream;
27704
27705   function path(object) {
27706     if (object) {
27707       if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
27708       geoStream(object, projectionStream(contextStream));
27709     }
27710     return contextStream.result();
27711   }
27712
27713   path.area = function(object) {
27714     geoStream(object, projectionStream(areaStream$1));
27715     return areaStream$1.result();
27716   };
27717
27718   path.measure = function(object) {
27719     geoStream(object, projectionStream(lengthStream$1));
27720     return lengthStream$1.result();
27721   };
27722
27723   path.bounds = function(object) {
27724     geoStream(object, projectionStream(boundsStream$1));
27725     return boundsStream$1.result();
27726   };
27727
27728   path.centroid = function(object) {
27729     geoStream(object, projectionStream(centroidStream$1));
27730     return centroidStream$1.result();
27731   };
27732
27733   path.projection = function(_) {
27734     return arguments.length ? (projectionStream = _ == null ? (projection = null, identity$4) : (projection = _).stream, path) : projection;
27735   };
27736
27737   path.context = function(_) {
27738     if (!arguments.length) return context;
27739     contextStream = _ == null ? (context = null, new PathString) : new PathContext(context = _);
27740     if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
27741     return path;
27742   };
27743
27744   path.pointRadius = function(_) {
27745     if (!arguments.length) return pointRadius;
27746     pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
27747     return path;
27748   };
27749
27750   return path.projection(projection).context(context);
27751 };
27752
27753 var clip = function(pointVisible, clipLine, interpolate, start) {
27754   return function(rotate, sink) {
27755     var line = clipLine(sink),
27756         rotatedStart = rotate.invert(start[0], start[1]),
27757         ringBuffer = clipBuffer(),
27758         ringSink = clipLine(ringBuffer),
27759         polygonStarted = false,
27760         polygon,
27761         segments,
27762         ring;
27763
27764     var clip = {
27765       point: point,
27766       lineStart: lineStart,
27767       lineEnd: lineEnd,
27768       polygonStart: function() {
27769         clip.point = pointRing;
27770         clip.lineStart = ringStart;
27771         clip.lineEnd = ringEnd;
27772         segments = [];
27773         polygon = [];
27774       },
27775       polygonEnd: function() {
27776         clip.point = point;
27777         clip.lineStart = lineStart;
27778         clip.lineEnd = lineEnd;
27779         segments = merge(segments);
27780         var startInside = polygonContains(polygon, rotatedStart);
27781         if (segments.length) {
27782           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27783           clipPolygon(segments, compareIntersection, startInside, interpolate, sink);
27784         } else if (startInside) {
27785           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27786           sink.lineStart();
27787           interpolate(null, null, 1, sink);
27788           sink.lineEnd();
27789         }
27790         if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
27791         segments = polygon = null;
27792       },
27793       sphere: function() {
27794         sink.polygonStart();
27795         sink.lineStart();
27796         interpolate(null, null, 1, sink);
27797         sink.lineEnd();
27798         sink.polygonEnd();
27799       }
27800     };
27801
27802     function point(lambda, phi) {
27803       var point = rotate(lambda, phi);
27804       if (pointVisible(lambda = point[0], phi = point[1])) sink.point(lambda, phi);
27805     }
27806
27807     function pointLine(lambda, phi) {
27808       var point = rotate(lambda, phi);
27809       line.point(point[0], point[1]);
27810     }
27811
27812     function lineStart() {
27813       clip.point = pointLine;
27814       line.lineStart();
27815     }
27816
27817     function lineEnd() {
27818       clip.point = point;
27819       line.lineEnd();
27820     }
27821
27822     function pointRing(lambda, phi) {
27823       ring.push([lambda, phi]);
27824       var point = rotate(lambda, phi);
27825       ringSink.point(point[0], point[1]);
27826     }
27827
27828     function ringStart() {
27829       ringSink.lineStart();
27830       ring = [];
27831     }
27832
27833     function ringEnd() {
27834       pointRing(ring[0][0], ring[0][1]);
27835       ringSink.lineEnd();
27836
27837       var clean = ringSink.clean(),
27838           ringSegments = ringBuffer.result(),
27839           i, n = ringSegments.length, m,
27840           segment,
27841           point;
27842
27843       ring.pop();
27844       polygon.push(ring);
27845       ring = null;
27846
27847       if (!n) return;
27848
27849       // No intersections.
27850       if (clean & 1) {
27851         segment = ringSegments[0];
27852         if ((m = segment.length - 1) > 0) {
27853           if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
27854           sink.lineStart();
27855           for (i = 0; i < m; ++i) sink.point((point = segment[i])[0], point[1]);
27856           sink.lineEnd();
27857         }
27858         return;
27859       }
27860
27861       // Rejoin connected segments.
27862       // TODO reuse ringBuffer.rejoin()?
27863       if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
27864
27865       segments.push(ringSegments.filter(validSegment));
27866     }
27867
27868     return clip;
27869   };
27870 };
27871
27872 function validSegment(segment) {
27873   return segment.length > 1;
27874 }
27875
27876 // Intersections are sorted along the clip edge. For both antimeridian cutting
27877 // and circle clipping, the same comparison is used.
27878 function compareIntersection(a, b) {
27879   return ((a = a.x)[0] < 0 ? a[1] - halfPi$2 - epsilon$2 : halfPi$2 - a[1])
27880        - ((b = b.x)[0] < 0 ? b[1] - halfPi$2 - epsilon$2 : halfPi$2 - b[1]);
27881 }
27882
27883 var clipAntimeridian = clip(
27884   function() { return true; },
27885   clipAntimeridianLine,
27886   clipAntimeridianInterpolate,
27887   [-pi$3, -halfPi$2]
27888 );
27889
27890 // Takes a line and cuts into visible segments. Return values: 0 - there were
27891 // intersections or the line was empty; 1 - no intersections; 2 - there were
27892 // intersections, and the first and last segments should be rejoined.
27893 function clipAntimeridianLine(stream) {
27894   var lambda0 = NaN,
27895       phi0 = NaN,
27896       sign0 = NaN,
27897       clean; // no intersections
27898
27899   return {
27900     lineStart: function() {
27901       stream.lineStart();
27902       clean = 1;
27903     },
27904     point: function(lambda1, phi1) {
27905       var sign1 = lambda1 > 0 ? pi$3 : -pi$3,
27906           delta = abs(lambda1 - lambda0);
27907       if (abs(delta - pi$3) < epsilon$2) { // line crosses a pole
27908         stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi$2 : -halfPi$2);
27909         stream.point(sign0, phi0);
27910         stream.lineEnd();
27911         stream.lineStart();
27912         stream.point(sign1, phi0);
27913         stream.point(lambda1, phi0);
27914         clean = 0;
27915       } else if (sign0 !== sign1 && delta >= pi$3) { // line crosses antimeridian
27916         if (abs(lambda0 - sign0) < epsilon$2) lambda0 -= sign0 * epsilon$2; // handle degeneracies
27917         if (abs(lambda1 - sign1) < epsilon$2) lambda1 -= sign1 * epsilon$2;
27918         phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
27919         stream.point(sign0, phi0);
27920         stream.lineEnd();
27921         stream.lineStart();
27922         stream.point(sign1, phi0);
27923         clean = 0;
27924       }
27925       stream.point(lambda0 = lambda1, phi0 = phi1);
27926       sign0 = sign1;
27927     },
27928     lineEnd: function() {
27929       stream.lineEnd();
27930       lambda0 = phi0 = NaN;
27931     },
27932     clean: function() {
27933       return 2 - clean; // if intersections, rejoin first and last segments
27934     }
27935   };
27936 }
27937
27938 function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
27939   var cosPhi0,
27940       cosPhi1,
27941       sinLambda0Lambda1 = sin$1(lambda0 - lambda1);
27942   return abs(sinLambda0Lambda1) > epsilon$2
27943       ? atan((sin$1(phi0) * (cosPhi1 = cos$1(phi1)) * sin$1(lambda1)
27944           - sin$1(phi1) * (cosPhi0 = cos$1(phi0)) * sin$1(lambda0))
27945           / (cosPhi0 * cosPhi1 * sinLambda0Lambda1))
27946       : (phi0 + phi1) / 2;
27947 }
27948
27949 function clipAntimeridianInterpolate(from, to, direction, stream) {
27950   var phi;
27951   if (from == null) {
27952     phi = direction * halfPi$2;
27953     stream.point(-pi$3, phi);
27954     stream.point(0, phi);
27955     stream.point(pi$3, phi);
27956     stream.point(pi$3, 0);
27957     stream.point(pi$3, -phi);
27958     stream.point(0, -phi);
27959     stream.point(-pi$3, -phi);
27960     stream.point(-pi$3, 0);
27961     stream.point(-pi$3, phi);
27962   } else if (abs(from[0] - to[0]) > epsilon$2) {
27963     var lambda = from[0] < to[0] ? pi$3 : -pi$3;
27964     phi = direction * lambda / 2;
27965     stream.point(-lambda, phi);
27966     stream.point(0, phi);
27967     stream.point(lambda, phi);
27968   } else {
27969     stream.point(to[0], to[1]);
27970   }
27971 }
27972
27973 var clipCircle = function(radius, delta) {
27974   var cr = cos$1(radius),
27975       smallRadius = cr > 0,
27976       notHemisphere = abs(cr) > epsilon$2; // TODO optimise for this common case
27977
27978   function interpolate(from, to, direction, stream) {
27979     circleStream(stream, radius, delta, direction, from, to);
27980   }
27981
27982   function visible(lambda, phi) {
27983     return cos$1(lambda) * cos$1(phi) > cr;
27984   }
27985
27986   // Takes a line and cuts into visible segments. Return values used for polygon
27987   // clipping: 0 - there were intersections or the line was empty; 1 - no
27988   // intersections 2 - there were intersections, and the first and last segments
27989   // should be rejoined.
27990   function clipLine(stream) {
27991     var point0, // previous point
27992         c0, // code for previous point
27993         v0, // visibility of previous point
27994         v00, // visibility of first point
27995         clean; // no intersections
27996     return {
27997       lineStart: function() {
27998         v00 = v0 = false;
27999         clean = 1;
28000       },
28001       point: function(lambda, phi) {
28002         var point1 = [lambda, phi],
28003             point2,
28004             v = visible(lambda, phi),
28005             c = smallRadius
28006               ? v ? 0 : code(lambda, phi)
28007               : v ? code(lambda + (lambda < 0 ? pi$3 : -pi$3), phi) : 0;
28008         if (!point0 && (v00 = v0 = v)) stream.lineStart();
28009         // Handle degeneracies.
28010         // TODO ignore if not clipping polygons.
28011         if (v !== v0) {
28012           point2 = intersect(point0, point1);
28013           if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) {
28014             point1[0] += epsilon$2;
28015             point1[1] += epsilon$2;
28016             v = visible(point1[0], point1[1]);
28017           }
28018         }
28019         if (v !== v0) {
28020           clean = 0;
28021           if (v) {
28022             // outside going in
28023             stream.lineStart();
28024             point2 = intersect(point1, point0);
28025             stream.point(point2[0], point2[1]);
28026           } else {
28027             // inside going out
28028             point2 = intersect(point0, point1);
28029             stream.point(point2[0], point2[1]);
28030             stream.lineEnd();
28031           }
28032           point0 = point2;
28033         } else if (notHemisphere && point0 && smallRadius ^ v) {
28034           var t;
28035           // If the codes for two points are different, or are both zero,
28036           // and there this segment intersects with the small circle.
28037           if (!(c & c0) && (t = intersect(point1, point0, true))) {
28038             clean = 0;
28039             if (smallRadius) {
28040               stream.lineStart();
28041               stream.point(t[0][0], t[0][1]);
28042               stream.point(t[1][0], t[1][1]);
28043               stream.lineEnd();
28044             } else {
28045               stream.point(t[1][0], t[1][1]);
28046               stream.lineEnd();
28047               stream.lineStart();
28048               stream.point(t[0][0], t[0][1]);
28049             }
28050           }
28051         }
28052         if (v && (!point0 || !pointEqual(point0, point1))) {
28053           stream.point(point1[0], point1[1]);
28054         }
28055         point0 = point1, v0 = v, c0 = c;
28056       },
28057       lineEnd: function() {
28058         if (v0) stream.lineEnd();
28059         point0 = null;
28060       },
28061       // Rejoin first and last segments if there were intersections and the first
28062       // and last points were visible.
28063       clean: function() {
28064         return clean | ((v00 && v0) << 1);
28065       }
28066     };
28067   }
28068
28069   // Intersects the great circle between a and b with the clip circle.
28070   function intersect(a, b, two) {
28071     var pa = cartesian(a),
28072         pb = cartesian(b);
28073
28074     // We have two planes, n1.p = d1 and n2.p = d2.
28075     // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
28076     var n1 = [1, 0, 0], // normal
28077         n2 = cartesianCross(pa, pb),
28078         n2n2 = cartesianDot(n2, n2),
28079         n1n2 = n2[0], // cartesianDot(n1, n2),
28080         determinant = n2n2 - n1n2 * n1n2;
28081
28082     // Two polar points.
28083     if (!determinant) return !two && a;
28084
28085     var c1 =  cr * n2n2 / determinant,
28086         c2 = -cr * n1n2 / determinant,
28087         n1xn2 = cartesianCross(n1, n2),
28088         A = cartesianScale(n1, c1),
28089         B = cartesianScale(n2, c2);
28090     cartesianAddInPlace(A, B);
28091
28092     // Solve |p(t)|^2 = 1.
28093     var u = n1xn2,
28094         w = cartesianDot(A, u),
28095         uu = cartesianDot(u, u),
28096         t2 = w * w - uu * (cartesianDot(A, A) - 1);
28097
28098     if (t2 < 0) return;
28099
28100     var t = sqrt(t2),
28101         q = cartesianScale(u, (-w - t) / uu);
28102     cartesianAddInPlace(q, A);
28103     q = spherical(q);
28104
28105     if (!two) return q;
28106
28107     // Two intersection points.
28108     var lambda0 = a[0],
28109         lambda1 = b[0],
28110         phi0 = a[1],
28111         phi1 = b[1],
28112         z;
28113
28114     if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
28115
28116     var delta = lambda1 - lambda0,
28117         polar = abs(delta - pi$3) < epsilon$2,
28118         meridian = polar || delta < epsilon$2;
28119
28120     if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z;
28121
28122     // Check that the first point is between a and b.
28123     if (meridian
28124         ? polar
28125           ? phi0 + phi1 > 0 ^ q[1] < (abs(q[0] - lambda0) < epsilon$2 ? phi0 : phi1)
28126           : phi0 <= q[1] && q[1] <= phi1
28127         : delta > pi$3 ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
28128       var q1 = cartesianScale(u, (-w + t) / uu);
28129       cartesianAddInPlace(q1, A);
28130       return [q, spherical(q1)];
28131     }
28132   }
28133
28134   // Generates a 4-bit vector representing the location of a point relative to
28135   // the small circle's bounding box.
28136   function code(lambda, phi) {
28137     var r = smallRadius ? radius : pi$3 - radius,
28138         code = 0;
28139     if (lambda < -r) code |= 1; // left
28140     else if (lambda > r) code |= 2; // right
28141     if (phi < -r) code |= 4; // below
28142     else if (phi > r) code |= 8; // above
28143     return code;
28144   }
28145
28146   return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi$3, radius - pi$3]);
28147 };
28148
28149 var transform = function(methods) {
28150   return {
28151     stream: transformer(methods)
28152   };
28153 };
28154
28155 function transformer(methods) {
28156   return function(stream) {
28157     var s = new TransformStream;
28158     for (var key in methods) s[key] = methods[key];
28159     s.stream = stream;
28160     return s;
28161   };
28162 }
28163
28164 function TransformStream() {}
28165
28166 TransformStream.prototype = {
28167   constructor: TransformStream,
28168   point: function(x, y) { this.stream.point(x, y); },
28169   sphere: function() { this.stream.sphere(); },
28170   lineStart: function() { this.stream.lineStart(); },
28171   lineEnd: function() { this.stream.lineEnd(); },
28172   polygonStart: function() { this.stream.polygonStart(); },
28173   polygonEnd: function() { this.stream.polygonEnd(); }
28174 };
28175
28176 function fitExtent(projection, extent, object) {
28177   var w = extent[1][0] - extent[0][0],
28178       h = extent[1][1] - extent[0][1],
28179       clip = projection.clipExtent && projection.clipExtent();
28180
28181   projection
28182       .scale(150)
28183       .translate([0, 0]);
28184
28185   if (clip != null) projection.clipExtent(null);
28186
28187   geoStream(object, projection.stream(boundsStream$1));
28188
28189   var b = boundsStream$1.result(),
28190       k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
28191       x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
28192       y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
28193
28194   if (clip != null) projection.clipExtent(clip);
28195
28196   return projection
28197       .scale(k * 150)
28198       .translate([x, y]);
28199 }
28200
28201 function fitSize(projection, size, object) {
28202   return fitExtent(projection, [[0, 0], size], object);
28203 }
28204
28205 var maxDepth = 16;
28206 var cosMinDistance = cos$1(30 * radians); // cos(minimum angular distance)
28207
28208 var resample = function(project, delta2) {
28209   return +delta2 ? resample$1(project, delta2) : resampleNone(project);
28210 };
28211
28212 function resampleNone(project) {
28213   return transformer({
28214     point: function(x, y) {
28215       x = project(x, y);
28216       this.stream.point(x[0], x[1]);
28217     }
28218   });
28219 }
28220
28221 function resample$1(project, delta2) {
28222
28223   function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
28224     var dx = x1 - x0,
28225         dy = y1 - y0,
28226         d2 = dx * dx + dy * dy;
28227     if (d2 > 4 * delta2 && depth--) {
28228       var a = a0 + a1,
28229           b = b0 + b1,
28230           c = c0 + c1,
28231           m = sqrt(a * a + b * b + c * c),
28232           phi2 = asin(c /= m),
28233           lambda2 = abs(abs(c) - 1) < epsilon$2 || abs(lambda0 - lambda1) < epsilon$2 ? (lambda0 + lambda1) / 2 : atan2(b, a),
28234           p = project(lambda2, phi2),
28235           x2 = p[0],
28236           y2 = p[1],
28237           dx2 = x2 - x0,
28238           dy2 = y2 - y0,
28239           dz = dy * dx2 - dx * dy2;
28240       if (dz * dz / d2 > delta2 // perpendicular projected distance
28241           || abs((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
28242           || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
28243         resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
28244         stream.point(x2, y2);
28245         resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
28246       }
28247     }
28248   }
28249   return function(stream) {
28250     var lambda00, x00, y00, a00, b00, c00, // first point
28251         lambda0, x0, y0, a0, b0, c0; // previous point
28252
28253     var resampleStream = {
28254       point: point,
28255       lineStart: lineStart,
28256       lineEnd: lineEnd,
28257       polygonStart: function() { stream.polygonStart(); resampleStream.lineStart = ringStart; },
28258       polygonEnd: function() { stream.polygonEnd(); resampleStream.lineStart = lineStart; }
28259     };
28260
28261     function point(x, y) {
28262       x = project(x, y);
28263       stream.point(x[0], x[1]);
28264     }
28265
28266     function lineStart() {
28267       x0 = NaN;
28268       resampleStream.point = linePoint;
28269       stream.lineStart();
28270     }
28271
28272     function linePoint(lambda, phi) {
28273       var c = cartesian([lambda, phi]), p = project(lambda, phi);
28274       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);
28275       stream.point(x0, y0);
28276     }
28277
28278     function lineEnd() {
28279       resampleStream.point = point;
28280       stream.lineEnd();
28281     }
28282
28283     function ringStart() {
28284       lineStart();
28285       resampleStream.point = ringPoint;
28286       resampleStream.lineEnd = ringEnd;
28287     }
28288
28289     function ringPoint(lambda, phi) {
28290       linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
28291       resampleStream.point = linePoint;
28292     }
28293
28294     function ringEnd() {
28295       resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
28296       resampleStream.lineEnd = lineEnd;
28297       lineEnd();
28298     }
28299
28300     return resampleStream;
28301   };
28302 }
28303
28304 var transformRadians = transformer({
28305   point: function(x, y) {
28306     this.stream.point(x * radians, y * radians);
28307   }
28308 });
28309
28310 function projection(project) {
28311   return projectionMutator(function() { return project; })();
28312 }
28313
28314 function projectionMutator(projectAt) {
28315   var project,
28316       k = 150, // scale
28317       x = 480, y = 250, // translate
28318       dx, dy, lambda = 0, phi = 0, // center
28319       deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, projectRotate, // rotate
28320       theta = null, preclip = clipAntimeridian, // clip angle
28321       x0 = null, y0, x1, y1, postclip = identity$4, // clip extent
28322       delta2 = 0.5, projectResample = resample(projectTransform, delta2), // precision
28323       cache,
28324       cacheStream;
28325
28326   function projection(point) {
28327     point = projectRotate(point[0] * radians, point[1] * radians);
28328     return [point[0] * k + dx, dy - point[1] * k];
28329   }
28330
28331   function invert(point) {
28332     point = projectRotate.invert((point[0] - dx) / k, (dy - point[1]) / k);
28333     return point && [point[0] * degrees$1, point[1] * degrees$1];
28334   }
28335
28336   function projectTransform(x, y) {
28337     return x = project(x, y), [x[0] * k + dx, dy - x[1] * k];
28338   }
28339
28340   projection.stream = function(stream) {
28341     return cache && cacheStream === stream ? cache : cache = transformRadians(preclip(rotate, projectResample(postclip(cacheStream = stream))));
28342   };
28343
28344   projection.clipAngle = function(_) {
28345     return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians, 6 * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees$1;
28346   };
28347
28348   projection.clipExtent = function(_) {
28349     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]];
28350   };
28351
28352   projection.scale = function(_) {
28353     return arguments.length ? (k = +_, recenter()) : k;
28354   };
28355
28356   projection.translate = function(_) {
28357     return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
28358   };
28359
28360   projection.center = function(_) {
28361     return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees$1, phi * degrees$1];
28362   };
28363
28364   projection.rotate = function(_) {
28365     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];
28366   };
28367
28368   projection.precision = function(_) {
28369     return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
28370   };
28371
28372   projection.fitExtent = function(extent, object) {
28373     return fitExtent(projection, extent, object);
28374   };
28375
28376   projection.fitSize = function(size, object) {
28377     return fitSize(projection, size, object);
28378   };
28379
28380   function recenter() {
28381     projectRotate = compose(rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma), project);
28382     var center = project(lambda, phi);
28383     dx = x - center[0] * k;
28384     dy = y + center[1] * k;
28385     return reset();
28386   }
28387
28388   function reset() {
28389     cache = cacheStream = null;
28390     return projection;
28391   }
28392
28393   return function() {
28394     project = projectAt.apply(this, arguments);
28395     projection.invert = project.invert && invert;
28396     return recenter();
28397   };
28398 }
28399
28400 function conicProjection(projectAt) {
28401   var phi0 = 0,
28402       phi1 = pi$3 / 3,
28403       m = projectionMutator(projectAt),
28404       p = m(phi0, phi1);
28405
28406   p.parallels = function(_) {
28407     return arguments.length ? m(phi0 = _[0] * radians, phi1 = _[1] * radians) : [phi0 * degrees$1, phi1 * degrees$1];
28408   };
28409
28410   return p;
28411 }
28412
28413 function cylindricalEqualAreaRaw(phi0) {
28414   var cosPhi0 = cos$1(phi0);
28415
28416   function forward(lambda, phi) {
28417     return [lambda * cosPhi0, sin$1(phi) / cosPhi0];
28418   }
28419
28420   forward.invert = function(x, y) {
28421     return [x / cosPhi0, asin(y * cosPhi0)];
28422   };
28423
28424   return forward;
28425 }
28426
28427 function conicEqualAreaRaw(y0, y1) {
28428   var sy0 = sin$1(y0), n = (sy0 + sin$1(y1)) / 2;
28429
28430   // Are the parallels symmetrical around the Equator?
28431   if (abs(n) < epsilon$2) return cylindricalEqualAreaRaw(y0);
28432
28433   var c = 1 + sy0 * (2 * n - sy0), r0 = sqrt(c) / n;
28434
28435   function project(x, y) {
28436     var r = sqrt(c - 2 * n * sin$1(y)) / n;
28437     return [r * sin$1(x *= n), r0 - r * cos$1(x)];
28438   }
28439
28440   project.invert = function(x, y) {
28441     var r0y = r0 - y;
28442     return [atan2(x, abs(r0y)) / n * sign(r0y), asin((c - (x * x + r0y * r0y) * n * n) / (2 * n))];
28443   };
28444
28445   return project;
28446 }
28447
28448 var conicEqualArea = function() {
28449   return conicProjection(conicEqualAreaRaw)
28450       .scale(155.424)
28451       .center([0, 33.6442]);
28452 };
28453
28454 var albers = function() {
28455   return conicEqualArea()
28456       .parallels([29.5, 45.5])
28457       .scale(1070)
28458       .translate([480, 250])
28459       .rotate([96, 0])
28460       .center([-0.6, 38.7]);
28461 };
28462
28463 // The projections must have mutually exclusive clip regions on the sphere,
28464 // as this will avoid emitting interleaving lines and polygons.
28465 function multiplex(streams) {
28466   var n = streams.length;
28467   return {
28468     point: function(x, y) { var i = -1; while (++i < n) streams[i].point(x, y); },
28469     sphere: function() { var i = -1; while (++i < n) streams[i].sphere(); },
28470     lineStart: function() { var i = -1; while (++i < n) streams[i].lineStart(); },
28471     lineEnd: function() { var i = -1; while (++i < n) streams[i].lineEnd(); },
28472     polygonStart: function() { var i = -1; while (++i < n) streams[i].polygonStart(); },
28473     polygonEnd: function() { var i = -1; while (++i < n) streams[i].polygonEnd(); }
28474   };
28475 }
28476
28477 // A composite projection for the United States, configured by default for
28478 // 960×500. The projection also works quite well at 960×600 if you change the
28479 // scale to 1285 and adjust the translate accordingly. The set of standard
28480 // parallels for each region comes from USGS, which is published here:
28481 // http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers
28482 var albersUsa = function() {
28483   var cache,
28484       cacheStream,
28485       lower48 = albers(), lower48Point,
28486       alaska = conicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]), alaskaPoint, // EPSG:3338
28487       hawaii = conicEqualArea().rotate([157, 0]).center([-3, 19.9]).parallels([8, 18]), hawaiiPoint, // ESRI:102007
28488       point, pointStream = {point: function(x, y) { point = [x, y]; }};
28489
28490   function albersUsa(coordinates) {
28491     var x = coordinates[0], y = coordinates[1];
28492     return point = null,
28493         (lower48Point.point(x, y), point)
28494         || (alaskaPoint.point(x, y), point)
28495         || (hawaiiPoint.point(x, y), point);
28496   }
28497
28498   albersUsa.invert = function(coordinates) {
28499     var k = lower48.scale(),
28500         t = lower48.translate(),
28501         x = (coordinates[0] - t[0]) / k,
28502         y = (coordinates[1] - t[1]) / k;
28503     return (y >= 0.120 && y < 0.234 && x >= -0.425 && x < -0.214 ? alaska
28504         : y >= 0.166 && y < 0.234 && x >= -0.214 && x < -0.115 ? hawaii
28505         : lower48).invert(coordinates);
28506   };
28507
28508   albersUsa.stream = function(stream) {
28509     return cache && cacheStream === stream ? cache : cache = multiplex([lower48.stream(cacheStream = stream), alaska.stream(stream), hawaii.stream(stream)]);
28510   };
28511
28512   albersUsa.precision = function(_) {
28513     if (!arguments.length) return lower48.precision();
28514     lower48.precision(_), alaska.precision(_), hawaii.precision(_);
28515     return reset();
28516   };
28517
28518   albersUsa.scale = function(_) {
28519     if (!arguments.length) return lower48.scale();
28520     lower48.scale(_), alaska.scale(_ * 0.35), hawaii.scale(_);
28521     return albersUsa.translate(lower48.translate());
28522   };
28523
28524   albersUsa.translate = function(_) {
28525     if (!arguments.length) return lower48.translate();
28526     var k = lower48.scale(), x = +_[0], y = +_[1];
28527
28528     lower48Point = lower48
28529         .translate(_)
28530         .clipExtent([[x - 0.455 * k, y - 0.238 * k], [x + 0.455 * k, y + 0.238 * k]])
28531         .stream(pointStream);
28532
28533     alaskaPoint = alaska
28534         .translate([x - 0.307 * k, y + 0.201 * k])
28535         .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]])
28536         .stream(pointStream);
28537
28538     hawaiiPoint = hawaii
28539         .translate([x - 0.205 * k, y + 0.212 * k])
28540         .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]])
28541         .stream(pointStream);
28542
28543     return reset();
28544   };
28545
28546   albersUsa.fitExtent = function(extent, object) {
28547     return fitExtent(albersUsa, extent, object);
28548   };
28549
28550   albersUsa.fitSize = function(size, object) {
28551     return fitSize(albersUsa, size, object);
28552   };
28553
28554   function reset() {
28555     cache = cacheStream = null;
28556     return albersUsa;
28557   }
28558
28559   return albersUsa.scale(1070);
28560 };
28561
28562 function azimuthalRaw(scale) {
28563   return function(x, y) {
28564     var cx = cos$1(x),
28565         cy = cos$1(y),
28566         k = scale(cx * cy);
28567     return [
28568       k * cy * sin$1(x),
28569       k * sin$1(y)
28570     ];
28571   }
28572 }
28573
28574 function azimuthalInvert(angle) {
28575   return function(x, y) {
28576     var z = sqrt(x * x + y * y),
28577         c = angle(z),
28578         sc = sin$1(c),
28579         cc = cos$1(c);
28580     return [
28581       atan2(x * sc, z * cc),
28582       asin(z && y * sc / z)
28583     ];
28584   }
28585 }
28586
28587 var azimuthalEqualAreaRaw = azimuthalRaw(function(cxcy) {
28588   return sqrt(2 / (1 + cxcy));
28589 });
28590
28591 azimuthalEqualAreaRaw.invert = azimuthalInvert(function(z) {
28592   return 2 * asin(z / 2);
28593 });
28594
28595 var azimuthalEqualArea = function() {
28596   return projection(azimuthalEqualAreaRaw)
28597       .scale(124.75)
28598       .clipAngle(180 - 1e-3);
28599 };
28600
28601 var azimuthalEquidistantRaw = azimuthalRaw(function(c) {
28602   return (c = acos(c)) && c / sin$1(c);
28603 });
28604
28605 azimuthalEquidistantRaw.invert = azimuthalInvert(function(z) {
28606   return z;
28607 });
28608
28609 var azimuthalEquidistant = function() {
28610   return projection(azimuthalEquidistantRaw)
28611       .scale(79.4188)
28612       .clipAngle(180 - 1e-3);
28613 };
28614
28615 function mercatorRaw(lambda, phi) {
28616   return [lambda, log(tan((halfPi$2 + phi) / 2))];
28617 }
28618
28619 mercatorRaw.invert = function(x, y) {
28620   return [x, 2 * atan(exp(y)) - halfPi$2];
28621 };
28622
28623 var mercator = function() {
28624   return mercatorProjection(mercatorRaw)
28625       .scale(961 / tau$3);
28626 };
28627
28628 function mercatorProjection(project) {
28629   var m = projection(project),
28630       center = m.center,
28631       scale = m.scale,
28632       translate = m.translate,
28633       clipExtent = m.clipExtent,
28634       x0 = null, y0, x1, y1; // clip extent
28635
28636   m.scale = function(_) {
28637     return arguments.length ? (scale(_), reclip()) : scale();
28638   };
28639
28640   m.translate = function(_) {
28641     return arguments.length ? (translate(_), reclip()) : translate();
28642   };
28643
28644   m.center = function(_) {
28645     return arguments.length ? (center(_), reclip()) : center();
28646   };
28647
28648   m.clipExtent = function(_) {
28649     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]];
28650   };
28651
28652   function reclip() {
28653     var k = pi$3 * scale(),
28654         t = m(rotation(m.rotate()).invert([0, 0]));
28655     return clipExtent(x0 == null
28656         ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw
28657         ? [[Math.max(t[0] - k, x0), y0], [Math.min(t[0] + k, x1), y1]]
28658         : [[x0, Math.max(t[1] - k, y0)], [x1, Math.min(t[1] + k, y1)]]);
28659   }
28660
28661   return reclip();
28662 }
28663
28664 function tany(y) {
28665   return tan((halfPi$2 + y) / 2);
28666 }
28667
28668 function conicConformalRaw(y0, y1) {
28669   var cy0 = cos$1(y0),
28670       n = y0 === y1 ? sin$1(y0) : log(cy0 / cos$1(y1)) / log(tany(y1) / tany(y0)),
28671       f = cy0 * pow(tany(y0), n) / n;
28672
28673   if (!n) return mercatorRaw;
28674
28675   function project(x, y) {
28676     if (f > 0) { if (y < -halfPi$2 + epsilon$2) y = -halfPi$2 + epsilon$2; }
28677     else { if (y > halfPi$2 - epsilon$2) y = halfPi$2 - epsilon$2; }
28678     var r = f / pow(tany(y), n);
28679     return [r * sin$1(n * x), f - r * cos$1(n * x)];
28680   }
28681
28682   project.invert = function(x, y) {
28683     var fy = f - y, r = sign(n) * sqrt(x * x + fy * fy);
28684     return [atan2(x, abs(fy)) / n * sign(fy), 2 * atan(pow(f / r, 1 / n)) - halfPi$2];
28685   };
28686
28687   return project;
28688 }
28689
28690 var conicConformal = function() {
28691   return conicProjection(conicConformalRaw)
28692       .scale(109.5)
28693       .parallels([30, 30]);
28694 };
28695
28696 function equirectangularRaw(lambda, phi) {
28697   return [lambda, phi];
28698 }
28699
28700 equirectangularRaw.invert = equirectangularRaw;
28701
28702 var equirectangular = function() {
28703   return projection(equirectangularRaw)
28704       .scale(152.63);
28705 };
28706
28707 function conicEquidistantRaw(y0, y1) {
28708   var cy0 = cos$1(y0),
28709       n = y0 === y1 ? sin$1(y0) : (cy0 - cos$1(y1)) / (y1 - y0),
28710       g = cy0 / n + y0;
28711
28712   if (abs(n) < epsilon$2) return equirectangularRaw;
28713
28714   function project(x, y) {
28715     var gy = g - y, nx = n * x;
28716     return [gy * sin$1(nx), g - gy * cos$1(nx)];
28717   }
28718
28719   project.invert = function(x, y) {
28720     var gy = g - y;
28721     return [atan2(x, abs(gy)) / n * sign(gy), g - sign(n) * sqrt(x * x + gy * gy)];
28722   };
28723
28724   return project;
28725 }
28726
28727 var conicEquidistant = function() {
28728   return conicProjection(conicEquidistantRaw)
28729       .scale(131.154)
28730       .center([0, 13.9389]);
28731 };
28732
28733 function gnomonicRaw(x, y) {
28734   var cy = cos$1(y), k = cos$1(x) * cy;
28735   return [cy * sin$1(x) / k, sin$1(y) / k];
28736 }
28737
28738 gnomonicRaw.invert = azimuthalInvert(atan);
28739
28740 var gnomonic = function() {
28741   return projection(gnomonicRaw)
28742       .scale(144.049)
28743       .clipAngle(60);
28744 };
28745
28746 function scaleTranslate(kx, ky, tx, ty) {
28747   return kx === 1 && ky === 1 && tx === 0 && ty === 0 ? identity$4 : transformer({
28748     point: function(x, y) {
28749       this.stream.point(x * kx + tx, y * ky + ty);
28750     }
28751   });
28752 }
28753
28754 var identity$5 = function() {
28755   var k = 1, tx = 0, ty = 0, sx = 1, sy = 1, transform$$1 = identity$4, // scale, translate and reflect
28756       x0 = null, y0, x1, y1, clip = identity$4, // clip extent
28757       cache,
28758       cacheStream,
28759       projection;
28760
28761   function reset() {
28762     cache = cacheStream = null;
28763     return projection;
28764   }
28765
28766   return projection = {
28767     stream: function(stream) {
28768       return cache && cacheStream === stream ? cache : cache = transform$$1(clip(cacheStream = stream));
28769     },
28770     clipExtent: function(_) {
28771       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]];
28772     },
28773     scale: function(_) {
28774       return arguments.length ? (transform$$1 = scaleTranslate((k = +_) * sx, k * sy, tx, ty), reset()) : k;
28775     },
28776     translate: function(_) {
28777       return arguments.length ? (transform$$1 = scaleTranslate(k * sx, k * sy, tx = +_[0], ty = +_[1]), reset()) : [tx, ty];
28778     },
28779     reflectX: function(_) {
28780       return arguments.length ? (transform$$1 = scaleTranslate(k * (sx = _ ? -1 : 1), k * sy, tx, ty), reset()) : sx < 0;
28781     },
28782     reflectY: function(_) {
28783       return arguments.length ? (transform$$1 = scaleTranslate(k * sx, k * (sy = _ ? -1 : 1), tx, ty), reset()) : sy < 0;
28784     },
28785     fitExtent: function(extent, object) {
28786       return fitExtent(projection, extent, object);
28787     },
28788     fitSize: function(size, object) {
28789       return fitSize(projection, size, object);
28790     }
28791   };
28792 };
28793
28794 function orthographicRaw(x, y) {
28795   return [cos$1(y) * sin$1(x), sin$1(y)];
28796 }
28797
28798 orthographicRaw.invert = azimuthalInvert(asin);
28799
28800 var orthographic = function() {
28801   return projection(orthographicRaw)
28802       .scale(249.5)
28803       .clipAngle(90 + epsilon$2);
28804 };
28805
28806 function stereographicRaw(x, y) {
28807   var cy = cos$1(y), k = 1 + cos$1(x) * cy;
28808   return [cy * sin$1(x) / k, sin$1(y) / k];
28809 }
28810
28811 stereographicRaw.invert = azimuthalInvert(function(z) {
28812   return 2 * atan(z);
28813 });
28814
28815 var stereographic = function() {
28816   return projection(stereographicRaw)
28817       .scale(250)
28818       .clipAngle(142);
28819 };
28820
28821 function transverseMercatorRaw(lambda, phi) {
28822   return [log(tan((halfPi$2 + phi) / 2)), -lambda];
28823 }
28824
28825 transverseMercatorRaw.invert = function(x, y) {
28826   return [-y, 2 * atan(exp(x)) - halfPi$2];
28827 };
28828
28829 var transverseMercator = function() {
28830   var m = mercatorProjection(transverseMercatorRaw),
28831       center = m.center,
28832       rotate = m.rotate;
28833
28834   m.center = function(_) {
28835     return arguments.length ? center([-_[1], _[0]]) : (_ = center(), [_[1], -_[0]]);
28836   };
28837
28838   m.rotate = function(_) {
28839     return arguments.length ? rotate([_[0], _[1], _.length > 2 ? _[2] + 90 : 90]) : (_ = rotate(), [_[0], _[1], _[2] - 90]);
28840   };
28841
28842   return rotate([0, 0, 90])
28843       .scale(159.155);
28844 };
28845
28846 function defaultSeparation(a, b) {
28847   return a.parent === b.parent ? 1 : 2;
28848 }
28849
28850 function meanX(children) {
28851   return children.reduce(meanXReduce, 0) / children.length;
28852 }
28853
28854 function meanXReduce(x, c) {
28855   return x + c.x;
28856 }
28857
28858 function maxY(children) {
28859   return 1 + children.reduce(maxYReduce, 0);
28860 }
28861
28862 function maxYReduce(y, c) {
28863   return Math.max(y, c.y);
28864 }
28865
28866 function leafLeft(node) {
28867   var children;
28868   while (children = node.children) node = children[0];
28869   return node;
28870 }
28871
28872 function leafRight(node) {
28873   var children;
28874   while (children = node.children) node = children[children.length - 1];
28875   return node;
28876 }
28877
28878 var cluster = function() {
28879   var separation = defaultSeparation,
28880       dx = 1,
28881       dy = 1,
28882       nodeSize = false;
28883
28884   function cluster(root) {
28885     var previousNode,
28886         x = 0;
28887
28888     // First walk, computing the initial x & y values.
28889     root.eachAfter(function(node) {
28890       var children = node.children;
28891       if (children) {
28892         node.x = meanX(children);
28893         node.y = maxY(children);
28894       } else {
28895         node.x = previousNode ? x += separation(node, previousNode) : 0;
28896         node.y = 0;
28897         previousNode = node;
28898       }
28899     });
28900
28901     var left = leafLeft(root),
28902         right = leafRight(root),
28903         x0 = left.x - separation(left, right) / 2,
28904         x1 = right.x + separation(right, left) / 2;
28905
28906     // Second walk, normalizing x & y to the desired size.
28907     return root.eachAfter(nodeSize ? function(node) {
28908       node.x = (node.x - root.x) * dx;
28909       node.y = (root.y - node.y) * dy;
28910     } : function(node) {
28911       node.x = (node.x - x0) / (x1 - x0) * dx;
28912       node.y = (1 - (root.y ? node.y / root.y : 1)) * dy;
28913     });
28914   }
28915
28916   cluster.separation = function(x) {
28917     return arguments.length ? (separation = x, cluster) : separation;
28918   };
28919
28920   cluster.size = function(x) {
28921     return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? null : [dx, dy]);
28922   };
28923
28924   cluster.nodeSize = function(x) {
28925     return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? [dx, dy] : null);
28926   };
28927
28928   return cluster;
28929 };
28930
28931 function count(node) {
28932   var sum = 0,
28933       children = node.children,
28934       i = children && children.length;
28935   if (!i) sum = 1;
28936   else while (--i >= 0) sum += children[i].value;
28937   node.value = sum;
28938 }
28939
28940 var node_count = function() {
28941   return this.eachAfter(count);
28942 };
28943
28944 var node_each = function(callback) {
28945   var node = this, current, next = [node], children, i, n;
28946   do {
28947     current = next.reverse(), next = [];
28948     while (node = current.pop()) {
28949       callback(node), children = node.children;
28950       if (children) for (i = 0, n = children.length; i < n; ++i) {
28951         next.push(children[i]);
28952       }
28953     }
28954   } while (next.length);
28955   return this;
28956 };
28957
28958 var node_eachBefore = function(callback) {
28959   var node = this, nodes = [node], children, i;
28960   while (node = nodes.pop()) {
28961     callback(node), children = node.children;
28962     if (children) for (i = children.length - 1; i >= 0; --i) {
28963       nodes.push(children[i]);
28964     }
28965   }
28966   return this;
28967 };
28968
28969 var node_eachAfter = function(callback) {
28970   var node = this, nodes = [node], next = [], children, i, n;
28971   while (node = nodes.pop()) {
28972     next.push(node), children = node.children;
28973     if (children) for (i = 0, n = children.length; i < n; ++i) {
28974       nodes.push(children[i]);
28975     }
28976   }
28977   while (node = next.pop()) {
28978     callback(node);
28979   }
28980   return this;
28981 };
28982
28983 var node_sum = function(value) {
28984   return this.eachAfter(function(node) {
28985     var sum = +value(node.data) || 0,
28986         children = node.children,
28987         i = children && children.length;
28988     while (--i >= 0) sum += children[i].value;
28989     node.value = sum;
28990   });
28991 };
28992
28993 var node_sort = function(compare) {
28994   return this.eachBefore(function(node) {
28995     if (node.children) {
28996       node.children.sort(compare);
28997     }
28998   });
28999 };
29000
29001 var node_path = function(end) {
29002   var start = this,
29003       ancestor = leastCommonAncestor(start, end),
29004       nodes = [start];
29005   while (start !== ancestor) {
29006     start = start.parent;
29007     nodes.push(start);
29008   }
29009   var k = nodes.length;
29010   while (end !== ancestor) {
29011     nodes.splice(k, 0, end);
29012     end = end.parent;
29013   }
29014   return nodes;
29015 };
29016
29017 function leastCommonAncestor(a, b) {
29018   if (a === b) return a;
29019   var aNodes = a.ancestors(),
29020       bNodes = b.ancestors(),
29021       c = null;
29022   a = aNodes.pop();
29023   b = bNodes.pop();
29024   while (a === b) {
29025     c = a;
29026     a = aNodes.pop();
29027     b = bNodes.pop();
29028   }
29029   return c;
29030 }
29031
29032 var node_ancestors = function() {
29033   var node = this, nodes = [node];
29034   while (node = node.parent) {
29035     nodes.push(node);
29036   }
29037   return nodes;
29038 };
29039
29040 var node_descendants = function() {
29041   var nodes = [];
29042   this.each(function(node) {
29043     nodes.push(node);
29044   });
29045   return nodes;
29046 };
29047
29048 var node_leaves = function() {
29049   var leaves = [];
29050   this.eachBefore(function(node) {
29051     if (!node.children) {
29052       leaves.push(node);
29053     }
29054   });
29055   return leaves;
29056 };
29057
29058 var node_links = function() {
29059   var root = this, links = [];
29060   root.each(function(node) {
29061     if (node !== root) { // Don’t include the root’s parent, if any.
29062       links.push({source: node.parent, target: node});
29063     }
29064   });
29065   return links;
29066 };
29067
29068 function hierarchy(data, children) {
29069   var root = new Node(data),
29070       valued = +data.value && (root.value = data.value),
29071       node,
29072       nodes = [root],
29073       child,
29074       childs,
29075       i,
29076       n;
29077
29078   if (children == null) children = defaultChildren;
29079
29080   while (node = nodes.pop()) {
29081     if (valued) node.value = +node.data.value;
29082     if ((childs = children(node.data)) && (n = childs.length)) {
29083       node.children = new Array(n);
29084       for (i = n - 1; i >= 0; --i) {
29085         nodes.push(child = node.children[i] = new Node(childs[i]));
29086         child.parent = node;
29087         child.depth = node.depth + 1;
29088       }
29089     }
29090   }
29091
29092   return root.eachBefore(computeHeight);
29093 }
29094
29095 function node_copy() {
29096   return hierarchy(this).eachBefore(copyData);
29097 }
29098
29099 function defaultChildren(d) {
29100   return d.children;
29101 }
29102
29103 function copyData(node) {
29104   node.data = node.data.data;
29105 }
29106
29107 function computeHeight(node) {
29108   var height = 0;
29109   do node.height = height;
29110   while ((node = node.parent) && (node.height < ++height));
29111 }
29112
29113 function Node(data) {
29114   this.data = data;
29115   this.depth =
29116   this.height = 0;
29117   this.parent = null;
29118 }
29119
29120 Node.prototype = hierarchy.prototype = {
29121   constructor: Node,
29122   count: node_count,
29123   each: node_each,
29124   eachAfter: node_eachAfter,
29125   eachBefore: node_eachBefore,
29126   sum: node_sum,
29127   sort: node_sort,
29128   path: node_path,
29129   ancestors: node_ancestors,
29130   descendants: node_descendants,
29131   leaves: node_leaves,
29132   links: node_links,
29133   copy: node_copy
29134 };
29135
29136 function Node$2(value) {
29137   this._ = value;
29138   this.next = null;
29139 }
29140
29141 var shuffle$1 = function(array) {
29142   var i,
29143       n = (array = array.slice()).length,
29144       head = null,
29145       node = head;
29146
29147   while (n) {
29148     var next = new Node$2(array[n - 1]);
29149     if (node) node = node.next = next;
29150     else node = head = next;
29151     array[i] = array[--n];
29152   }
29153
29154   return {
29155     head: head,
29156     tail: node
29157   };
29158 };
29159
29160 var enclose = function(circles) {
29161   return encloseN(shuffle$1(circles), []);
29162 };
29163
29164 function encloses(a, b) {
29165   var dx = b.x - a.x,
29166       dy = b.y - a.y,
29167       dr = a.r - b.r;
29168   return dr * dr + 1e-6 > dx * dx + dy * dy;
29169 }
29170
29171 // Returns the smallest circle that contains circles L and intersects circles B.
29172 function encloseN(L, B) {
29173   var circle,
29174       l0 = null,
29175       l1 = L.head,
29176       l2,
29177       p1;
29178
29179   switch (B.length) {
29180     case 1: circle = enclose1(B[0]); break;
29181     case 2: circle = enclose2(B[0], B[1]); break;
29182     case 3: circle = enclose3(B[0], B[1], B[2]); break;
29183   }
29184
29185   while (l1) {
29186     p1 = l1._, l2 = l1.next;
29187     if (!circle || !encloses(circle, p1)) {
29188
29189       // Temporarily truncate L before l1.
29190       if (l0) L.tail = l0, l0.next = null;
29191       else L.head = L.tail = null;
29192
29193       B.push(p1);
29194       circle = encloseN(L, B); // Note: reorders L!
29195       B.pop();
29196
29197       // Move l1 to the front of L and reconnect the truncated list L.
29198       if (L.head) l1.next = L.head, L.head = l1;
29199       else l1.next = null, L.head = L.tail = l1;
29200       l0 = L.tail, l0.next = l2;
29201
29202     } else {
29203       l0 = l1;
29204     }
29205     l1 = l2;
29206   }
29207
29208   L.tail = l0;
29209   return circle;
29210 }
29211
29212 function enclose1(a) {
29213   return {
29214     x: a.x,
29215     y: a.y,
29216     r: a.r
29217   };
29218 }
29219
29220 function enclose2(a, b) {
29221   var x1 = a.x, y1 = a.y, r1 = a.r,
29222       x2 = b.x, y2 = b.y, r2 = b.r,
29223       x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1,
29224       l = Math.sqrt(x21 * x21 + y21 * y21);
29225   return {
29226     x: (x1 + x2 + x21 / l * r21) / 2,
29227     y: (y1 + y2 + y21 / l * r21) / 2,
29228     r: (l + r1 + r2) / 2
29229   };
29230 }
29231
29232 function enclose3(a, b, c) {
29233   var x1 = a.x, y1 = a.y, r1 = a.r,
29234       x2 = b.x, y2 = b.y, r2 = b.r,
29235       x3 = c.x, y3 = c.y, r3 = c.r,
29236       a2 = 2 * (x1 - x2),
29237       b2 = 2 * (y1 - y2),
29238       c2 = 2 * (r2 - r1),
29239       d2 = x1 * x1 + y1 * y1 - r1 * r1 - x2 * x2 - y2 * y2 + r2 * r2,
29240       a3 = 2 * (x1 - x3),
29241       b3 = 2 * (y1 - y3),
29242       c3 = 2 * (r3 - r1),
29243       d3 = x1 * x1 + y1 * y1 - r1 * r1 - x3 * x3 - y3 * y3 + r3 * r3,
29244       ab = a3 * b2 - a2 * b3,
29245       xa = (b2 * d3 - b3 * d2) / ab - x1,
29246       xb = (b3 * c2 - b2 * c3) / ab,
29247       ya = (a3 * d2 - a2 * d3) / ab - y1,
29248       yb = (a2 * c3 - a3 * c2) / ab,
29249       A = xb * xb + yb * yb - 1,
29250       B = 2 * (xa * xb + ya * yb + r1),
29251       C = xa * xa + ya * ya - r1 * r1,
29252       r = (-B - Math.sqrt(B * B - 4 * A * C)) / (2 * A);
29253   return {
29254     x: xa + xb * r + x1,
29255     y: ya + yb * r + y1,
29256     r: r
29257   };
29258 }
29259
29260 function place(a, b, c) {
29261   var ax = a.x,
29262       ay = a.y,
29263       da = b.r + c.r,
29264       db = a.r + c.r,
29265       dx = b.x - ax,
29266       dy = b.y - ay,
29267       dc = dx * dx + dy * dy;
29268   if (dc) {
29269     var x = 0.5 + ((db *= db) - (da *= da)) / (2 * dc),
29270         y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
29271     c.x = ax + x * dx + y * dy;
29272     c.y = ay + x * dy - y * dx;
29273   } else {
29274     c.x = ax + db;
29275     c.y = ay;
29276   }
29277 }
29278
29279 function intersects(a, b) {
29280   var dx = b.x - a.x,
29281       dy = b.y - a.y,
29282       dr = a.r + b.r;
29283   return dr * dr - 1e-6 > dx * dx + dy * dy;
29284 }
29285
29286 function distance2(node, x, y) {
29287   var a = node._,
29288       b = node.next._,
29289       ab = a.r + b.r,
29290       dx = (a.x * b.r + b.x * a.r) / ab - x,
29291       dy = (a.y * b.r + b.y * a.r) / ab - y;
29292   return dx * dx + dy * dy;
29293 }
29294
29295 function Node$1(circle) {
29296   this._ = circle;
29297   this.next = null;
29298   this.previous = null;
29299 }
29300
29301 function packEnclose(circles) {
29302   if (!(n = circles.length)) return 0;
29303
29304   var a, b, c, n;
29305
29306   // Place the first circle.
29307   a = circles[0], a.x = 0, a.y = 0;
29308   if (!(n > 1)) return a.r;
29309
29310   // Place the second circle.
29311   b = circles[1], a.x = -b.r, b.x = a.r, b.y = 0;
29312   if (!(n > 2)) return a.r + b.r;
29313
29314   // Place the third circle.
29315   place(b, a, c = circles[2]);
29316
29317   // Initialize the weighted centroid.
29318   var aa = a.r * a.r,
29319       ba = b.r * b.r,
29320       ca = c.r * c.r,
29321       oa = aa + ba + ca,
29322       ox = aa * a.x + ba * b.x + ca * c.x,
29323       oy = aa * a.y + ba * b.y + ca * c.y,
29324       cx, cy, i, j, k, sj, sk;
29325
29326   // Initialize the front-chain using the first three circles a, b and c.
29327   a = new Node$1(a), b = new Node$1(b), c = new Node$1(c);
29328   a.next = c.previous = b;
29329   b.next = a.previous = c;
29330   c.next = b.previous = a;
29331
29332   // Attempt to place each remaining circle…
29333   pack: for (i = 3; i < n; ++i) {
29334     place(a._, b._, c = circles[i]), c = new Node$1(c);
29335
29336     // Find the closest intersecting circle on the front-chain, if any.
29337     // “Closeness” is determined by linear distance along the front-chain.
29338     // “Ahead” or “behind” is likewise determined by linear distance.
29339     j = b.next, k = a.previous, sj = b._.r, sk = a._.r;
29340     do {
29341       if (sj <= sk) {
29342         if (intersects(j._, c._)) {
29343           b = j, a.next = b, b.previous = a, --i;
29344           continue pack;
29345         }
29346         sj += j._.r, j = j.next;
29347       } else {
29348         if (intersects(k._, c._)) {
29349           a = k, a.next = b, b.previous = a, --i;
29350           continue pack;
29351         }
29352         sk += k._.r, k = k.previous;
29353       }
29354     } while (j !== k.next);
29355
29356     // Success! Insert the new circle c between a and b.
29357     c.previous = a, c.next = b, a.next = b.previous = b = c;
29358
29359     // Update the weighted centroid.
29360     oa += ca = c._.r * c._.r;
29361     ox += ca * c._.x;
29362     oy += ca * c._.y;
29363
29364     // Compute the new closest circle pair to the centroid.
29365     aa = distance2(a, cx = ox / oa, cy = oy / oa);
29366     while ((c = c.next) !== b) {
29367       if ((ca = distance2(c, cx, cy)) < aa) {
29368         a = c, aa = ca;
29369       }
29370     }
29371     b = a.next;
29372   }
29373
29374   // Compute the enclosing circle of the front chain.
29375   a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = enclose(a);
29376
29377   // Translate the circles to put the enclosing circle around the origin.
29378   for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y;
29379
29380   return c.r;
29381 }
29382
29383 var siblings = function(circles) {
29384   packEnclose(circles);
29385   return circles;
29386 };
29387
29388 function optional(f) {
29389   return f == null ? null : required(f);
29390 }
29391
29392 function required(f) {
29393   if (typeof f !== "function") throw new Error;
29394   return f;
29395 }
29396
29397 function constantZero() {
29398   return 0;
29399 }
29400
29401 var constant$8 = function(x) {
29402   return function() {
29403     return x;
29404   };
29405 };
29406
29407 function defaultRadius$1(d) {
29408   return Math.sqrt(d.value);
29409 }
29410
29411 var index$5 = function() {
29412   var radius = null,
29413       dx = 1,
29414       dy = 1,
29415       padding = constantZero;
29416
29417   function pack(root) {
29418     root.x = dx / 2, root.y = dy / 2;
29419     if (radius) {
29420       root.eachBefore(radiusLeaf(radius))
29421           .eachAfter(packChildren(padding, 0.5))
29422           .eachBefore(translateChild(1));
29423     } else {
29424       root.eachBefore(radiusLeaf(defaultRadius$1))
29425           .eachAfter(packChildren(constantZero, 1))
29426           .eachAfter(packChildren(padding, root.r / Math.min(dx, dy)))
29427           .eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r)));
29428     }
29429     return root;
29430   }
29431
29432   pack.radius = function(x) {
29433     return arguments.length ? (radius = optional(x), pack) : radius;
29434   };
29435
29436   pack.size = function(x) {
29437     return arguments.length ? (dx = +x[0], dy = +x[1], pack) : [dx, dy];
29438   };
29439
29440   pack.padding = function(x) {
29441     return arguments.length ? (padding = typeof x === "function" ? x : constant$8(+x), pack) : padding;
29442   };
29443
29444   return pack;
29445 };
29446
29447 function radiusLeaf(radius) {
29448   return function(node) {
29449     if (!node.children) {
29450       node.r = Math.max(0, +radius(node) || 0);
29451     }
29452   };
29453 }
29454
29455 function packChildren(padding, k) {
29456   return function(node) {
29457     if (children = node.children) {
29458       var children,
29459           i,
29460           n = children.length,
29461           r = padding(node) * k || 0,
29462           e;
29463
29464       if (r) for (i = 0; i < n; ++i) children[i].r += r;
29465       e = packEnclose(children);
29466       if (r) for (i = 0; i < n; ++i) children[i].r -= r;
29467       node.r = e + r;
29468     }
29469   };
29470 }
29471
29472 function translateChild(k) {
29473   return function(node) {
29474     var parent = node.parent;
29475     node.r *= k;
29476     if (parent) {
29477       node.x = parent.x + k * node.x;
29478       node.y = parent.y + k * node.y;
29479     }
29480   };
29481 }
29482
29483 var roundNode = function(node) {
29484   node.x0 = Math.round(node.x0);
29485   node.y0 = Math.round(node.y0);
29486   node.x1 = Math.round(node.x1);
29487   node.y1 = Math.round(node.y1);
29488 };
29489
29490 var treemapDice = function(parent, x0, y0, x1, y1) {
29491   var nodes = parent.children,
29492       node,
29493       i = -1,
29494       n = nodes.length,
29495       k = parent.value && (x1 - x0) / parent.value;
29496
29497   while (++i < n) {
29498     node = nodes[i], node.y0 = y0, node.y1 = y1;
29499     node.x0 = x0, node.x1 = x0 += node.value * k;
29500   }
29501 };
29502
29503 var partition = function() {
29504   var dx = 1,
29505       dy = 1,
29506       padding = 0,
29507       round = false;
29508
29509   function partition(root) {
29510     var n = root.height + 1;
29511     root.x0 =
29512     root.y0 = padding;
29513     root.x1 = dx;
29514     root.y1 = dy / n;
29515     root.eachBefore(positionNode(dy, n));
29516     if (round) root.eachBefore(roundNode);
29517     return root;
29518   }
29519
29520   function positionNode(dy, n) {
29521     return function(node) {
29522       if (node.children) {
29523         treemapDice(node, node.x0, dy * (node.depth + 1) / n, node.x1, dy * (node.depth + 2) / n);
29524       }
29525       var x0 = node.x0,
29526           y0 = node.y0,
29527           x1 = node.x1 - padding,
29528           y1 = node.y1 - padding;
29529       if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29530       if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29531       node.x0 = x0;
29532       node.y0 = y0;
29533       node.x1 = x1;
29534       node.y1 = y1;
29535     };
29536   }
29537
29538   partition.round = function(x) {
29539     return arguments.length ? (round = !!x, partition) : round;
29540   };
29541
29542   partition.size = function(x) {
29543     return arguments.length ? (dx = +x[0], dy = +x[1], partition) : [dx, dy];
29544   };
29545
29546   partition.padding = function(x) {
29547     return arguments.length ? (padding = +x, partition) : padding;
29548   };
29549
29550   return partition;
29551 };
29552
29553 var keyPrefix$1 = "$";
29554 var preroot = {depth: -1};
29555 var ambiguous = {};
29556
29557 function defaultId(d) {
29558   return d.id;
29559 }
29560
29561 function defaultParentId(d) {
29562   return d.parentId;
29563 }
29564
29565 var stratify = function() {
29566   var id = defaultId,
29567       parentId = defaultParentId;
29568
29569   function stratify(data) {
29570     var d,
29571         i,
29572         n = data.length,
29573         root,
29574         parent,
29575         node,
29576         nodes = new Array(n),
29577         nodeId,
29578         nodeKey,
29579         nodeByKey = {};
29580
29581     for (i = 0; i < n; ++i) {
29582       d = data[i], node = nodes[i] = new Node(d);
29583       if ((nodeId = id(d, i, data)) != null && (nodeId += "")) {
29584         nodeKey = keyPrefix$1 + (node.id = nodeId);
29585         nodeByKey[nodeKey] = nodeKey in nodeByKey ? ambiguous : node;
29586       }
29587     }
29588
29589     for (i = 0; i < n; ++i) {
29590       node = nodes[i], nodeId = parentId(data[i], i, data);
29591       if (nodeId == null || !(nodeId += "")) {
29592         if (root) throw new Error("multiple roots");
29593         root = node;
29594       } else {
29595         parent = nodeByKey[keyPrefix$1 + nodeId];
29596         if (!parent) throw new Error("missing: " + nodeId);
29597         if (parent === ambiguous) throw new Error("ambiguous: " + nodeId);
29598         if (parent.children) parent.children.push(node);
29599         else parent.children = [node];
29600         node.parent = parent;
29601       }
29602     }
29603
29604     if (!root) throw new Error("no root");
29605     root.parent = preroot;
29606     root.eachBefore(function(node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight);
29607     root.parent = null;
29608     if (n > 0) throw new Error("cycle");
29609
29610     return root;
29611   }
29612
29613   stratify.id = function(x) {
29614     return arguments.length ? (id = required(x), stratify) : id;
29615   };
29616
29617   stratify.parentId = function(x) {
29618     return arguments.length ? (parentId = required(x), stratify) : parentId;
29619   };
29620
29621   return stratify;
29622 };
29623
29624 function defaultSeparation$1(a, b) {
29625   return a.parent === b.parent ? 1 : 2;
29626 }
29627
29628 // function radialSeparation(a, b) {
29629 //   return (a.parent === b.parent ? 1 : 2) / a.depth;
29630 // }
29631
29632 // This function is used to traverse the left contour of a subtree (or
29633 // subforest). It returns the successor of v on this contour. This successor is
29634 // either given by the leftmost child of v or by the thread of v. The function
29635 // returns null if and only if v is on the highest level of its subtree.
29636 function nextLeft(v) {
29637   var children = v.children;
29638   return children ? children[0] : v.t;
29639 }
29640
29641 // This function works analogously to nextLeft.
29642 function nextRight(v) {
29643   var children = v.children;
29644   return children ? children[children.length - 1] : v.t;
29645 }
29646
29647 // Shifts the current subtree rooted at w+. This is done by increasing
29648 // prelim(w+) and mod(w+) by shift.
29649 function moveSubtree(wm, wp, shift) {
29650   var change = shift / (wp.i - wm.i);
29651   wp.c -= change;
29652   wp.s += shift;
29653   wm.c += change;
29654   wp.z += shift;
29655   wp.m += shift;
29656 }
29657
29658 // All other shifts, applied to the smaller subtrees between w- and w+, are
29659 // performed by this function. To prepare the shifts, we have to adjust
29660 // change(w+), shift(w+), and change(w-).
29661 function executeShifts(v) {
29662   var shift = 0,
29663       change = 0,
29664       children = v.children,
29665       i = children.length,
29666       w;
29667   while (--i >= 0) {
29668     w = children[i];
29669     w.z += shift;
29670     w.m += shift;
29671     shift += w.s + (change += w.c);
29672   }
29673 }
29674
29675 // If vi-’s ancestor is a sibling of v, returns vi-’s ancestor. Otherwise,
29676 // returns the specified (default) ancestor.
29677 function nextAncestor(vim, v, ancestor) {
29678   return vim.a.parent === v.parent ? vim.a : ancestor;
29679 }
29680
29681 function TreeNode(node, i) {
29682   this._ = node;
29683   this.parent = null;
29684   this.children = null;
29685   this.A = null; // default ancestor
29686   this.a = this; // ancestor
29687   this.z = 0; // prelim
29688   this.m = 0; // mod
29689   this.c = 0; // change
29690   this.s = 0; // shift
29691   this.t = null; // thread
29692   this.i = i; // number
29693 }
29694
29695 TreeNode.prototype = Object.create(Node.prototype);
29696
29697 function treeRoot(root) {
29698   var tree = new TreeNode(root, 0),
29699       node,
29700       nodes = [tree],
29701       child,
29702       children,
29703       i,
29704       n;
29705
29706   while (node = nodes.pop()) {
29707     if (children = node._.children) {
29708       node.children = new Array(n = children.length);
29709       for (i = n - 1; i >= 0; --i) {
29710         nodes.push(child = node.children[i] = new TreeNode(children[i], i));
29711         child.parent = node;
29712       }
29713     }
29714   }
29715
29716   (tree.parent = new TreeNode(null, 0)).children = [tree];
29717   return tree;
29718 }
29719
29720 // Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
29721 var tree = function() {
29722   var separation = defaultSeparation$1,
29723       dx = 1,
29724       dy = 1,
29725       nodeSize = null;
29726
29727   function tree(root) {
29728     var t = treeRoot(root);
29729
29730     // Compute the layout using Buchheim et al.’s algorithm.
29731     t.eachAfter(firstWalk), t.parent.m = -t.z;
29732     t.eachBefore(secondWalk);
29733
29734     // If a fixed node size is specified, scale x and y.
29735     if (nodeSize) root.eachBefore(sizeNode);
29736
29737     // If a fixed tree size is specified, scale x and y based on the extent.
29738     // Compute the left-most, right-most, and depth-most nodes for extents.
29739     else {
29740       var left = root,
29741           right = root,
29742           bottom = root;
29743       root.eachBefore(function(node) {
29744         if (node.x < left.x) left = node;
29745         if (node.x > right.x) right = node;
29746         if (node.depth > bottom.depth) bottom = node;
29747       });
29748       var s = left === right ? 1 : separation(left, right) / 2,
29749           tx = s - left.x,
29750           kx = dx / (right.x + s + tx),
29751           ky = dy / (bottom.depth || 1);
29752       root.eachBefore(function(node) {
29753         node.x = (node.x + tx) * kx;
29754         node.y = node.depth * ky;
29755       });
29756     }
29757
29758     return root;
29759   }
29760
29761   // Computes a preliminary x-coordinate for v. Before that, FIRST WALK is
29762   // applied recursively to the children of v, as well as the function
29763   // APPORTION. After spacing out the children by calling EXECUTE SHIFTS, the
29764   // node v is placed to the midpoint of its outermost children.
29765   function firstWalk(v) {
29766     var children = v.children,
29767         siblings = v.parent.children,
29768         w = v.i ? siblings[v.i - 1] : null;
29769     if (children) {
29770       executeShifts(v);
29771       var midpoint = (children[0].z + children[children.length - 1].z) / 2;
29772       if (w) {
29773         v.z = w.z + separation(v._, w._);
29774         v.m = v.z - midpoint;
29775       } else {
29776         v.z = midpoint;
29777       }
29778     } else if (w) {
29779       v.z = w.z + separation(v._, w._);
29780     }
29781     v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
29782   }
29783
29784   // Computes all real x-coordinates by summing up the modifiers recursively.
29785   function secondWalk(v) {
29786     v._.x = v.z + v.parent.m;
29787     v.m += v.parent.m;
29788   }
29789
29790   // The core of the algorithm. Here, a new subtree is combined with the
29791   // previous subtrees. Threads are used to traverse the inside and outside
29792   // contours of the left and right subtree up to the highest common level. The
29793   // vertices used for the traversals are vi+, vi-, vo-, and vo+, where the
29794   // superscript o means outside and i means inside, the subscript - means left
29795   // subtree and + means right subtree. For summing up the modifiers along the
29796   // contour, we use respective variables si+, si-, so-, and so+. Whenever two
29797   // nodes of the inside contours conflict, we compute the left one of the
29798   // greatest uncommon ancestors using the function ANCESTOR and call MOVE
29799   // SUBTREE to shift the subtree and prepare the shifts of smaller subtrees.
29800   // Finally, we add a new thread (if necessary).
29801   function apportion(v, w, ancestor) {
29802     if (w) {
29803       var vip = v,
29804           vop = v,
29805           vim = w,
29806           vom = vip.parent.children[0],
29807           sip = vip.m,
29808           sop = vop.m,
29809           sim = vim.m,
29810           som = vom.m,
29811           shift;
29812       while (vim = nextRight(vim), vip = nextLeft(vip), vim && vip) {
29813         vom = nextLeft(vom);
29814         vop = nextRight(vop);
29815         vop.a = v;
29816         shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
29817         if (shift > 0) {
29818           moveSubtree(nextAncestor(vim, v, ancestor), v, shift);
29819           sip += shift;
29820           sop += shift;
29821         }
29822         sim += vim.m;
29823         sip += vip.m;
29824         som += vom.m;
29825         sop += vop.m;
29826       }
29827       if (vim && !nextRight(vop)) {
29828         vop.t = vim;
29829         vop.m += sim - sop;
29830       }
29831       if (vip && !nextLeft(vom)) {
29832         vom.t = vip;
29833         vom.m += sip - som;
29834         ancestor = v;
29835       }
29836     }
29837     return ancestor;
29838   }
29839
29840   function sizeNode(node) {
29841     node.x *= dx;
29842     node.y = node.depth * dy;
29843   }
29844
29845   tree.separation = function(x) {
29846     return arguments.length ? (separation = x, tree) : separation;
29847   };
29848
29849   tree.size = function(x) {
29850     return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], tree) : (nodeSize ? null : [dx, dy]);
29851   };
29852
29853   tree.nodeSize = function(x) {
29854     return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], tree) : (nodeSize ? [dx, dy] : null);
29855   };
29856
29857   return tree;
29858 };
29859
29860 var treemapSlice = function(parent, x0, y0, x1, y1) {
29861   var nodes = parent.children,
29862       node,
29863       i = -1,
29864       n = nodes.length,
29865       k = parent.value && (y1 - y0) / parent.value;
29866
29867   while (++i < n) {
29868     node = nodes[i], node.x0 = x0, node.x1 = x1;
29869     node.y0 = y0, node.y1 = y0 += node.value * k;
29870   }
29871 };
29872
29873 var phi = (1 + Math.sqrt(5)) / 2;
29874
29875 function squarifyRatio(ratio, parent, x0, y0, x1, y1) {
29876   var rows = [],
29877       nodes = parent.children,
29878       row,
29879       nodeValue,
29880       i0 = 0,
29881       i1 = 0,
29882       n = nodes.length,
29883       dx, dy,
29884       value = parent.value,
29885       sumValue,
29886       minValue,
29887       maxValue,
29888       newRatio,
29889       minRatio,
29890       alpha,
29891       beta;
29892
29893   while (i0 < n) {
29894     dx = x1 - x0, dy = y1 - y0;
29895
29896     // Find the next non-empty node.
29897     do sumValue = nodes[i1++].value; while (!sumValue && i1 < n);
29898     minValue = maxValue = sumValue;
29899     alpha = Math.max(dy / dx, dx / dy) / (value * ratio);
29900     beta = sumValue * sumValue * alpha;
29901     minRatio = Math.max(maxValue / beta, beta / minValue);
29902
29903     // Keep adding nodes while the aspect ratio maintains or improves.
29904     for (; i1 < n; ++i1) {
29905       sumValue += nodeValue = nodes[i1].value;
29906       if (nodeValue < minValue) minValue = nodeValue;
29907       if (nodeValue > maxValue) maxValue = nodeValue;
29908       beta = sumValue * sumValue * alpha;
29909       newRatio = Math.max(maxValue / beta, beta / minValue);
29910       if (newRatio > minRatio) { sumValue -= nodeValue; break; }
29911       minRatio = newRatio;
29912     }
29913
29914     // Position and record the row orientation.
29915     rows.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)});
29916     if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += dy * sumValue / value : y1);
29917     else treemapSlice(row, x0, y0, value ? x0 += dx * sumValue / value : x1, y1);
29918     value -= sumValue, i0 = i1;
29919   }
29920
29921   return rows;
29922 }
29923
29924 var squarify = ((function custom(ratio) {
29925
29926   function squarify(parent, x0, y0, x1, y1) {
29927     squarifyRatio(ratio, parent, x0, y0, x1, y1);
29928   }
29929
29930   squarify.ratio = function(x) {
29931     return custom((x = +x) > 1 ? x : 1);
29932   };
29933
29934   return squarify;
29935 }))(phi);
29936
29937 var index$6 = function() {
29938   var tile = squarify,
29939       round = false,
29940       dx = 1,
29941       dy = 1,
29942       paddingStack = [0],
29943       paddingInner = constantZero,
29944       paddingTop = constantZero,
29945       paddingRight = constantZero,
29946       paddingBottom = constantZero,
29947       paddingLeft = constantZero;
29948
29949   function treemap(root) {
29950     root.x0 =
29951     root.y0 = 0;
29952     root.x1 = dx;
29953     root.y1 = dy;
29954     root.eachBefore(positionNode);
29955     paddingStack = [0];
29956     if (round) root.eachBefore(roundNode);
29957     return root;
29958   }
29959
29960   function positionNode(node) {
29961     var p = paddingStack[node.depth],
29962         x0 = node.x0 + p,
29963         y0 = node.y0 + p,
29964         x1 = node.x1 - p,
29965         y1 = node.y1 - p;
29966     if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29967     if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29968     node.x0 = x0;
29969     node.y0 = y0;
29970     node.x1 = x1;
29971     node.y1 = y1;
29972     if (node.children) {
29973       p = paddingStack[node.depth + 1] = paddingInner(node) / 2;
29974       x0 += paddingLeft(node) - p;
29975       y0 += paddingTop(node) - p;
29976       x1 -= paddingRight(node) - p;
29977       y1 -= paddingBottom(node) - p;
29978       if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
29979       if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
29980       tile(node, x0, y0, x1, y1);
29981     }
29982   }
29983
29984   treemap.round = function(x) {
29985     return arguments.length ? (round = !!x, treemap) : round;
29986   };
29987
29988   treemap.size = function(x) {
29989     return arguments.length ? (dx = +x[0], dy = +x[1], treemap) : [dx, dy];
29990   };
29991
29992   treemap.tile = function(x) {
29993     return arguments.length ? (tile = required(x), treemap) : tile;
29994   };
29995
29996   treemap.padding = function(x) {
29997     return arguments.length ? treemap.paddingInner(x).paddingOuter(x) : treemap.paddingInner();
29998   };
29999
30000   treemap.paddingInner = function(x) {
30001     return arguments.length ? (paddingInner = typeof x === "function" ? x : constant$8(+x), treemap) : paddingInner;
30002   };
30003
30004   treemap.paddingOuter = function(x) {
30005     return arguments.length ? treemap.paddingTop(x).paddingRight(x).paddingBottom(x).paddingLeft(x) : treemap.paddingTop();
30006   };
30007
30008   treemap.paddingTop = function(x) {
30009     return arguments.length ? (paddingTop = typeof x === "function" ? x : constant$8(+x), treemap) : paddingTop;
30010   };
30011
30012   treemap.paddingRight = function(x) {
30013     return arguments.length ? (paddingRight = typeof x === "function" ? x : constant$8(+x), treemap) : paddingRight;
30014   };
30015
30016   treemap.paddingBottom = function(x) {
30017     return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant$8(+x), treemap) : paddingBottom;
30018   };
30019
30020   treemap.paddingLeft = function(x) {
30021     return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant$8(+x), treemap) : paddingLeft;
30022   };
30023
30024   return treemap;
30025 };
30026
30027 var binary = function(parent, x0, y0, x1, y1) {
30028   var nodes = parent.children,
30029       i, n = nodes.length,
30030       sum, sums = new Array(n + 1);
30031
30032   for (sums[0] = sum = i = 0; i < n; ++i) {
30033     sums[i + 1] = sum += nodes[i].value;
30034   }
30035
30036   partition(0, n, parent.value, x0, y0, x1, y1);
30037
30038   function partition(i, j, value, x0, y0, x1, y1) {
30039     if (i >= j - 1) {
30040       var node = nodes[i];
30041       node.x0 = x0, node.y0 = y0;
30042       node.x1 = x1, node.y1 = y1;
30043       return;
30044     }
30045
30046     var valueOffset = sums[i],
30047         valueTarget = (value / 2) + valueOffset,
30048         k = i + 1,
30049         hi = j - 1;
30050
30051     while (k < hi) {
30052       var mid = k + hi >>> 1;
30053       if (sums[mid] < valueTarget) k = mid + 1;
30054       else hi = mid;
30055     }
30056
30057     if ((valueTarget - sums[k - 1]) < (sums[k] - valueTarget) && i + 1 < k) --k;
30058
30059     var valueLeft = sums[k] - valueOffset,
30060         valueRight = value - valueLeft;
30061
30062     if ((x1 - x0) > (y1 - y0)) {
30063       var xk = (x0 * valueRight + x1 * valueLeft) / value;
30064       partition(i, k, valueLeft, x0, y0, xk, y1);
30065       partition(k, j, valueRight, xk, y0, x1, y1);
30066     } else {
30067       var yk = (y0 * valueRight + y1 * valueLeft) / value;
30068       partition(i, k, valueLeft, x0, y0, x1, yk);
30069       partition(k, j, valueRight, x0, yk, x1, y1);
30070     }
30071   }
30072 };
30073
30074 var sliceDice = function(parent, x0, y0, x1, y1) {
30075   (parent.depth & 1 ? treemapSlice : treemapDice)(parent, x0, y0, x1, y1);
30076 };
30077
30078 var resquarify = ((function custom(ratio) {
30079
30080   function resquarify(parent, x0, y0, x1, y1) {
30081     if ((rows = parent._squarify) && (rows.ratio === ratio)) {
30082       var rows,
30083           row,
30084           nodes,
30085           i,
30086           j = -1,
30087           n,
30088           m = rows.length,
30089           value = parent.value;
30090
30091       while (++j < m) {
30092         row = rows[j], nodes = row.children;
30093         for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value;
30094         if (row.dice) treemapDice(row, x0, y0, x1, y0 += (y1 - y0) * row.value / value);
30095         else treemapSlice(row, x0, y0, x0 += (x1 - x0) * row.value / value, y1);
30096         value -= row.value;
30097       }
30098     } else {
30099       parent._squarify = rows = squarifyRatio(ratio, parent, x0, y0, x1, y1);
30100       rows.ratio = ratio;
30101     }
30102   }
30103
30104   resquarify.ratio = function(x) {
30105     return custom((x = +x) > 1 ? x : 1);
30106   };
30107
30108   return resquarify;
30109 }))(phi);
30110
30111 var d3polygonArea = function(polygon) {
30112   var i = -1,
30113       n = polygon.length,
30114       a,
30115       b = polygon[n - 1],
30116       area = 0;
30117
30118   while (++i < n) {
30119     a = b;
30120     b = polygon[i];
30121     area += a[1] * b[0] - a[0] * b[1];
30122   }
30123
30124   return area / 2;
30125 };
30126
30127 var d3polygonCentroid = function(polygon) {
30128   var i = -1,
30129       n = polygon.length,
30130       x = 0,
30131       y = 0,
30132       a,
30133       b = polygon[n - 1],
30134       c,
30135       k = 0;
30136
30137   while (++i < n) {
30138     a = b;
30139     b = polygon[i];
30140     k += c = a[0] * b[1] - b[0] * a[1];
30141     x += (a[0] + b[0]) * c;
30142     y += (a[1] + b[1]) * c;
30143   }
30144
30145   return k *= 3, [x / k, y / k];
30146 };
30147
30148 // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
30149 // the 3D cross product in a quadrant I Cartesian coordinate system (+x is
30150 // right, +y is up). Returns a positive value if ABC is counter-clockwise,
30151 // negative if clockwise, and zero if the points are collinear.
30152 var cross$1 = function(a, b, c) {
30153   return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
30154 };
30155
30156 function lexicographicOrder(a, b) {
30157   return a[0] - b[0] || a[1] - b[1];
30158 }
30159
30160 // Computes the upper convex hull per the monotone chain algorithm.
30161 // Assumes points.length >= 3, is sorted by x, unique in y.
30162 // Returns an array of indices into points in left-to-right order.
30163 function computeUpperHullIndexes(points) {
30164   var n = points.length,
30165       indexes = [0, 1],
30166       size = 2;
30167
30168   for (var i = 2; i < n; ++i) {
30169     while (size > 1 && cross$1(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size;
30170     indexes[size++] = i;
30171   }
30172
30173   return indexes.slice(0, size); // remove popped points
30174 }
30175
30176 var d3polygonHull = function(points) {
30177   if ((n = points.length) < 3) return null;
30178
30179   var i,
30180       n,
30181       sortedPoints = new Array(n),
30182       flippedPoints = new Array(n);
30183
30184   for (i = 0; i < n; ++i) sortedPoints[i] = [+points[i][0], +points[i][1], i];
30185   sortedPoints.sort(lexicographicOrder);
30186   for (i = 0; i < n; ++i) flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
30187
30188   var upperIndexes = computeUpperHullIndexes(sortedPoints),
30189       lowerIndexes = computeUpperHullIndexes(flippedPoints);
30190
30191   // Construct the hull polygon, removing possible duplicate endpoints.
30192   var skipLeft = lowerIndexes[0] === upperIndexes[0],
30193       skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
30194       hull = [];
30195
30196   // Add upper hull in right-to-l order.
30197   // Then add lower hull in left-to-right order.
30198   for (i = upperIndexes.length - 1; i >= 0; --i) hull.push(points[sortedPoints[upperIndexes[i]][2]]);
30199   for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
30200
30201   return hull;
30202 };
30203
30204 var contains$1 = function(polygon, point) {
30205   var n = polygon.length,
30206       p = polygon[n - 1],
30207       x = point[0], y = point[1],
30208       x0 = p[0], y0 = p[1],
30209       x1, y1,
30210       inside = false;
30211
30212   for (var i = 0; i < n; ++i) {
30213     p = polygon[i], x1 = p[0], y1 = p[1];
30214     if (((y1 > y) !== (y0 > y)) && (x < (x0 - x1) * (y - y1) / (y0 - y1) + x1)) inside = !inside;
30215     x0 = x1, y0 = y1;
30216   }
30217
30218   return inside;
30219 };
30220
30221 var length$1 = function(polygon) {
30222   var i = -1,
30223       n = polygon.length,
30224       b = polygon[n - 1],
30225       xa,
30226       ya,
30227       xb = b[0],
30228       yb = b[1],
30229       perimeter = 0;
30230
30231   while (++i < n) {
30232     xa = xb;
30233     ya = yb;
30234     b = polygon[i];
30235     xb = b[0];
30236     yb = b[1];
30237     xa -= xb;
30238     ya -= yb;
30239     perimeter += Math.sqrt(xa * xa + ya * ya);
30240   }
30241
30242   return perimeter;
30243 };
30244
30245 var slice$3 = [].slice;
30246
30247 var noabort = {};
30248
30249 function Queue(size) {
30250   this._size = size;
30251   this._call =
30252   this._error = null;
30253   this._tasks = [];
30254   this._data = [];
30255   this._waiting =
30256   this._active =
30257   this._ended =
30258   this._start = 0; // inside a synchronous task callback?
30259 }
30260
30261 Queue.prototype = queue.prototype = {
30262   constructor: Queue,
30263   defer: function(callback) {
30264     if (typeof callback !== "function") throw new Error("invalid callback");
30265     if (this._call) throw new Error("defer after await");
30266     if (this._error != null) return this;
30267     var t = slice$3.call(arguments, 1);
30268     t.push(callback);
30269     ++this._waiting, this._tasks.push(t);
30270     poke$1(this);
30271     return this;
30272   },
30273   abort: function() {
30274     if (this._error == null) abort(this, new Error("abort"));
30275     return this;
30276   },
30277   await: function(callback) {
30278     if (typeof callback !== "function") throw new Error("invalid callback");
30279     if (this._call) throw new Error("multiple await");
30280     this._call = function(error, results) { callback.apply(null, [error].concat(results)); };
30281     maybeNotify(this);
30282     return this;
30283   },
30284   awaitAll: function(callback) {
30285     if (typeof callback !== "function") throw new Error("invalid callback");
30286     if (this._call) throw new Error("multiple await");
30287     this._call = callback;
30288     maybeNotify(this);
30289     return this;
30290   }
30291 };
30292
30293 function poke$1(q) {
30294   if (!q._start) {
30295     try { start$1(q); } // let the current task complete
30296     catch (e) {
30297       if (q._tasks[q._ended + q._active - 1]) abort(q, e); // task errored synchronously
30298       else if (!q._data) throw e; // await callback errored synchronously
30299     }
30300   }
30301 }
30302
30303 function start$1(q) {
30304   while (q._start = q._waiting && q._active < q._size) {
30305     var i = q._ended + q._active,
30306         t = q._tasks[i],
30307         j = t.length - 1,
30308         c = t[j];
30309     t[j] = end(q, i);
30310     --q._waiting, ++q._active;
30311     t = c.apply(null, t);
30312     if (!q._tasks[i]) continue; // task finished synchronously
30313     q._tasks[i] = t || noabort;
30314   }
30315 }
30316
30317 function end(q, i) {
30318   return function(e, r) {
30319     if (!q._tasks[i]) return; // ignore multiple callbacks
30320     --q._active, ++q._ended;
30321     q._tasks[i] = null;
30322     if (q._error != null) return; // ignore secondary errors
30323     if (e != null) {
30324       abort(q, e);
30325     } else {
30326       q._data[i] = r;
30327       if (q._waiting) poke$1(q);
30328       else maybeNotify(q);
30329     }
30330   };
30331 }
30332
30333 function abort(q, e) {
30334   var i = q._tasks.length, t;
30335   q._error = e; // ignore active callbacks
30336   q._data = undefined; // allow gc
30337   q._waiting = NaN; // prevent starting
30338
30339   while (--i >= 0) {
30340     if (t = q._tasks[i]) {
30341       q._tasks[i] = null;
30342       if (t.abort) {
30343         try { t.abort(); }
30344         catch (e) { /* ignore */ }
30345       }
30346     }
30347   }
30348
30349   q._active = NaN; // allow notification
30350   maybeNotify(q);
30351 }
30352
30353 function maybeNotify(q) {
30354   if (!q._active && q._call) {
30355     var d = q._data;
30356     q._data = undefined; // allow gc
30357     q._call(q._error, d);
30358   }
30359 }
30360
30361 function queue(concurrency) {
30362   if (concurrency == null) concurrency = Infinity;
30363   else if (!((concurrency = +concurrency) >= 1)) throw new Error("invalid concurrency");
30364   return new Queue(concurrency);
30365 }
30366
30367 var defaultSource$1 = function() {
30368   return Math.random();
30369 };
30370
30371 var uniform = ((function sourceRandomUniform(source) {
30372   function randomUniform(min, max) {
30373     min = min == null ? 0 : +min;
30374     max = max == null ? 1 : +max;
30375     if (arguments.length === 1) max = min, min = 0;
30376     else max -= min;
30377     return function() {
30378       return source() * max + min;
30379     };
30380   }
30381
30382   randomUniform.source = sourceRandomUniform;
30383
30384   return randomUniform;
30385 }))(defaultSource$1);
30386
30387 var normal = ((function sourceRandomNormal(source) {
30388   function randomNormal(mu, sigma) {
30389     var x, r;
30390     mu = mu == null ? 0 : +mu;
30391     sigma = sigma == null ? 1 : +sigma;
30392     return function() {
30393       var y;
30394
30395       // If available, use the second previously-generated uniform random.
30396       if (x != null) y = x, x = null;
30397
30398       // Otherwise, generate a new x and y.
30399       else do {
30400         x = source() * 2 - 1;
30401         y = source() * 2 - 1;
30402         r = x * x + y * y;
30403       } while (!r || r > 1);
30404
30405       return mu + sigma * y * Math.sqrt(-2 * Math.log(r) / r);
30406     };
30407   }
30408
30409   randomNormal.source = sourceRandomNormal;
30410
30411   return randomNormal;
30412 }))(defaultSource$1);
30413
30414 var logNormal = ((function sourceRandomLogNormal(source) {
30415   function randomLogNormal() {
30416     var randomNormal = normal.source(source).apply(this, arguments);
30417     return function() {
30418       return Math.exp(randomNormal());
30419     };
30420   }
30421
30422   randomLogNormal.source = sourceRandomLogNormal;
30423
30424   return randomLogNormal;
30425 }))(defaultSource$1);
30426
30427 var irwinHall = ((function sourceRandomIrwinHall(source) {
30428   function randomIrwinHall(n) {
30429     return function() {
30430       for (var sum = 0, i = 0; i < n; ++i) sum += source();
30431       return sum;
30432     };
30433   }
30434
30435   randomIrwinHall.source = sourceRandomIrwinHall;
30436
30437   return randomIrwinHall;
30438 }))(defaultSource$1);
30439
30440 var bates = ((function sourceRandomBates(source) {
30441   function randomBates(n) {
30442     var randomIrwinHall = irwinHall.source(source)(n);
30443     return function() {
30444       return randomIrwinHall() / n;
30445     };
30446   }
30447
30448   randomBates.source = sourceRandomBates;
30449
30450   return randomBates;
30451 }))(defaultSource$1);
30452
30453 var exponential$1 = ((function sourceRandomExponential(source) {
30454   function randomExponential(lambda) {
30455     return function() {
30456       return -Math.log(1 - source()) / lambda;
30457     };
30458   }
30459
30460   randomExponential.source = sourceRandomExponential;
30461
30462   return randomExponential;
30463 }))(defaultSource$1);
30464
30465 var request = function(url, callback) {
30466   var request,
30467       event = dispatch("beforesend", "progress", "load", "error"),
30468       mimeType,
30469       headers = map$1(),
30470       xhr = new XMLHttpRequest,
30471       user = null,
30472       password = null,
30473       response,
30474       responseType,
30475       timeout = 0;
30476
30477   // If IE does not support CORS, use XDomainRequest.
30478   if (typeof XDomainRequest !== "undefined"
30479       && !("withCredentials" in xhr)
30480       && /^(http(s)?:)?\/\//.test(url)) xhr = new XDomainRequest;
30481
30482   "onload" in xhr
30483       ? xhr.onload = xhr.onerror = xhr.ontimeout = respond
30484       : xhr.onreadystatechange = function(o) { xhr.readyState > 3 && respond(o); };
30485
30486   function respond(o) {
30487     var status = xhr.status, result;
30488     if (!status && hasResponse(xhr)
30489         || status >= 200 && status < 300
30490         || status === 304) {
30491       if (response) {
30492         try {
30493           result = response.call(request, xhr);
30494         } catch (e) {
30495           event.call("error", request, e);
30496           return;
30497         }
30498       } else {
30499         result = xhr;
30500       }
30501       event.call("load", request, result);
30502     } else {
30503       event.call("error", request, o);
30504     }
30505   }
30506
30507   xhr.onprogress = function(e) {
30508     event.call("progress", request, e);
30509   };
30510
30511   request = {
30512     header: function(name, value) {
30513       name = (name + "").toLowerCase();
30514       if (arguments.length < 2) return headers.get(name);
30515       if (value == null) headers.remove(name);
30516       else headers.set(name, value + "");
30517       return request;
30518     },
30519
30520     // If mimeType is non-null and no Accept header is set, a default is used.
30521     mimeType: function(value) {
30522       if (!arguments.length) return mimeType;
30523       mimeType = value == null ? null : value + "";
30524       return request;
30525     },
30526
30527     // Specifies what type the response value should take;
30528     // for instance, arraybuffer, blob, document, or text.
30529     responseType: function(value) {
30530       if (!arguments.length) return responseType;
30531       responseType = value;
30532       return request;
30533     },
30534
30535     timeout: function(value) {
30536       if (!arguments.length) return timeout;
30537       timeout = +value;
30538       return request;
30539     },
30540
30541     user: function(value) {
30542       return arguments.length < 1 ? user : (user = value == null ? null : value + "", request);
30543     },
30544
30545     password: function(value) {
30546       return arguments.length < 1 ? password : (password = value == null ? null : value + "", request);
30547     },
30548
30549     // Specify how to convert the response content to a specific type;
30550     // changes the callback value on "load" events.
30551     response: function(value) {
30552       response = value;
30553       return request;
30554     },
30555
30556     // Alias for send("GET", …).
30557     get: function(data, callback) {
30558       return request.send("GET", data, callback);
30559     },
30560
30561     // Alias for send("POST", …).
30562     post: function(data, callback) {
30563       return request.send("POST", data, callback);
30564     },
30565
30566     // If callback is non-null, it will be used for error and load events.
30567     send: function(method, data, callback) {
30568       xhr.open(method, url, true, user, password);
30569       if (mimeType != null && !headers.has("accept")) headers.set("accept", mimeType + ",*/*");
30570       if (xhr.setRequestHeader) headers.each(function(value, name) { xhr.setRequestHeader(name, value); });
30571       if (mimeType != null && xhr.overrideMimeType) xhr.overrideMimeType(mimeType);
30572       if (responseType != null) xhr.responseType = responseType;
30573       if (timeout > 0) xhr.timeout = timeout;
30574       if (callback == null && typeof data === "function") callback = data, data = null;
30575       if (callback != null && callback.length === 1) callback = fixCallback(callback);
30576       if (callback != null) request.on("error", callback).on("load", function(xhr) { callback(null, xhr); });
30577       event.call("beforesend", request, xhr);
30578       xhr.send(data == null ? null : data);
30579       return request;
30580     },
30581
30582     abort: function() {
30583       xhr.abort();
30584       return request;
30585     },
30586
30587     on: function() {
30588       var value = event.on.apply(event, arguments);
30589       return value === event ? request : value;
30590     }
30591   };
30592
30593   if (callback != null) {
30594     if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
30595     return request.get(callback);
30596   }
30597
30598   return request;
30599 };
30600
30601 function fixCallback(callback) {
30602   return function(error, xhr) {
30603     callback(error == null ? xhr : null);
30604   };
30605 }
30606
30607 function hasResponse(xhr) {
30608   var type = xhr.responseType;
30609   return type && type !== "text"
30610       ? xhr.response // null on error
30611       : xhr.responseText; // "" on error
30612 }
30613
30614 var type$3 = function(defaultMimeType, response) {
30615   return function(url, callback) {
30616     var r = request(url).mimeType(defaultMimeType).response(response);
30617     if (callback != null) {
30618       if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
30619       return r.get(callback);
30620     }
30621     return r;
30622   };
30623 };
30624
30625 var html = type$3("text/html", function(xhr) {
30626   return document.createRange().createContextualFragment(xhr.responseText);
30627 });
30628
30629 var json = type$3("application/json", function(xhr) {
30630   return JSON.parse(xhr.responseText);
30631 });
30632
30633 var text = type$3("text/plain", function(xhr) {
30634   return xhr.responseText;
30635 });
30636
30637 var xml = type$3("application/xml", function(xhr) {
30638   var xml = xhr.responseXML;
30639   if (!xml) throw new Error("parse error");
30640   return xml;
30641 });
30642
30643 var dsv$1 = function(defaultMimeType, parse) {
30644   return function(url, row, callback) {
30645     if (arguments.length < 3) callback = row, row = null;
30646     var r = request(url).mimeType(defaultMimeType);
30647     r.row = function(_) { return arguments.length ? r.response(responseOf(parse, row = _)) : row; };
30648     r.row(row);
30649     return callback ? r.get(callback) : r;
30650   };
30651 };
30652
30653 function responseOf(parse, row) {
30654   return function(request$$1) {
30655     return parse(request$$1.responseText, row);
30656   };
30657 }
30658
30659 var csv$1 = dsv$1("text/csv", csvParse);
30660
30661 var tsv$1 = dsv$1("text/tab-separated-values", tsvParse);
30662
30663 var array$2 = Array.prototype;
30664
30665 var map$3 = array$2.map;
30666 var slice$4 = array$2.slice;
30667
30668 var implicit = {name: "implicit"};
30669
30670 function ordinal(range) {
30671   var index = map$1(),
30672       domain = [],
30673       unknown = implicit;
30674
30675   range = range == null ? [] : slice$4.call(range);
30676
30677   function scale(d) {
30678     var key = d + "", i = index.get(key);
30679     if (!i) {
30680       if (unknown !== implicit) return unknown;
30681       index.set(key, i = domain.push(d));
30682     }
30683     return range[(i - 1) % range.length];
30684   }
30685
30686   scale.domain = function(_) {
30687     if (!arguments.length) return domain.slice();
30688     domain = [], index = map$1();
30689     var i = -1, n = _.length, d, key;
30690     while (++i < n) if (!index.has(key = (d = _[i]) + "")) index.set(key, domain.push(d));
30691     return scale;
30692   };
30693
30694   scale.range = function(_) {
30695     return arguments.length ? (range = slice$4.call(_), scale) : range.slice();
30696   };
30697
30698   scale.unknown = function(_) {
30699     return arguments.length ? (unknown = _, scale) : unknown;
30700   };
30701
30702   scale.copy = function() {
30703     return ordinal()
30704         .domain(domain)
30705         .range(range)
30706         .unknown(unknown);
30707   };
30708
30709   return scale;
30710 }
30711
30712 function band() {
30713   var scale = ordinal().unknown(undefined),
30714       domain = scale.domain,
30715       ordinalRange = scale.range,
30716       range = [0, 1],
30717       step,
30718       bandwidth,
30719       round = false,
30720       paddingInner = 0,
30721       paddingOuter = 0,
30722       align = 0.5;
30723
30724   delete scale.unknown;
30725
30726   function rescale() {
30727     var n = domain().length,
30728         reverse = range[1] < range[0],
30729         start = range[reverse - 0],
30730         stop = range[1 - reverse];
30731     step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2);
30732     if (round) step = Math.floor(step);
30733     start += (stop - start - step * (n - paddingInner)) * align;
30734     bandwidth = step * (1 - paddingInner);
30735     if (round) start = Math.round(start), bandwidth = Math.round(bandwidth);
30736     var values = sequence(n).map(function(i) { return start + step * i; });
30737     return ordinalRange(reverse ? values.reverse() : values);
30738   }
30739
30740   scale.domain = function(_) {
30741     return arguments.length ? (domain(_), rescale()) : domain();
30742   };
30743
30744   scale.range = function(_) {
30745     return arguments.length ? (range = [+_[0], +_[1]], rescale()) : range.slice();
30746   };
30747
30748   scale.rangeRound = function(_) {
30749     return range = [+_[0], +_[1]], round = true, rescale();
30750   };
30751
30752   scale.bandwidth = function() {
30753     return bandwidth;
30754   };
30755
30756   scale.step = function() {
30757     return step;
30758   };
30759
30760   scale.round = function(_) {
30761     return arguments.length ? (round = !!_, rescale()) : round;
30762   };
30763
30764   scale.padding = function(_) {
30765     return arguments.length ? (paddingInner = paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
30766   };
30767
30768   scale.paddingInner = function(_) {
30769     return arguments.length ? (paddingInner = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
30770   };
30771
30772   scale.paddingOuter = function(_) {
30773     return arguments.length ? (paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingOuter;
30774   };
30775
30776   scale.align = function(_) {
30777     return arguments.length ? (align = Math.max(0, Math.min(1, _)), rescale()) : align;
30778   };
30779
30780   scale.copy = function() {
30781     return band()
30782         .domain(domain())
30783         .range(range)
30784         .round(round)
30785         .paddingInner(paddingInner)
30786         .paddingOuter(paddingOuter)
30787         .align(align);
30788   };
30789
30790   return rescale();
30791 }
30792
30793 function pointish(scale) {
30794   var copy = scale.copy;
30795
30796   scale.padding = scale.paddingOuter;
30797   delete scale.paddingInner;
30798   delete scale.paddingOuter;
30799
30800   scale.copy = function() {
30801     return pointish(copy());
30802   };
30803
30804   return scale;
30805 }
30806
30807 function point$1() {
30808   return pointish(band().paddingInner(1));
30809 }
30810
30811 var constant$9 = function(x) {
30812   return function() {
30813     return x;
30814   };
30815 };
30816
30817 var number$1 = function(x) {
30818   return +x;
30819 };
30820
30821 var unit = [0, 1];
30822
30823 function deinterpolateLinear(a, b) {
30824   return (b -= (a = +a))
30825       ? function(x) { return (x - a) / b; }
30826       : constant$9(b);
30827 }
30828
30829 function deinterpolateClamp(deinterpolate) {
30830   return function(a, b) {
30831     var d = deinterpolate(a = +a, b = +b);
30832     return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); };
30833   };
30834 }
30835
30836 function reinterpolateClamp(reinterpolate$$1) {
30837   return function(a, b) {
30838     var r = reinterpolate$$1(a = +a, b = +b);
30839     return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); };
30840   };
30841 }
30842
30843 function bimap(domain, range, deinterpolate, reinterpolate$$1) {
30844   var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1];
30845   if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate$$1(r1, r0);
30846   else d0 = deinterpolate(d0, d1), r0 = reinterpolate$$1(r0, r1);
30847   return function(x) { return r0(d0(x)); };
30848 }
30849
30850 function polymap(domain, range, deinterpolate, reinterpolate$$1) {
30851   var j = Math.min(domain.length, range.length) - 1,
30852       d = new Array(j),
30853       r = new Array(j),
30854       i = -1;
30855
30856   // Reverse descending domains.
30857   if (domain[j] < domain[0]) {
30858     domain = domain.slice().reverse();
30859     range = range.slice().reverse();
30860   }
30861
30862   while (++i < j) {
30863     d[i] = deinterpolate(domain[i], domain[i + 1]);
30864     r[i] = reinterpolate$$1(range[i], range[i + 1]);
30865   }
30866
30867   return function(x) {
30868     var i = bisectRight(domain, x, 1, j) - 1;
30869     return r[i](d[i](x));
30870   };
30871 }
30872
30873 function copy(source, target) {
30874   return target
30875       .domain(source.domain())
30876       .range(source.range())
30877       .interpolate(source.interpolate())
30878       .clamp(source.clamp());
30879 }
30880
30881 // deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
30882 // reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].
30883 function continuous(deinterpolate, reinterpolate$$1) {
30884   var domain = unit,
30885       range = unit,
30886       interpolate = interpolateValue,
30887       clamp = false,
30888       piecewise,
30889       output,
30890       input;
30891
30892   function rescale() {
30893     piecewise = Math.min(domain.length, range.length) > 2 ? polymap : bimap;
30894     output = input = null;
30895     return scale;
30896   }
30897
30898   function scale(x) {
30899     return (output || (output = piecewise(domain, range, clamp ? deinterpolateClamp(deinterpolate) : deinterpolate, interpolate)))(+x);
30900   }
30901
30902   scale.invert = function(y) {
30903     return (input || (input = piecewise(range, domain, deinterpolateLinear, clamp ? reinterpolateClamp(reinterpolate$$1) : reinterpolate$$1)))(+y);
30904   };
30905
30906   scale.domain = function(_) {
30907     return arguments.length ? (domain = map$3.call(_, number$1), rescale()) : domain.slice();
30908   };
30909
30910   scale.range = function(_) {
30911     return arguments.length ? (range = slice$4.call(_), rescale()) : range.slice();
30912   };
30913
30914   scale.rangeRound = function(_) {
30915     return range = slice$4.call(_), interpolate = interpolateRound, rescale();
30916   };
30917
30918   scale.clamp = function(_) {
30919     return arguments.length ? (clamp = !!_, rescale()) : clamp;
30920   };
30921
30922   scale.interpolate = function(_) {
30923     return arguments.length ? (interpolate = _, rescale()) : interpolate;
30924   };
30925
30926   return rescale();
30927 }
30928
30929 var tickFormat = function(domain, count, specifier) {
30930   var start = domain[0],
30931       stop = domain[domain.length - 1],
30932       step = tickStep(start, stop, count == null ? 10 : count),
30933       precision;
30934   specifier = formatSpecifier(specifier == null ? ",f" : specifier);
30935   switch (specifier.type) {
30936     case "s": {
30937       var value = Math.max(Math.abs(start), Math.abs(stop));
30938       if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
30939       return formatPrefix(specifier, value);
30940     }
30941     case "":
30942     case "e":
30943     case "g":
30944     case "p":
30945     case "r": {
30946       if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
30947       break;
30948     }
30949     case "f":
30950     case "%": {
30951       if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
30952       break;
30953     }
30954   }
30955   return format(specifier);
30956 };
30957
30958 function linearish(scale) {
30959   var domain = scale.domain;
30960
30961   scale.ticks = function(count) {
30962     var d = domain();
30963     return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
30964   };
30965
30966   scale.tickFormat = function(count, specifier) {
30967     return tickFormat(domain(), count, specifier);
30968   };
30969
30970   scale.nice = function(count) {
30971     if (count == null) count = 10;
30972
30973     var d = domain(),
30974         i0 = 0,
30975         i1 = d.length - 1,
30976         start = d[i0],
30977         stop = d[i1],
30978         step;
30979
30980     if (stop < start) {
30981       step = start, start = stop, stop = step;
30982       step = i0, i0 = i1, i1 = step;
30983     }
30984
30985     step = tickIncrement(start, stop, count);
30986
30987     if (step > 0) {
30988       start = Math.floor(start / step) * step;
30989       stop = Math.ceil(stop / step) * step;
30990       step = tickIncrement(start, stop, count);
30991     } else if (step < 0) {
30992       start = Math.ceil(start * step) / step;
30993       stop = Math.floor(stop * step) / step;
30994       step = tickIncrement(start, stop, count);
30995     }
30996
30997     if (step > 0) {
30998       d[i0] = Math.floor(start / step) * step;
30999       d[i1] = Math.ceil(stop / step) * step;
31000       domain(d);
31001     } else if (step < 0) {
31002       d[i0] = Math.ceil(start * step) / step;
31003       d[i1] = Math.floor(stop * step) / step;
31004       domain(d);
31005     }
31006
31007     return scale;
31008   };
31009
31010   return scale;
31011 }
31012
31013 function linear$2() {
31014   var scale = continuous(deinterpolateLinear, reinterpolate);
31015
31016   scale.copy = function() {
31017     return copy(scale, linear$2());
31018   };
31019
31020   return linearish(scale);
31021 }
31022
31023 function identity$6() {
31024   var domain = [0, 1];
31025
31026   function scale(x) {
31027     return +x;
31028   }
31029
31030   scale.invert = scale;
31031
31032   scale.domain = scale.range = function(_) {
31033     return arguments.length ? (domain = map$3.call(_, number$1), scale) : domain.slice();
31034   };
31035
31036   scale.copy = function() {
31037     return identity$6().domain(domain);
31038   };
31039
31040   return linearish(scale);
31041 }
31042
31043 var nice = function(domain, interval) {
31044   domain = domain.slice();
31045
31046   var i0 = 0,
31047       i1 = domain.length - 1,
31048       x0 = domain[i0],
31049       x1 = domain[i1],
31050       t;
31051
31052   if (x1 < x0) {
31053     t = i0, i0 = i1, i1 = t;
31054     t = x0, x0 = x1, x1 = t;
31055   }
31056
31057   domain[i0] = interval.floor(x0);
31058   domain[i1] = interval.ceil(x1);
31059   return domain;
31060 };
31061
31062 function deinterpolate(a, b) {
31063   return (b = Math.log(b / a))
31064       ? function(x) { return Math.log(x / a) / b; }
31065       : constant$9(b);
31066 }
31067
31068 function reinterpolate$1(a, b) {
31069   return a < 0
31070       ? function(t) { return -Math.pow(-b, t) * Math.pow(-a, 1 - t); }
31071       : function(t) { return Math.pow(b, t) * Math.pow(a, 1 - t); };
31072 }
31073
31074 function pow10(x) {
31075   return isFinite(x) ? +("1e" + x) : x < 0 ? 0 : x;
31076 }
31077
31078 function powp(base) {
31079   return base === 10 ? pow10
31080       : base === Math.E ? Math.exp
31081       : function(x) { return Math.pow(base, x); };
31082 }
31083
31084 function logp(base) {
31085   return base === Math.E ? Math.log
31086       : base === 10 && Math.log10
31087       || base === 2 && Math.log2
31088       || (base = Math.log(base), function(x) { return Math.log(x) / base; });
31089 }
31090
31091 function reflect(f) {
31092   return function(x) {
31093     return -f(-x);
31094   };
31095 }
31096
31097 function log$1() {
31098   var scale = continuous(deinterpolate, reinterpolate$1).domain([1, 10]),
31099       domain = scale.domain,
31100       base = 10,
31101       logs = logp(10),
31102       pows = powp(10);
31103
31104   function rescale() {
31105     logs = logp(base), pows = powp(base);
31106     if (domain()[0] < 0) logs = reflect(logs), pows = reflect(pows);
31107     return scale;
31108   }
31109
31110   scale.base = function(_) {
31111     return arguments.length ? (base = +_, rescale()) : base;
31112   };
31113
31114   scale.domain = function(_) {
31115     return arguments.length ? (domain(_), rescale()) : domain();
31116   };
31117
31118   scale.ticks = function(count) {
31119     var d = domain(),
31120         u = d[0],
31121         v = d[d.length - 1],
31122         r;
31123
31124     if (r = v < u) i = u, u = v, v = i;
31125
31126     var i = logs(u),
31127         j = logs(v),
31128         p,
31129         k,
31130         t,
31131         n = count == null ? 10 : +count,
31132         z = [];
31133
31134     if (!(base % 1) && j - i < n) {
31135       i = Math.round(i) - 1, j = Math.round(j) + 1;
31136       if (u > 0) for (; i < j; ++i) {
31137         for (k = 1, p = pows(i); k < base; ++k) {
31138           t = p * k;
31139           if (t < u) continue;
31140           if (t > v) break;
31141           z.push(t);
31142         }
31143       } else for (; i < j; ++i) {
31144         for (k = base - 1, p = pows(i); k >= 1; --k) {
31145           t = p * k;
31146           if (t < u) continue;
31147           if (t > v) break;
31148           z.push(t);
31149         }
31150       }
31151     } else {
31152       z = ticks(i, j, Math.min(j - i, n)).map(pows);
31153     }
31154
31155     return r ? z.reverse() : z;
31156   };
31157
31158   scale.tickFormat = function(count, specifier) {
31159     if (specifier == null) specifier = base === 10 ? ".0e" : ",";
31160     if (typeof specifier !== "function") specifier = format(specifier);
31161     if (count === Infinity) return specifier;
31162     if (count == null) count = 10;
31163     var k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate?
31164     return function(d) {
31165       var i = d / pows(Math.round(logs(d)));
31166       if (i * base < base - 0.5) i *= base;
31167       return i <= k ? specifier(d) : "";
31168     };
31169   };
31170
31171   scale.nice = function() {
31172     return domain(nice(domain(), {
31173       floor: function(x) { return pows(Math.floor(logs(x))); },
31174       ceil: function(x) { return pows(Math.ceil(logs(x))); }
31175     }));
31176   };
31177
31178   scale.copy = function() {
31179     return copy(scale, log$1().base(base));
31180   };
31181
31182   return scale;
31183 }
31184
31185 function raise$1(x, exponent) {
31186   return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent);
31187 }
31188
31189 function pow$1() {
31190   var exponent = 1,
31191       scale = continuous(deinterpolate, reinterpolate),
31192       domain = scale.domain;
31193
31194   function deinterpolate(a, b) {
31195     return (b = raise$1(b, exponent) - (a = raise$1(a, exponent)))
31196         ? function(x) { return (raise$1(x, exponent) - a) / b; }
31197         : constant$9(b);
31198   }
31199
31200   function reinterpolate(a, b) {
31201     b = raise$1(b, exponent) - (a = raise$1(a, exponent));
31202     return function(t) { return raise$1(a + b * t, 1 / exponent); };
31203   }
31204
31205   scale.exponent = function(_) {
31206     return arguments.length ? (exponent = +_, domain(domain())) : exponent;
31207   };
31208
31209   scale.copy = function() {
31210     return copy(scale, pow$1().exponent(exponent));
31211   };
31212
31213   return linearish(scale);
31214 }
31215
31216 function sqrt$1() {
31217   return pow$1().exponent(0.5);
31218 }
31219
31220 function quantile() {
31221   var domain = [],
31222       range = [],
31223       thresholds = [];
31224
31225   function rescale() {
31226     var i = 0, n = Math.max(1, range.length);
31227     thresholds = new Array(n - 1);
31228     while (++i < n) thresholds[i - 1] = threshold(domain, i / n);
31229     return scale;
31230   }
31231
31232   function scale(x) {
31233     if (!isNaN(x = +x)) return range[bisectRight(thresholds, x)];
31234   }
31235
31236   scale.invertExtent = function(y) {
31237     var i = range.indexOf(y);
31238     return i < 0 ? [NaN, NaN] : [
31239       i > 0 ? thresholds[i - 1] : domain[0],
31240       i < thresholds.length ? thresholds[i] : domain[domain.length - 1]
31241     ];
31242   };
31243
31244   scale.domain = function(_) {
31245     if (!arguments.length) return domain.slice();
31246     domain = [];
31247     for (var i = 0, n = _.length, d; i < n; ++i) if (d = _[i], d != null && !isNaN(d = +d)) domain.push(d);
31248     domain.sort(ascending);
31249     return rescale();
31250   };
31251
31252   scale.range = function(_) {
31253     return arguments.length ? (range = slice$4.call(_), rescale()) : range.slice();
31254   };
31255
31256   scale.quantiles = function() {
31257     return thresholds.slice();
31258   };
31259
31260   scale.copy = function() {
31261     return quantile()
31262         .domain(domain)
31263         .range(range);
31264   };
31265
31266   return scale;
31267 }
31268
31269 function quantize$1() {
31270   var x0 = 0,
31271       x1 = 1,
31272       n = 1,
31273       domain = [0.5],
31274       range = [0, 1];
31275
31276   function scale(x) {
31277     if (x <= x) return range[bisectRight(domain, x, 0, n)];
31278   }
31279
31280   function rescale() {
31281     var i = -1;
31282     domain = new Array(n);
31283     while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
31284     return scale;
31285   }
31286
31287   scale.domain = function(_) {
31288     return arguments.length ? (x0 = +_[0], x1 = +_[1], rescale()) : [x0, x1];
31289   };
31290
31291   scale.range = function(_) {
31292     return arguments.length ? (n = (range = slice$4.call(_)).length - 1, rescale()) : range.slice();
31293   };
31294
31295   scale.invertExtent = function(y) {
31296     var i = range.indexOf(y);
31297     return i < 0 ? [NaN, NaN]
31298         : i < 1 ? [x0, domain[0]]
31299         : i >= n ? [domain[n - 1], x1]
31300         : [domain[i - 1], domain[i]];
31301   };
31302
31303   scale.copy = function() {
31304     return quantize$1()
31305         .domain([x0, x1])
31306         .range(range);
31307   };
31308
31309   return linearish(scale);
31310 }
31311
31312 function threshold$1() {
31313   var domain = [0.5],
31314       range = [0, 1],
31315       n = 1;
31316
31317   function scale(x) {
31318     if (x <= x) return range[bisectRight(domain, x, 0, n)];
31319   }
31320
31321   scale.domain = function(_) {
31322     return arguments.length ? (domain = slice$4.call(_), n = Math.min(domain.length, range.length - 1), scale) : domain.slice();
31323   };
31324
31325   scale.range = function(_) {
31326     return arguments.length ? (range = slice$4.call(_), n = Math.min(domain.length, range.length - 1), scale) : range.slice();
31327   };
31328
31329   scale.invertExtent = function(y) {
31330     var i = range.indexOf(y);
31331     return [domain[i - 1], domain[i]];
31332   };
31333
31334   scale.copy = function() {
31335     return threshold$1()
31336         .domain(domain)
31337         .range(range);
31338   };
31339
31340   return scale;
31341 }
31342
31343 var t0$1 = new Date;
31344 var t1$1 = new Date;
31345
31346 function newInterval(floori, offseti, count, field) {
31347
31348   function interval(date) {
31349     return floori(date = new Date(+date)), date;
31350   }
31351
31352   interval.floor = interval;
31353
31354   interval.ceil = function(date) {
31355     return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;
31356   };
31357
31358   interval.round = function(date) {
31359     var d0 = interval(date),
31360         d1 = interval.ceil(date);
31361     return date - d0 < d1 - date ? d0 : d1;
31362   };
31363
31364   interval.offset = function(date, step) {
31365     return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;
31366   };
31367
31368   interval.range = function(start, stop, step) {
31369     var range = [];
31370     start = interval.ceil(start);
31371     step = step == null ? 1 : Math.floor(step);
31372     if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date
31373     do range.push(new Date(+start)); while (offseti(start, step), floori(start), start < stop)
31374     return range;
31375   };
31376
31377   interval.filter = function(test) {
31378     return newInterval(function(date) {
31379       if (date >= date) while (floori(date), !test(date)) date.setTime(date - 1);
31380     }, function(date, step) {
31381       if (date >= date) while (--step >= 0) while (offseti(date, 1), !test(date)) {} // eslint-disable-line no-empty
31382     });
31383   };
31384
31385   if (count) {
31386     interval.count = function(start, end) {
31387       t0$1.setTime(+start), t1$1.setTime(+end);
31388       floori(t0$1), floori(t1$1);
31389       return Math.floor(count(t0$1, t1$1));
31390     };
31391
31392     interval.every = function(step) {
31393       step = Math.floor(step);
31394       return !isFinite(step) || !(step > 0) ? null
31395           : !(step > 1) ? interval
31396           : interval.filter(field
31397               ? function(d) { return field(d) % step === 0; }
31398               : function(d) { return interval.count(0, d) % step === 0; });
31399     };
31400   }
31401
31402   return interval;
31403 }
31404
31405 var millisecond = newInterval(function() {
31406   // noop
31407 }, function(date, step) {
31408   date.setTime(+date + step);
31409 }, function(start, end) {
31410   return end - start;
31411 });
31412
31413 // An optimized implementation for this simple case.
31414 millisecond.every = function(k) {
31415   k = Math.floor(k);
31416   if (!isFinite(k) || !(k > 0)) return null;
31417   if (!(k > 1)) return millisecond;
31418   return newInterval(function(date) {
31419     date.setTime(Math.floor(date / k) * k);
31420   }, function(date, step) {
31421     date.setTime(+date + step * k);
31422   }, function(start, end) {
31423     return (end - start) / k;
31424   });
31425 };
31426
31427 var milliseconds = millisecond.range;
31428
31429 var durationSecond$1 = 1e3;
31430 var durationMinute$1 = 6e4;
31431 var durationHour$1 = 36e5;
31432 var durationDay$1 = 864e5;
31433 var durationWeek$1 = 6048e5;
31434
31435 var second = newInterval(function(date) {
31436   date.setTime(Math.floor(date / durationSecond$1) * durationSecond$1);
31437 }, function(date, step) {
31438   date.setTime(+date + step * durationSecond$1);
31439 }, function(start, end) {
31440   return (end - start) / durationSecond$1;
31441 }, function(date) {
31442   return date.getUTCSeconds();
31443 });
31444
31445 var seconds = second.range;
31446
31447 var minute = newInterval(function(date) {
31448   date.setTime(Math.floor(date / durationMinute$1) * durationMinute$1);
31449 }, function(date, step) {
31450   date.setTime(+date + step * durationMinute$1);
31451 }, function(start, end) {
31452   return (end - start) / durationMinute$1;
31453 }, function(date) {
31454   return date.getMinutes();
31455 });
31456
31457 var minutes = minute.range;
31458
31459 var hour = newInterval(function(date) {
31460   var offset = date.getTimezoneOffset() * durationMinute$1 % durationHour$1;
31461   if (offset < 0) offset += durationHour$1;
31462   date.setTime(Math.floor((+date - offset) / durationHour$1) * durationHour$1 + offset);
31463 }, function(date, step) {
31464   date.setTime(+date + step * durationHour$1);
31465 }, function(start, end) {
31466   return (end - start) / durationHour$1;
31467 }, function(date) {
31468   return date.getHours();
31469 });
31470
31471 var hours = hour.range;
31472
31473 var day = newInterval(function(date) {
31474   date.setHours(0, 0, 0, 0);
31475 }, function(date, step) {
31476   date.setDate(date.getDate() + step);
31477 }, function(start, end) {
31478   return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute$1) / durationDay$1;
31479 }, function(date) {
31480   return date.getDate() - 1;
31481 });
31482
31483 var days = day.range;
31484
31485 function weekday(i) {
31486   return newInterval(function(date) {
31487     date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
31488     date.setHours(0, 0, 0, 0);
31489   }, function(date, step) {
31490     date.setDate(date.getDate() + step * 7);
31491   }, function(start, end) {
31492     return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute$1) / durationWeek$1;
31493   });
31494 }
31495
31496 var sunday = weekday(0);
31497 var monday = weekday(1);
31498 var tuesday = weekday(2);
31499 var wednesday = weekday(3);
31500 var thursday = weekday(4);
31501 var friday = weekday(5);
31502 var saturday = weekday(6);
31503
31504 var sundays = sunday.range;
31505 var mondays = monday.range;
31506 var tuesdays = tuesday.range;
31507 var wednesdays = wednesday.range;
31508 var thursdays = thursday.range;
31509 var fridays = friday.range;
31510 var saturdays = saturday.range;
31511
31512 var month = newInterval(function(date) {
31513   date.setDate(1);
31514   date.setHours(0, 0, 0, 0);
31515 }, function(date, step) {
31516   date.setMonth(date.getMonth() + step);
31517 }, function(start, end) {
31518   return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
31519 }, function(date) {
31520   return date.getMonth();
31521 });
31522
31523 var months = month.range;
31524
31525 var year = newInterval(function(date) {
31526   date.setMonth(0, 1);
31527   date.setHours(0, 0, 0, 0);
31528 }, function(date, step) {
31529   date.setFullYear(date.getFullYear() + step);
31530 }, function(start, end) {
31531   return end.getFullYear() - start.getFullYear();
31532 }, function(date) {
31533   return date.getFullYear();
31534 });
31535
31536 // An optimized implementation for this simple case.
31537 year.every = function(k) {
31538   return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
31539     date.setFullYear(Math.floor(date.getFullYear() / k) * k);
31540     date.setMonth(0, 1);
31541     date.setHours(0, 0, 0, 0);
31542   }, function(date, step) {
31543     date.setFullYear(date.getFullYear() + step * k);
31544   });
31545 };
31546
31547 var years = year.range;
31548
31549 var utcMinute = newInterval(function(date) {
31550   date.setUTCSeconds(0, 0);
31551 }, function(date, step) {
31552   date.setTime(+date + step * durationMinute$1);
31553 }, function(start, end) {
31554   return (end - start) / durationMinute$1;
31555 }, function(date) {
31556   return date.getUTCMinutes();
31557 });
31558
31559 var utcMinutes = utcMinute.range;
31560
31561 var utcHour = newInterval(function(date) {
31562   date.setUTCMinutes(0, 0, 0);
31563 }, function(date, step) {
31564   date.setTime(+date + step * durationHour$1);
31565 }, function(start, end) {
31566   return (end - start) / durationHour$1;
31567 }, function(date) {
31568   return date.getUTCHours();
31569 });
31570
31571 var utcHours = utcHour.range;
31572
31573 var utcDay = newInterval(function(date) {
31574   date.setUTCHours(0, 0, 0, 0);
31575 }, function(date, step) {
31576   date.setUTCDate(date.getUTCDate() + step);
31577 }, function(start, end) {
31578   return (end - start) / durationDay$1;
31579 }, function(date) {
31580   return date.getUTCDate() - 1;
31581 });
31582
31583 var utcDays = utcDay.range;
31584
31585 function utcWeekday(i) {
31586   return newInterval(function(date) {
31587     date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
31588     date.setUTCHours(0, 0, 0, 0);
31589   }, function(date, step) {
31590     date.setUTCDate(date.getUTCDate() + step * 7);
31591   }, function(start, end) {
31592     return (end - start) / durationWeek$1;
31593   });
31594 }
31595
31596 var utcSunday = utcWeekday(0);
31597 var utcMonday = utcWeekday(1);
31598 var utcTuesday = utcWeekday(2);
31599 var utcWednesday = utcWeekday(3);
31600 var utcThursday = utcWeekday(4);
31601 var utcFriday = utcWeekday(5);
31602 var utcSaturday = utcWeekday(6);
31603
31604 var utcSundays = utcSunday.range;
31605 var utcMondays = utcMonday.range;
31606 var utcTuesdays = utcTuesday.range;
31607 var utcWednesdays = utcWednesday.range;
31608 var utcThursdays = utcThursday.range;
31609 var utcFridays = utcFriday.range;
31610 var utcSaturdays = utcSaturday.range;
31611
31612 var utcMonth = newInterval(function(date) {
31613   date.setUTCDate(1);
31614   date.setUTCHours(0, 0, 0, 0);
31615 }, function(date, step) {
31616   date.setUTCMonth(date.getUTCMonth() + step);
31617 }, function(start, end) {
31618   return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;
31619 }, function(date) {
31620   return date.getUTCMonth();
31621 });
31622
31623 var utcMonths = utcMonth.range;
31624
31625 var utcYear = newInterval(function(date) {
31626   date.setUTCMonth(0, 1);
31627   date.setUTCHours(0, 0, 0, 0);
31628 }, function(date, step) {
31629   date.setUTCFullYear(date.getUTCFullYear() + step);
31630 }, function(start, end) {
31631   return end.getUTCFullYear() - start.getUTCFullYear();
31632 }, function(date) {
31633   return date.getUTCFullYear();
31634 });
31635
31636 // An optimized implementation for this simple case.
31637 utcYear.every = function(k) {
31638   return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
31639     date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);
31640     date.setUTCMonth(0, 1);
31641     date.setUTCHours(0, 0, 0, 0);
31642   }, function(date, step) {
31643     date.setUTCFullYear(date.getUTCFullYear() + step * k);
31644   });
31645 };
31646
31647 var utcYears = utcYear.range;
31648
31649 function localDate(d) {
31650   if (0 <= d.y && d.y < 100) {
31651     var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L);
31652     date.setFullYear(d.y);
31653     return date;
31654   }
31655   return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L);
31656 }
31657
31658 function utcDate(d) {
31659   if (0 <= d.y && d.y < 100) {
31660     var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L));
31661     date.setUTCFullYear(d.y);
31662     return date;
31663   }
31664   return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));
31665 }
31666
31667 function newYear(y) {
31668   return {y: y, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0};
31669 }
31670
31671 function formatLocale$1(locale) {
31672   var locale_dateTime = locale.dateTime,
31673       locale_date = locale.date,
31674       locale_time = locale.time,
31675       locale_periods = locale.periods,
31676       locale_weekdays = locale.days,
31677       locale_shortWeekdays = locale.shortDays,
31678       locale_months = locale.months,
31679       locale_shortMonths = locale.shortMonths;
31680
31681   var periodRe = formatRe(locale_periods),
31682       periodLookup = formatLookup(locale_periods),
31683       weekdayRe = formatRe(locale_weekdays),
31684       weekdayLookup = formatLookup(locale_weekdays),
31685       shortWeekdayRe = formatRe(locale_shortWeekdays),
31686       shortWeekdayLookup = formatLookup(locale_shortWeekdays),
31687       monthRe = formatRe(locale_months),
31688       monthLookup = formatLookup(locale_months),
31689       shortMonthRe = formatRe(locale_shortMonths),
31690       shortMonthLookup = formatLookup(locale_shortMonths);
31691
31692   var formats = {
31693     "a": formatShortWeekday,
31694     "A": formatWeekday,
31695     "b": formatShortMonth,
31696     "B": formatMonth,
31697     "c": null,
31698     "d": formatDayOfMonth,
31699     "e": formatDayOfMonth,
31700     "H": formatHour24,
31701     "I": formatHour12,
31702     "j": formatDayOfYear,
31703     "L": formatMilliseconds,
31704     "m": formatMonthNumber,
31705     "M": formatMinutes,
31706     "p": formatPeriod,
31707     "S": formatSeconds,
31708     "U": formatWeekNumberSunday,
31709     "w": formatWeekdayNumber,
31710     "W": formatWeekNumberMonday,
31711     "x": null,
31712     "X": null,
31713     "y": formatYear,
31714     "Y": formatFullYear,
31715     "Z": formatZone,
31716     "%": formatLiteralPercent
31717   };
31718
31719   var utcFormats = {
31720     "a": formatUTCShortWeekday,
31721     "A": formatUTCWeekday,
31722     "b": formatUTCShortMonth,
31723     "B": formatUTCMonth,
31724     "c": null,
31725     "d": formatUTCDayOfMonth,
31726     "e": formatUTCDayOfMonth,
31727     "H": formatUTCHour24,
31728     "I": formatUTCHour12,
31729     "j": formatUTCDayOfYear,
31730     "L": formatUTCMilliseconds,
31731     "m": formatUTCMonthNumber,
31732     "M": formatUTCMinutes,
31733     "p": formatUTCPeriod,
31734     "S": formatUTCSeconds,
31735     "U": formatUTCWeekNumberSunday,
31736     "w": formatUTCWeekdayNumber,
31737     "W": formatUTCWeekNumberMonday,
31738     "x": null,
31739     "X": null,
31740     "y": formatUTCYear,
31741     "Y": formatUTCFullYear,
31742     "Z": formatUTCZone,
31743     "%": formatLiteralPercent
31744   };
31745
31746   var parses = {
31747     "a": parseShortWeekday,
31748     "A": parseWeekday,
31749     "b": parseShortMonth,
31750     "B": parseMonth,
31751     "c": parseLocaleDateTime,
31752     "d": parseDayOfMonth,
31753     "e": parseDayOfMonth,
31754     "H": parseHour24,
31755     "I": parseHour24,
31756     "j": parseDayOfYear,
31757     "L": parseMilliseconds,
31758     "m": parseMonthNumber,
31759     "M": parseMinutes,
31760     "p": parsePeriod,
31761     "S": parseSeconds,
31762     "U": parseWeekNumberSunday,
31763     "w": parseWeekdayNumber,
31764     "W": parseWeekNumberMonday,
31765     "x": parseLocaleDate,
31766     "X": parseLocaleTime,
31767     "y": parseYear,
31768     "Y": parseFullYear,
31769     "Z": parseZone,
31770     "%": parseLiteralPercent
31771   };
31772
31773   // These recursive directive definitions must be deferred.
31774   formats.x = newFormat(locale_date, formats);
31775   formats.X = newFormat(locale_time, formats);
31776   formats.c = newFormat(locale_dateTime, formats);
31777   utcFormats.x = newFormat(locale_date, utcFormats);
31778   utcFormats.X = newFormat(locale_time, utcFormats);
31779   utcFormats.c = newFormat(locale_dateTime, utcFormats);
31780
31781   function newFormat(specifier, formats) {
31782     return function(date) {
31783       var string = [],
31784           i = -1,
31785           j = 0,
31786           n = specifier.length,
31787           c,
31788           pad,
31789           format;
31790
31791       if (!(date instanceof Date)) date = new Date(+date);
31792
31793       while (++i < n) {
31794         if (specifier.charCodeAt(i) === 37) {
31795           string.push(specifier.slice(j, i));
31796           if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);
31797           else pad = c === "e" ? " " : "0";
31798           if (format = formats[c]) c = format(date, pad);
31799           string.push(c);
31800           j = i + 1;
31801         }
31802       }
31803
31804       string.push(specifier.slice(j, i));
31805       return string.join("");
31806     };
31807   }
31808
31809   function newParse(specifier, newDate) {
31810     return function(string) {
31811       var d = newYear(1900),
31812           i = parseSpecifier(d, specifier, string += "", 0);
31813       if (i != string.length) return null;
31814
31815       // The am-pm flag is 0 for AM, and 1 for PM.
31816       if ("p" in d) d.H = d.H % 12 + d.p * 12;
31817
31818       // Convert day-of-week and week-of-year to day-of-year.
31819       if ("W" in d || "U" in d) {
31820         if (!("w" in d)) d.w = "W" in d ? 1 : 0;
31821         var day$$1 = "Z" in d ? utcDate(newYear(d.y)).getUTCDay() : newDate(newYear(d.y)).getDay();
31822         d.m = 0;
31823         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;
31824       }
31825
31826       // If a time zone is specified, all fields are interpreted as UTC and then
31827       // offset according to the specified time zone.
31828       if ("Z" in d) {
31829         d.H += d.Z / 100 | 0;
31830         d.M += d.Z % 100;
31831         return utcDate(d);
31832       }
31833
31834       // Otherwise, all fields are in local time.
31835       return newDate(d);
31836     };
31837   }
31838
31839   function parseSpecifier(d, specifier, string, j) {
31840     var i = 0,
31841         n = specifier.length,
31842         m = string.length,
31843         c,
31844         parse;
31845
31846     while (i < n) {
31847       if (j >= m) return -1;
31848       c = specifier.charCodeAt(i++);
31849       if (c === 37) {
31850         c = specifier.charAt(i++);
31851         parse = parses[c in pads ? specifier.charAt(i++) : c];
31852         if (!parse || ((j = parse(d, string, j)) < 0)) return -1;
31853       } else if (c != string.charCodeAt(j++)) {
31854         return -1;
31855       }
31856     }
31857
31858     return j;
31859   }
31860
31861   function parsePeriod(d, string, i) {
31862     var n = periodRe.exec(string.slice(i));
31863     return n ? (d.p = periodLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31864   }
31865
31866   function parseShortWeekday(d, string, i) {
31867     var n = shortWeekdayRe.exec(string.slice(i));
31868     return n ? (d.w = shortWeekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31869   }
31870
31871   function parseWeekday(d, string, i) {
31872     var n = weekdayRe.exec(string.slice(i));
31873     return n ? (d.w = weekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31874   }
31875
31876   function parseShortMonth(d, string, i) {
31877     var n = shortMonthRe.exec(string.slice(i));
31878     return n ? (d.m = shortMonthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31879   }
31880
31881   function parseMonth(d, string, i) {
31882     var n = monthRe.exec(string.slice(i));
31883     return n ? (d.m = monthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
31884   }
31885
31886   function parseLocaleDateTime(d, string, i) {
31887     return parseSpecifier(d, locale_dateTime, string, i);
31888   }
31889
31890   function parseLocaleDate(d, string, i) {
31891     return parseSpecifier(d, locale_date, string, i);
31892   }
31893
31894   function parseLocaleTime(d, string, i) {
31895     return parseSpecifier(d, locale_time, string, i);
31896   }
31897
31898   function formatShortWeekday(d) {
31899     return locale_shortWeekdays[d.getDay()];
31900   }
31901
31902   function formatWeekday(d) {
31903     return locale_weekdays[d.getDay()];
31904   }
31905
31906   function formatShortMonth(d) {
31907     return locale_shortMonths[d.getMonth()];
31908   }
31909
31910   function formatMonth(d) {
31911     return locale_months[d.getMonth()];
31912   }
31913
31914   function formatPeriod(d) {
31915     return locale_periods[+(d.getHours() >= 12)];
31916   }
31917
31918   function formatUTCShortWeekday(d) {
31919     return locale_shortWeekdays[d.getUTCDay()];
31920   }
31921
31922   function formatUTCWeekday(d) {
31923     return locale_weekdays[d.getUTCDay()];
31924   }
31925
31926   function formatUTCShortMonth(d) {
31927     return locale_shortMonths[d.getUTCMonth()];
31928   }
31929
31930   function formatUTCMonth(d) {
31931     return locale_months[d.getUTCMonth()];
31932   }
31933
31934   function formatUTCPeriod(d) {
31935     return locale_periods[+(d.getUTCHours() >= 12)];
31936   }
31937
31938   return {
31939     format: function(specifier) {
31940       var f = newFormat(specifier += "", formats);
31941       f.toString = function() { return specifier; };
31942       return f;
31943     },
31944     parse: function(specifier) {
31945       var p = newParse(specifier += "", localDate);
31946       p.toString = function() { return specifier; };
31947       return p;
31948     },
31949     utcFormat: function(specifier) {
31950       var f = newFormat(specifier += "", utcFormats);
31951       f.toString = function() { return specifier; };
31952       return f;
31953     },
31954     utcParse: function(specifier) {
31955       var p = newParse(specifier, utcDate);
31956       p.toString = function() { return specifier; };
31957       return p;
31958     }
31959   };
31960 }
31961
31962 var pads = {"-": "", "_": " ", "0": "0"};
31963 var numberRe = /^\s*\d+/;
31964 var percentRe = /^%/;
31965 var requoteRe = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
31966
31967 function pad(value, fill, width) {
31968   var sign = value < 0 ? "-" : "",
31969       string = (sign ? -value : value) + "",
31970       length = string.length;
31971   return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
31972 }
31973
31974 function requote(s) {
31975   return s.replace(requoteRe, "\\$&");
31976 }
31977
31978 function formatRe(names) {
31979   return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i");
31980 }
31981
31982 function formatLookup(names) {
31983   var map = {}, i = -1, n = names.length;
31984   while (++i < n) map[names[i].toLowerCase()] = i;
31985   return map;
31986 }
31987
31988 function parseWeekdayNumber(d, string, i) {
31989   var n = numberRe.exec(string.slice(i, i + 1));
31990   return n ? (d.w = +n[0], i + n[0].length) : -1;
31991 }
31992
31993 function parseWeekNumberSunday(d, string, i) {
31994   var n = numberRe.exec(string.slice(i));
31995   return n ? (d.U = +n[0], i + n[0].length) : -1;
31996 }
31997
31998 function parseWeekNumberMonday(d, string, i) {
31999   var n = numberRe.exec(string.slice(i));
32000   return n ? (d.W = +n[0], i + n[0].length) : -1;
32001 }
32002
32003 function parseFullYear(d, string, i) {
32004   var n = numberRe.exec(string.slice(i, i + 4));
32005   return n ? (d.y = +n[0], i + n[0].length) : -1;
32006 }
32007
32008 function parseYear(d, string, i) {
32009   var n = numberRe.exec(string.slice(i, i + 2));
32010   return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;
32011 }
32012
32013 function parseZone(d, string, i) {
32014   var n = /^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(string.slice(i, i + 6));
32015   return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || "00")), i + n[0].length) : -1;
32016 }
32017
32018 function parseMonthNumber(d, string, i) {
32019   var n = numberRe.exec(string.slice(i, i + 2));
32020   return n ? (d.m = n[0] - 1, i + n[0].length) : -1;
32021 }
32022
32023 function parseDayOfMonth(d, string, i) {
32024   var n = numberRe.exec(string.slice(i, i + 2));
32025   return n ? (d.d = +n[0], i + n[0].length) : -1;
32026 }
32027
32028 function parseDayOfYear(d, string, i) {
32029   var n = numberRe.exec(string.slice(i, i + 3));
32030   return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1;
32031 }
32032
32033 function parseHour24(d, string, i) {
32034   var n = numberRe.exec(string.slice(i, i + 2));
32035   return n ? (d.H = +n[0], i + n[0].length) : -1;
32036 }
32037
32038 function parseMinutes(d, string, i) {
32039   var n = numberRe.exec(string.slice(i, i + 2));
32040   return n ? (d.M = +n[0], i + n[0].length) : -1;
32041 }
32042
32043 function parseSeconds(d, string, i) {
32044   var n = numberRe.exec(string.slice(i, i + 2));
32045   return n ? (d.S = +n[0], i + n[0].length) : -1;
32046 }
32047
32048 function parseMilliseconds(d, string, i) {
32049   var n = numberRe.exec(string.slice(i, i + 3));
32050   return n ? (d.L = +n[0], i + n[0].length) : -1;
32051 }
32052
32053 function parseLiteralPercent(d, string, i) {
32054   var n = percentRe.exec(string.slice(i, i + 1));
32055   return n ? i + n[0].length : -1;
32056 }
32057
32058 function formatDayOfMonth(d, p) {
32059   return pad(d.getDate(), p, 2);
32060 }
32061
32062 function formatHour24(d, p) {
32063   return pad(d.getHours(), p, 2);
32064 }
32065
32066 function formatHour12(d, p) {
32067   return pad(d.getHours() % 12 || 12, p, 2);
32068 }
32069
32070 function formatDayOfYear(d, p) {
32071   return pad(1 + day.count(year(d), d), p, 3);
32072 }
32073
32074 function formatMilliseconds(d, p) {
32075   return pad(d.getMilliseconds(), p, 3);
32076 }
32077
32078 function formatMonthNumber(d, p) {
32079   return pad(d.getMonth() + 1, p, 2);
32080 }
32081
32082 function formatMinutes(d, p) {
32083   return pad(d.getMinutes(), p, 2);
32084 }
32085
32086 function formatSeconds(d, p) {
32087   return pad(d.getSeconds(), p, 2);
32088 }
32089
32090 function formatWeekNumberSunday(d, p) {
32091   return pad(sunday.count(year(d), d), p, 2);
32092 }
32093
32094 function formatWeekdayNumber(d) {
32095   return d.getDay();
32096 }
32097
32098 function formatWeekNumberMonday(d, p) {
32099   return pad(monday.count(year(d), d), p, 2);
32100 }
32101
32102 function formatYear(d, p) {
32103   return pad(d.getFullYear() % 100, p, 2);
32104 }
32105
32106 function formatFullYear(d, p) {
32107   return pad(d.getFullYear() % 10000, p, 4);
32108 }
32109
32110 function formatZone(d) {
32111   var z = d.getTimezoneOffset();
32112   return (z > 0 ? "-" : (z *= -1, "+"))
32113       + pad(z / 60 | 0, "0", 2)
32114       + pad(z % 60, "0", 2);
32115 }
32116
32117 function formatUTCDayOfMonth(d, p) {
32118   return pad(d.getUTCDate(), p, 2);
32119 }
32120
32121 function formatUTCHour24(d, p) {
32122   return pad(d.getUTCHours(), p, 2);
32123 }
32124
32125 function formatUTCHour12(d, p) {
32126   return pad(d.getUTCHours() % 12 || 12, p, 2);
32127 }
32128
32129 function formatUTCDayOfYear(d, p) {
32130   return pad(1 + utcDay.count(utcYear(d), d), p, 3);
32131 }
32132
32133 function formatUTCMilliseconds(d, p) {
32134   return pad(d.getUTCMilliseconds(), p, 3);
32135 }
32136
32137 function formatUTCMonthNumber(d, p) {
32138   return pad(d.getUTCMonth() + 1, p, 2);
32139 }
32140
32141 function formatUTCMinutes(d, p) {
32142   return pad(d.getUTCMinutes(), p, 2);
32143 }
32144
32145 function formatUTCSeconds(d, p) {
32146   return pad(d.getUTCSeconds(), p, 2);
32147 }
32148
32149 function formatUTCWeekNumberSunday(d, p) {
32150   return pad(utcSunday.count(utcYear(d), d), p, 2);
32151 }
32152
32153 function formatUTCWeekdayNumber(d) {
32154   return d.getUTCDay();
32155 }
32156
32157 function formatUTCWeekNumberMonday(d, p) {
32158   return pad(utcMonday.count(utcYear(d), d), p, 2);
32159 }
32160
32161 function formatUTCYear(d, p) {
32162   return pad(d.getUTCFullYear() % 100, p, 2);
32163 }
32164
32165 function formatUTCFullYear(d, p) {
32166   return pad(d.getUTCFullYear() % 10000, p, 4);
32167 }
32168
32169 function formatUTCZone() {
32170   return "+0000";
32171 }
32172
32173 function formatLiteralPercent() {
32174   return "%";
32175 }
32176
32177 var locale$2;
32178 var timeFormat;
32179 var timeParse;
32180 var utcFormat;
32181 var utcParse;
32182
32183 defaultLocale$1({
32184   dateTime: "%x, %X",
32185   date: "%-m/%-d/%Y",
32186   time: "%-I:%M:%S %p",
32187   periods: ["AM", "PM"],
32188   days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
32189   shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
32190   months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
32191   shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
32192 });
32193
32194 function defaultLocale$1(definition) {
32195   locale$2 = formatLocale$1(definition);
32196   timeFormat = locale$2.format;
32197   timeParse = locale$2.parse;
32198   utcFormat = locale$2.utcFormat;
32199   utcParse = locale$2.utcParse;
32200   return locale$2;
32201 }
32202
32203 var isoSpecifier = "%Y-%m-%dT%H:%M:%S.%LZ";
32204
32205 function formatIsoNative(date) {
32206   return date.toISOString();
32207 }
32208
32209 var formatIso = Date.prototype.toISOString
32210     ? formatIsoNative
32211     : utcFormat(isoSpecifier);
32212
32213 function parseIsoNative(string) {
32214   var date = new Date(string);
32215   return isNaN(date) ? null : date;
32216 }
32217
32218 var parseIso = +new Date("2000-01-01T00:00:00.000Z")
32219     ? parseIsoNative
32220     : utcParse(isoSpecifier);
32221
32222 var durationSecond = 1000;
32223 var durationMinute = durationSecond * 60;
32224 var durationHour = durationMinute * 60;
32225 var durationDay = durationHour * 24;
32226 var durationWeek = durationDay * 7;
32227 var durationMonth = durationDay * 30;
32228 var durationYear = durationDay * 365;
32229
32230 function date$1(t) {
32231   return new Date(t);
32232 }
32233
32234 function number$2(t) {
32235   return t instanceof Date ? +t : +new Date(+t);
32236 }
32237
32238 function calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format) {
32239   var scale = continuous(deinterpolateLinear, reinterpolate),
32240       invert = scale.invert,
32241       domain = scale.domain;
32242
32243   var formatMillisecond = format(".%L"),
32244       formatSecond = format(":%S"),
32245       formatMinute = format("%I:%M"),
32246       formatHour = format("%I %p"),
32247       formatDay = format("%a %d"),
32248       formatWeek = format("%b %d"),
32249       formatMonth = format("%B"),
32250       formatYear = format("%Y");
32251
32252   var tickIntervals = [
32253     [second$$1,  1,      durationSecond],
32254     [second$$1,  5,  5 * durationSecond],
32255     [second$$1, 15, 15 * durationSecond],
32256     [second$$1, 30, 30 * durationSecond],
32257     [minute$$1,  1,      durationMinute],
32258     [minute$$1,  5,  5 * durationMinute],
32259     [minute$$1, 15, 15 * durationMinute],
32260     [minute$$1, 30, 30 * durationMinute],
32261     [  hour$$1,  1,      durationHour  ],
32262     [  hour$$1,  3,  3 * durationHour  ],
32263     [  hour$$1,  6,  6 * durationHour  ],
32264     [  hour$$1, 12, 12 * durationHour  ],
32265     [   day$$1,  1,      durationDay   ],
32266     [   day$$1,  2,  2 * durationDay   ],
32267     [  week,  1,      durationWeek  ],
32268     [ month$$1,  1,      durationMonth ],
32269     [ month$$1,  3,  3 * durationMonth ],
32270     [  year$$1,  1,      durationYear  ]
32271   ];
32272
32273   function tickFormat(date$$1) {
32274     return (second$$1(date$$1) < date$$1 ? formatMillisecond
32275         : minute$$1(date$$1) < date$$1 ? formatSecond
32276         : hour$$1(date$$1) < date$$1 ? formatMinute
32277         : day$$1(date$$1) < date$$1 ? formatHour
32278         : month$$1(date$$1) < date$$1 ? (week(date$$1) < date$$1 ? formatDay : formatWeek)
32279         : year$$1(date$$1) < date$$1 ? formatMonth
32280         : formatYear)(date$$1);
32281   }
32282
32283   function tickInterval(interval$$1, start, stop, step) {
32284     if (interval$$1 == null) interval$$1 = 10;
32285
32286     // If a desired tick count is specified, pick a reasonable tick interval
32287     // based on the extent of the domain and a rough estimate of tick size.
32288     // Otherwise, assume interval is already a time interval and use it.
32289     if (typeof interval$$1 === "number") {
32290       var target = Math.abs(stop - start) / interval$$1,
32291           i = bisector(function(i) { return i[2]; }).right(tickIntervals, target);
32292       if (i === tickIntervals.length) {
32293         step = tickStep(start / durationYear, stop / durationYear, interval$$1);
32294         interval$$1 = year$$1;
32295       } else if (i) {
32296         i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
32297         step = i[1];
32298         interval$$1 = i[0];
32299       } else {
32300         step = tickStep(start, stop, interval$$1);
32301         interval$$1 = millisecond$$1;
32302       }
32303     }
32304
32305     return step == null ? interval$$1 : interval$$1.every(step);
32306   }
32307
32308   scale.invert = function(y) {
32309     return new Date(invert(y));
32310   };
32311
32312   scale.domain = function(_) {
32313     return arguments.length ? domain(map$3.call(_, number$2)) : domain().map(date$1);
32314   };
32315
32316   scale.ticks = function(interval$$1, step) {
32317     var d = domain(),
32318         t0 = d[0],
32319         t1 = d[d.length - 1],
32320         r = t1 < t0,
32321         t;
32322     if (r) t = t0, t0 = t1, t1 = t;
32323     t = tickInterval(interval$$1, t0, t1, step);
32324     t = t ? t.range(t0, t1 + 1) : []; // inclusive stop
32325     return r ? t.reverse() : t;
32326   };
32327
32328   scale.tickFormat = function(count, specifier) {
32329     return specifier == null ? tickFormat : format(specifier);
32330   };
32331
32332   scale.nice = function(interval$$1, step) {
32333     var d = domain();
32334     return (interval$$1 = tickInterval(interval$$1, d[0], d[d.length - 1], step))
32335         ? domain(nice(d, interval$$1))
32336         : scale;
32337   };
32338
32339   scale.copy = function() {
32340     return copy(scale, calendar(year$$1, month$$1, week, day$$1, hour$$1, minute$$1, second$$1, millisecond$$1, format));
32341   };
32342
32343   return scale;
32344 }
32345
32346 var time = function() {
32347   return calendar(year, month, sunday, day, hour, minute, second, millisecond, timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]);
32348 };
32349
32350 var utcTime = function() {
32351   return calendar(utcYear, utcMonth, utcSunday, utcDay, utcHour, utcMinute, second, millisecond, utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]);
32352 };
32353
32354 var colors = function(s) {
32355   return s.match(/.{6}/g).map(function(x) {
32356     return "#" + x;
32357   });
32358 };
32359
32360 var category10 = colors("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf");
32361
32362 var category20b = colors("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6");
32363
32364 var category20c = colors("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9");
32365
32366 var category20 = colors("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5");
32367
32368 var cubehelix$3 = cubehelixLong(cubehelix(300, 0.5, 0.0), cubehelix(-240, 0.5, 1.0));
32369
32370 var warm = cubehelixLong(cubehelix(-100, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
32371
32372 var cool = cubehelixLong(cubehelix(260, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
32373
32374 var rainbow = cubehelix();
32375
32376 var rainbow$1 = function(t) {
32377   if (t < 0 || t > 1) t -= Math.floor(t);
32378   var ts = Math.abs(t - 0.5);
32379   rainbow.h = 360 * t - 100;
32380   rainbow.s = 1.5 - 1.5 * ts;
32381   rainbow.l = 0.8 - 0.9 * ts;
32382   return rainbow + "";
32383 };
32384
32385 function ramp(range) {
32386   var n = range.length;
32387   return function(t) {
32388     return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))];
32389   };
32390 }
32391
32392 var viridis = ramp(colors("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));
32393
32394 var magma = ramp(colors("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf"));
32395
32396 var inferno = ramp(colors("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4"));
32397
32398 var plasma = ramp(colors("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));
32399
32400 function sequential(interpolator) {
32401   var x0 = 0,
32402       x1 = 1,
32403       clamp = false;
32404
32405   function scale(x) {
32406     var t = (x - x0) / (x1 - x0);
32407     return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t);
32408   }
32409
32410   scale.domain = function(_) {
32411     return arguments.length ? (x0 = +_[0], x1 = +_[1], scale) : [x0, x1];
32412   };
32413
32414   scale.clamp = function(_) {
32415     return arguments.length ? (clamp = !!_, scale) : clamp;
32416   };
32417
32418   scale.interpolator = function(_) {
32419     return arguments.length ? (interpolator = _, scale) : interpolator;
32420   };
32421
32422   scale.copy = function() {
32423     return sequential(interpolator).domain([x0, x1]).clamp(clamp);
32424   };
32425
32426   return linearish(scale);
32427 }
32428
32429 var constant$10 = function(x) {
32430   return function constant() {
32431     return x;
32432   };
32433 };
32434
32435 var abs$1 = Math.abs;
32436 var atan2$1 = Math.atan2;
32437 var cos$2 = Math.cos;
32438 var max$2 = Math.max;
32439 var min$1 = Math.min;
32440 var sin$2 = Math.sin;
32441 var sqrt$2 = Math.sqrt;
32442
32443 var epsilon$3 = 1e-12;
32444 var pi$4 = Math.PI;
32445 var halfPi$3 = pi$4 / 2;
32446 var tau$4 = 2 * pi$4;
32447
32448 function acos$1(x) {
32449   return x > 1 ? 0 : x < -1 ? pi$4 : Math.acos(x);
32450 }
32451
32452 function asin$1(x) {
32453   return x >= 1 ? halfPi$3 : x <= -1 ? -halfPi$3 : Math.asin(x);
32454 }
32455
32456 function arcInnerRadius(d) {
32457   return d.innerRadius;
32458 }
32459
32460 function arcOuterRadius(d) {
32461   return d.outerRadius;
32462 }
32463
32464 function arcStartAngle(d) {
32465   return d.startAngle;
32466 }
32467
32468 function arcEndAngle(d) {
32469   return d.endAngle;
32470 }
32471
32472 function arcPadAngle(d) {
32473   return d && d.padAngle; // Note: optional!
32474 }
32475
32476 function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
32477   var x10 = x1 - x0, y10 = y1 - y0,
32478       x32 = x3 - x2, y32 = y3 - y2,
32479       t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / (y32 * x10 - x32 * y10);
32480   return [x0 + t * x10, y0 + t * y10];
32481 }
32482
32483 // Compute perpendicular offset line of length rc.
32484 // http://mathworld.wolfram.com/Circle-LineIntersection.html
32485 function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
32486   var x01 = x0 - x1,
32487       y01 = y0 - y1,
32488       lo = (cw ? rc : -rc) / sqrt$2(x01 * x01 + y01 * y01),
32489       ox = lo * y01,
32490       oy = -lo * x01,
32491       x11 = x0 + ox,
32492       y11 = y0 + oy,
32493       x10 = x1 + ox,
32494       y10 = y1 + oy,
32495       x00 = (x11 + x10) / 2,
32496       y00 = (y11 + y10) / 2,
32497       dx = x10 - x11,
32498       dy = y10 - y11,
32499       d2 = dx * dx + dy * dy,
32500       r = r1 - rc,
32501       D = x11 * y10 - x10 * y11,
32502       d = (dy < 0 ? -1 : 1) * sqrt$2(max$2(0, r * r * d2 - D * D)),
32503       cx0 = (D * dy - dx * d) / d2,
32504       cy0 = (-D * dx - dy * d) / d2,
32505       cx1 = (D * dy + dx * d) / d2,
32506       cy1 = (-D * dx + dy * d) / d2,
32507       dx0 = cx0 - x00,
32508       dy0 = cy0 - y00,
32509       dx1 = cx1 - x00,
32510       dy1 = cy1 - y00;
32511
32512   // Pick the closer of the two intersection points.
32513   // TODO Is there a faster way to determine which intersection to use?
32514   if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
32515
32516   return {
32517     cx: cx0,
32518     cy: cy0,
32519     x01: -ox,
32520     y01: -oy,
32521     x11: cx0 * (r1 / r - 1),
32522     y11: cy0 * (r1 / r - 1)
32523   };
32524 }
32525
32526 var arc = function() {
32527   var innerRadius = arcInnerRadius,
32528       outerRadius = arcOuterRadius,
32529       cornerRadius = constant$10(0),
32530       padRadius = null,
32531       startAngle = arcStartAngle,
32532       endAngle = arcEndAngle,
32533       padAngle = arcPadAngle,
32534       context = null;
32535
32536   function arc() {
32537     var buffer,
32538         r,
32539         r0 = +innerRadius.apply(this, arguments),
32540         r1 = +outerRadius.apply(this, arguments),
32541         a0 = startAngle.apply(this, arguments) - halfPi$3,
32542         a1 = endAngle.apply(this, arguments) - halfPi$3,
32543         da = abs$1(a1 - a0),
32544         cw = a1 > a0;
32545
32546     if (!context) context = buffer = path();
32547
32548     // Ensure that the outer radius is always larger than the inner radius.
32549     if (r1 < r0) r = r1, r1 = r0, r0 = r;
32550
32551     // Is it a point?
32552     if (!(r1 > epsilon$3)) context.moveTo(0, 0);
32553
32554     // Or is it a circle or annulus?
32555     else if (da > tau$4 - epsilon$3) {
32556       context.moveTo(r1 * cos$2(a0), r1 * sin$2(a0));
32557       context.arc(0, 0, r1, a0, a1, !cw);
32558       if (r0 > epsilon$3) {
32559         context.moveTo(r0 * cos$2(a1), r0 * sin$2(a1));
32560         context.arc(0, 0, r0, a1, a0, cw);
32561       }
32562     }
32563
32564     // Or is it a circular or annular sector?
32565     else {
32566       var a01 = a0,
32567           a11 = a1,
32568           a00 = a0,
32569           a10 = a1,
32570           da0 = da,
32571           da1 = da,
32572           ap = padAngle.apply(this, arguments) / 2,
32573           rp = (ap > epsilon$3) && (padRadius ? +padRadius.apply(this, arguments) : sqrt$2(r0 * r0 + r1 * r1)),
32574           rc = min$1(abs$1(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
32575           rc0 = rc,
32576           rc1 = rc,
32577           t0,
32578           t1;
32579
32580       // Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
32581       if (rp > epsilon$3) {
32582         var p0 = asin$1(rp / r0 * sin$2(ap)),
32583             p1 = asin$1(rp / r1 * sin$2(ap));
32584         if ((da0 -= p0 * 2) > epsilon$3) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
32585         else da0 = 0, a00 = a10 = (a0 + a1) / 2;
32586         if ((da1 -= p1 * 2) > epsilon$3) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
32587         else da1 = 0, a01 = a11 = (a0 + a1) / 2;
32588       }
32589
32590       var x01 = r1 * cos$2(a01),
32591           y01 = r1 * sin$2(a01),
32592           x10 = r0 * cos$2(a10),
32593           y10 = r0 * sin$2(a10);
32594
32595       // Apply rounded corners?
32596       if (rc > epsilon$3) {
32597         var x11 = r1 * cos$2(a11),
32598             y11 = r1 * sin$2(a11),
32599             x00 = r0 * cos$2(a00),
32600             y00 = r0 * sin$2(a00);
32601
32602         // Restrict the corner radius according to the sector angle.
32603         if (da < pi$4) {
32604           var oc = da0 > epsilon$3 ? intersect(x01, y01, x00, y00, x11, y11, x10, y10) : [x10, y10],
32605               ax = x01 - oc[0],
32606               ay = y01 - oc[1],
32607               bx = x11 - oc[0],
32608               by = y11 - oc[1],
32609               kc = 1 / sin$2(acos$1((ax * bx + ay * by) / (sqrt$2(ax * ax + ay * ay) * sqrt$2(bx * bx + by * by))) / 2),
32610               lc = sqrt$2(oc[0] * oc[0] + oc[1] * oc[1]);
32611           rc0 = min$1(rc, (r0 - lc) / (kc - 1));
32612           rc1 = min$1(rc, (r1 - lc) / (kc + 1));
32613         }
32614       }
32615
32616       // Is the sector collapsed to a line?
32617       if (!(da1 > epsilon$3)) context.moveTo(x01, y01);
32618
32619       // Does the sector’s outer ring have rounded corners?
32620       else if (rc1 > epsilon$3) {
32621         t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
32622         t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
32623
32624         context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
32625
32626         // Have the corners merged?
32627         if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, atan2$1(t0.y01, t0.x01), atan2$1(t1.y01, t1.x01), !cw);
32628
32629         // Otherwise, draw the two corners and the ring.
32630         else {
32631           context.arc(t0.cx, t0.cy, rc1, atan2$1(t0.y01, t0.x01), atan2$1(t0.y11, t0.x11), !cw);
32632           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);
32633           context.arc(t1.cx, t1.cy, rc1, atan2$1(t1.y11, t1.x11), atan2$1(t1.y01, t1.x01), !cw);
32634         }
32635       }
32636
32637       // Or is the outer ring just a circular arc?
32638       else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
32639
32640       // Is there no inner ring, and it’s a circular sector?
32641       // Or perhaps it’s an annular sector collapsed due to padding?
32642       if (!(r0 > epsilon$3) || !(da0 > epsilon$3)) context.lineTo(x10, y10);
32643
32644       // Does the sector’s inner ring (or point) have rounded corners?
32645       else if (rc0 > epsilon$3) {
32646         t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
32647         t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
32648
32649         context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
32650
32651         // Have the corners merged?
32652         if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, atan2$1(t0.y01, t0.x01), atan2$1(t1.y01, t1.x01), !cw);
32653
32654         // Otherwise, draw the two corners and the ring.
32655         else {
32656           context.arc(t0.cx, t0.cy, rc0, atan2$1(t0.y01, t0.x01), atan2$1(t0.y11, t0.x11), !cw);
32657           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);
32658           context.arc(t1.cx, t1.cy, rc0, atan2$1(t1.y11, t1.x11), atan2$1(t1.y01, t1.x01), !cw);
32659         }
32660       }
32661
32662       // Or is the inner ring just a circular arc?
32663       else context.arc(0, 0, r0, a10, a00, cw);
32664     }
32665
32666     context.closePath();
32667
32668     if (buffer) return context = null, buffer + "" || null;
32669   }
32670
32671   arc.centroid = function() {
32672     var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
32673         a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi$4 / 2;
32674     return [cos$2(a) * r, sin$2(a) * r];
32675   };
32676
32677   arc.innerRadius = function(_) {
32678     return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : innerRadius;
32679   };
32680
32681   arc.outerRadius = function(_) {
32682     return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : outerRadius;
32683   };
32684
32685   arc.cornerRadius = function(_) {
32686     return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant$10(+_), arc) : cornerRadius;
32687   };
32688
32689   arc.padRadius = function(_) {
32690     return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), arc) : padRadius;
32691   };
32692
32693   arc.startAngle = function(_) {
32694     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : startAngle;
32695   };
32696
32697   arc.endAngle = function(_) {
32698     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : endAngle;
32699   };
32700
32701   arc.padAngle = function(_) {
32702     return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$10(+_), arc) : padAngle;
32703   };
32704
32705   arc.context = function(_) {
32706     return arguments.length ? ((context = _ == null ? null : _), arc) : context;
32707   };
32708
32709   return arc;
32710 };
32711
32712 function Linear(context) {
32713   this._context = context;
32714 }
32715
32716 Linear.prototype = {
32717   areaStart: function() {
32718     this._line = 0;
32719   },
32720   areaEnd: function() {
32721     this._line = NaN;
32722   },
32723   lineStart: function() {
32724     this._point = 0;
32725   },
32726   lineEnd: function() {
32727     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
32728     this._line = 1 - this._line;
32729   },
32730   point: function(x, y) {
32731     x = +x, y = +y;
32732     switch (this._point) {
32733       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
32734       case 1: this._point = 2; // proceed
32735       default: this._context.lineTo(x, y); break;
32736     }
32737   }
32738 };
32739
32740 var curveLinear = function(context) {
32741   return new Linear(context);
32742 };
32743
32744 function x$3(p) {
32745   return p[0];
32746 }
32747
32748 function y$3(p) {
32749   return p[1];
32750 }
32751
32752 var line = function() {
32753   var x = x$3,
32754       y = y$3,
32755       defined = constant$10(true),
32756       context = null,
32757       curve = curveLinear,
32758       output = null;
32759
32760   function line(data) {
32761     var i,
32762         n = data.length,
32763         d,
32764         defined0 = false,
32765         buffer;
32766
32767     if (context == null) output = curve(buffer = path());
32768
32769     for (i = 0; i <= n; ++i) {
32770       if (!(i < n && defined(d = data[i], i, data)) === defined0) {
32771         if (defined0 = !defined0) output.lineStart();
32772         else output.lineEnd();
32773       }
32774       if (defined0) output.point(+x(d, i, data), +y(d, i, data));
32775     }
32776
32777     if (buffer) return output = null, buffer + "" || null;
32778   }
32779
32780   line.x = function(_) {
32781     return arguments.length ? (x = typeof _ === "function" ? _ : constant$10(+_), line) : x;
32782   };
32783
32784   line.y = function(_) {
32785     return arguments.length ? (y = typeof _ === "function" ? _ : constant$10(+_), line) : y;
32786   };
32787
32788   line.defined = function(_) {
32789     return arguments.length ? (defined = typeof _ === "function" ? _ : constant$10(!!_), line) : defined;
32790   };
32791
32792   line.curve = function(_) {
32793     return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;
32794   };
32795
32796   line.context = function(_) {
32797     return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;
32798   };
32799
32800   return line;
32801 };
32802
32803 var area$1 = function() {
32804   var x0 = x$3,
32805       x1 = null,
32806       y0 = constant$10(0),
32807       y1 = y$3,
32808       defined = constant$10(true),
32809       context = null,
32810       curve = curveLinear,
32811       output = null;
32812
32813   function area(data) {
32814     var i,
32815         j,
32816         k,
32817         n = data.length,
32818         d,
32819         defined0 = false,
32820         buffer,
32821         x0z = new Array(n),
32822         y0z = new Array(n);
32823
32824     if (context == null) output = curve(buffer = path());
32825
32826     for (i = 0; i <= n; ++i) {
32827       if (!(i < n && defined(d = data[i], i, data)) === defined0) {
32828         if (defined0 = !defined0) {
32829           j = i;
32830           output.areaStart();
32831           output.lineStart();
32832         } else {
32833           output.lineEnd();
32834           output.lineStart();
32835           for (k = i - 1; k >= j; --k) {
32836             output.point(x0z[k], y0z[k]);
32837           }
32838           output.lineEnd();
32839           output.areaEnd();
32840         }
32841       }
32842       if (defined0) {
32843         x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);
32844         output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);
32845       }
32846     }
32847
32848     if (buffer) return output = null, buffer + "" || null;
32849   }
32850
32851   function arealine() {
32852     return line().defined(defined).curve(curve).context(context);
32853   }
32854
32855   area.x = function(_) {
32856     return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$10(+_), x1 = null, area) : x0;
32857   };
32858
32859   area.x0 = function(_) {
32860     return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$10(+_), area) : x0;
32861   };
32862
32863   area.x1 = function(_) {
32864     return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), area) : x1;
32865   };
32866
32867   area.y = function(_) {
32868     return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$10(+_), y1 = null, area) : y0;
32869   };
32870
32871   area.y0 = function(_) {
32872     return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$10(+_), area) : y0;
32873   };
32874
32875   area.y1 = function(_) {
32876     return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant$10(+_), area) : y1;
32877   };
32878
32879   area.lineX0 =
32880   area.lineY0 = function() {
32881     return arealine().x(x0).y(y0);
32882   };
32883
32884   area.lineY1 = function() {
32885     return arealine().x(x0).y(y1);
32886   };
32887
32888   area.lineX1 = function() {
32889     return arealine().x(x1).y(y0);
32890   };
32891
32892   area.defined = function(_) {
32893     return arguments.length ? (defined = typeof _ === "function" ? _ : constant$10(!!_), area) : defined;
32894   };
32895
32896   area.curve = function(_) {
32897     return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;
32898   };
32899
32900   area.context = function(_) {
32901     return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;
32902   };
32903
32904   return area;
32905 };
32906
32907 var descending$1 = function(a, b) {
32908   return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
32909 };
32910
32911 var identity$7 = function(d) {
32912   return d;
32913 };
32914
32915 var pie = function() {
32916   var value = identity$7,
32917       sortValues = descending$1,
32918       sort = null,
32919       startAngle = constant$10(0),
32920       endAngle = constant$10(tau$4),
32921       padAngle = constant$10(0);
32922
32923   function pie(data) {
32924     var i,
32925         n = data.length,
32926         j,
32927         k,
32928         sum = 0,
32929         index = new Array(n),
32930         arcs = new Array(n),
32931         a0 = +startAngle.apply(this, arguments),
32932         da = Math.min(tau$4, Math.max(-tau$4, endAngle.apply(this, arguments) - a0)),
32933         a1,
32934         p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)),
32935         pa = p * (da < 0 ? -1 : 1),
32936         v;
32937
32938     for (i = 0; i < n; ++i) {
32939       if ((v = arcs[index[i] = i] = +value(data[i], i, data)) > 0) {
32940         sum += v;
32941       }
32942     }
32943
32944     // Optionally sort the arcs by previously-computed values or by data.
32945     if (sortValues != null) index.sort(function(i, j) { return sortValues(arcs[i], arcs[j]); });
32946     else if (sort != null) index.sort(function(i, j) { return sort(data[i], data[j]); });
32947
32948     // Compute the arcs! They are stored in the original data's order.
32949     for (i = 0, k = sum ? (da - n * pa) / sum : 0; i < n; ++i, a0 = a1) {
32950       j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
32951         data: data[j],
32952         index: i,
32953         value: v,
32954         startAngle: a0,
32955         endAngle: a1,
32956         padAngle: p
32957       };
32958     }
32959
32960     return arcs;
32961   }
32962
32963   pie.value = function(_) {
32964     return arguments.length ? (value = typeof _ === "function" ? _ : constant$10(+_), pie) : value;
32965   };
32966
32967   pie.sortValues = function(_) {
32968     return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
32969   };
32970
32971   pie.sort = function(_) {
32972     return arguments.length ? (sort = _, sortValues = null, pie) : sort;
32973   };
32974
32975   pie.startAngle = function(_) {
32976     return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : startAngle;
32977   };
32978
32979   pie.endAngle = function(_) {
32980     return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : endAngle;
32981   };
32982
32983   pie.padAngle = function(_) {
32984     return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$10(+_), pie) : padAngle;
32985   };
32986
32987   return pie;
32988 };
32989
32990 var curveRadialLinear = curveRadial(curveLinear);
32991
32992 function Radial(curve) {
32993   this._curve = curve;
32994 }
32995
32996 Radial.prototype = {
32997   areaStart: function() {
32998     this._curve.areaStart();
32999   },
33000   areaEnd: function() {
33001     this._curve.areaEnd();
33002   },
33003   lineStart: function() {
33004     this._curve.lineStart();
33005   },
33006   lineEnd: function() {
33007     this._curve.lineEnd();
33008   },
33009   point: function(a, r) {
33010     this._curve.point(r * Math.sin(a), r * -Math.cos(a));
33011   }
33012 };
33013
33014 function curveRadial(curve) {
33015
33016   function radial(context) {
33017     return new Radial(curve(context));
33018   }
33019
33020   radial._curve = curve;
33021
33022   return radial;
33023 }
33024
33025 function radialLine(l) {
33026   var c = l.curve;
33027
33028   l.angle = l.x, delete l.x;
33029   l.radius = l.y, delete l.y;
33030
33031   l.curve = function(_) {
33032     return arguments.length ? c(curveRadial(_)) : c()._curve;
33033   };
33034
33035   return l;
33036 }
33037
33038 var radialLine$1 = function() {
33039   return radialLine(line().curve(curveRadialLinear));
33040 };
33041
33042 var radialArea = function() {
33043   var a = area$1().curve(curveRadialLinear),
33044       c = a.curve,
33045       x0 = a.lineX0,
33046       x1 = a.lineX1,
33047       y0 = a.lineY0,
33048       y1 = a.lineY1;
33049
33050   a.angle = a.x, delete a.x;
33051   a.startAngle = a.x0, delete a.x0;
33052   a.endAngle = a.x1, delete a.x1;
33053   a.radius = a.y, delete a.y;
33054   a.innerRadius = a.y0, delete a.y0;
33055   a.outerRadius = a.y1, delete a.y1;
33056   a.lineStartAngle = function() { return radialLine(x0()); }, delete a.lineX0;
33057   a.lineEndAngle = function() { return radialLine(x1()); }, delete a.lineX1;
33058   a.lineInnerRadius = function() { return radialLine(y0()); }, delete a.lineY0;
33059   a.lineOuterRadius = function() { return radialLine(y1()); }, delete a.lineY1;
33060
33061   a.curve = function(_) {
33062     return arguments.length ? c(curveRadial(_)) : c()._curve;
33063   };
33064
33065   return a;
33066 };
33067
33068 var slice$5 = Array.prototype.slice;
33069
33070 var radialPoint = function(x, y) {
33071   return [(y = +y) * Math.cos(x -= Math.PI / 2), y * Math.sin(x)];
33072 };
33073
33074 function linkSource(d) {
33075   return d.source;
33076 }
33077
33078 function linkTarget(d) {
33079   return d.target;
33080 }
33081
33082 function link$2(curve) {
33083   var source = linkSource,
33084       target = linkTarget,
33085       x = x$3,
33086       y = y$3,
33087       context = null;
33088
33089   function link() {
33090     var buffer, argv = slice$5.call(arguments), s = source.apply(this, argv), t = target.apply(this, argv);
33091     if (!context) context = buffer = path();
33092     curve(context, +x.apply(this, (argv[0] = s, argv)), +y.apply(this, argv), +x.apply(this, (argv[0] = t, argv)), +y.apply(this, argv));
33093     if (buffer) return context = null, buffer + "" || null;
33094   }
33095
33096   link.source = function(_) {
33097     return arguments.length ? (source = _, link) : source;
33098   };
33099
33100   link.target = function(_) {
33101     return arguments.length ? (target = _, link) : target;
33102   };
33103
33104   link.x = function(_) {
33105     return arguments.length ? (x = typeof _ === "function" ? _ : constant$10(+_), link) : x;
33106   };
33107
33108   link.y = function(_) {
33109     return arguments.length ? (y = typeof _ === "function" ? _ : constant$10(+_), link) : y;
33110   };
33111
33112   link.context = function(_) {
33113     return arguments.length ? ((context = _ == null ? null : _), link) : context;
33114   };
33115
33116   return link;
33117 }
33118
33119 function curveHorizontal(context, x0, y0, x1, y1) {
33120   context.moveTo(x0, y0);
33121   context.bezierCurveTo(x0 = (x0 + x1) / 2, y0, x0, y1, x1, y1);
33122 }
33123
33124 function curveVertical(context, x0, y0, x1, y1) {
33125   context.moveTo(x0, y0);
33126   context.bezierCurveTo(x0, y0 = (y0 + y1) / 2, x1, y0, x1, y1);
33127 }
33128
33129 function curveRadial$1(context, x0, y0, x1, y1) {
33130   var p0 = radialPoint(x0, y0),
33131       p1 = radialPoint(x0, y0 = (y0 + y1) / 2),
33132       p2 = radialPoint(x1, y0),
33133       p3 = radialPoint(x1, y1);
33134   context.moveTo(p0[0], p0[1]);
33135   context.bezierCurveTo(p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]);
33136 }
33137
33138 function linkHorizontal() {
33139   return link$2(curveHorizontal);
33140 }
33141
33142 function linkVertical() {
33143   return link$2(curveVertical);
33144 }
33145
33146 function linkRadial() {
33147   var l = link$2(curveRadial$1);
33148   l.angle = l.x, delete l.x;
33149   l.radius = l.y, delete l.y;
33150   return l;
33151 }
33152
33153 var circle$2 = {
33154   draw: function(context, size) {
33155     var r = Math.sqrt(size / pi$4);
33156     context.moveTo(r, 0);
33157     context.arc(0, 0, r, 0, tau$4);
33158   }
33159 };
33160
33161 var cross$2 = {
33162   draw: function(context, size) {
33163     var r = Math.sqrt(size / 5) / 2;
33164     context.moveTo(-3 * r, -r);
33165     context.lineTo(-r, -r);
33166     context.lineTo(-r, -3 * r);
33167     context.lineTo(r, -3 * r);
33168     context.lineTo(r, -r);
33169     context.lineTo(3 * r, -r);
33170     context.lineTo(3 * r, r);
33171     context.lineTo(r, r);
33172     context.lineTo(r, 3 * r);
33173     context.lineTo(-r, 3 * r);
33174     context.lineTo(-r, r);
33175     context.lineTo(-3 * r, r);
33176     context.closePath();
33177   }
33178 };
33179
33180 var tan30 = Math.sqrt(1 / 3);
33181 var tan30_2 = tan30 * 2;
33182
33183 var diamond = {
33184   draw: function(context, size) {
33185     var y = Math.sqrt(size / tan30_2),
33186         x = y * tan30;
33187     context.moveTo(0, -y);
33188     context.lineTo(x, 0);
33189     context.lineTo(0, y);
33190     context.lineTo(-x, 0);
33191     context.closePath();
33192   }
33193 };
33194
33195 var ka = 0.89081309152928522810;
33196 var kr = Math.sin(pi$4 / 10) / Math.sin(7 * pi$4 / 10);
33197 var kx = Math.sin(tau$4 / 10) * kr;
33198 var ky = -Math.cos(tau$4 / 10) * kr;
33199
33200 var star = {
33201   draw: function(context, size) {
33202     var r = Math.sqrt(size * ka),
33203         x = kx * r,
33204         y = ky * r;
33205     context.moveTo(0, -r);
33206     context.lineTo(x, y);
33207     for (var i = 1; i < 5; ++i) {
33208       var a = tau$4 * i / 5,
33209           c = Math.cos(a),
33210           s = Math.sin(a);
33211       context.lineTo(s * r, -c * r);
33212       context.lineTo(c * x - s * y, s * x + c * y);
33213     }
33214     context.closePath();
33215   }
33216 };
33217
33218 var square = {
33219   draw: function(context, size) {
33220     var w = Math.sqrt(size),
33221         x = -w / 2;
33222     context.rect(x, x, w, w);
33223   }
33224 };
33225
33226 var sqrt3 = Math.sqrt(3);
33227
33228 var triangle = {
33229   draw: function(context, size) {
33230     var y = -Math.sqrt(size / (sqrt3 * 3));
33231     context.moveTo(0, y * 2);
33232     context.lineTo(-sqrt3 * y, -y);
33233     context.lineTo(sqrt3 * y, -y);
33234     context.closePath();
33235   }
33236 };
33237
33238 var c = -0.5;
33239 var s = Math.sqrt(3) / 2;
33240 var k = 1 / Math.sqrt(12);
33241 var a = (k / 2 + 1) * 3;
33242
33243 var wye = {
33244   draw: function(context, size) {
33245     var r = Math.sqrt(size / a),
33246         x0 = r / 2,
33247         y0 = r * k,
33248         x1 = x0,
33249         y1 = r * k + r,
33250         x2 = -x1,
33251         y2 = y1;
33252     context.moveTo(x0, y0);
33253     context.lineTo(x1, y1);
33254     context.lineTo(x2, y2);
33255     context.lineTo(c * x0 - s * y0, s * x0 + c * y0);
33256     context.lineTo(c * x1 - s * y1, s * x1 + c * y1);
33257     context.lineTo(c * x2 - s * y2, s * x2 + c * y2);
33258     context.lineTo(c * x0 + s * y0, c * y0 - s * x0);
33259     context.lineTo(c * x1 + s * y1, c * y1 - s * x1);
33260     context.lineTo(c * x2 + s * y2, c * y2 - s * x2);
33261     context.closePath();
33262   }
33263 };
33264
33265 var symbols = [
33266   circle$2,
33267   cross$2,
33268   diamond,
33269   square,
33270   star,
33271   triangle,
33272   wye
33273 ];
33274
33275 var symbol = function() {
33276   var type = constant$10(circle$2),
33277       size = constant$10(64),
33278       context = null;
33279
33280   function symbol() {
33281     var buffer;
33282     if (!context) context = buffer = path();
33283     type.apply(this, arguments).draw(context, +size.apply(this, arguments));
33284     if (buffer) return context = null, buffer + "" || null;
33285   }
33286
33287   symbol.type = function(_) {
33288     return arguments.length ? (type = typeof _ === "function" ? _ : constant$10(_), symbol) : type;
33289   };
33290
33291   symbol.size = function(_) {
33292     return arguments.length ? (size = typeof _ === "function" ? _ : constant$10(+_), symbol) : size;
33293   };
33294
33295   symbol.context = function(_) {
33296     return arguments.length ? (context = _ == null ? null : _, symbol) : context;
33297   };
33298
33299   return symbol;
33300 };
33301
33302 var noop$2 = function() {};
33303
33304 function point$2(that, x, y) {
33305   that._context.bezierCurveTo(
33306     (2 * that._x0 + that._x1) / 3,
33307     (2 * that._y0 + that._y1) / 3,
33308     (that._x0 + 2 * that._x1) / 3,
33309     (that._y0 + 2 * that._y1) / 3,
33310     (that._x0 + 4 * that._x1 + x) / 6,
33311     (that._y0 + 4 * that._y1 + y) / 6
33312   );
33313 }
33314
33315 function Basis(context) {
33316   this._context = context;
33317 }
33318
33319 Basis.prototype = {
33320   areaStart: function() {
33321     this._line = 0;
33322   },
33323   areaEnd: function() {
33324     this._line = NaN;
33325   },
33326   lineStart: function() {
33327     this._x0 = this._x1 =
33328     this._y0 = this._y1 = NaN;
33329     this._point = 0;
33330   },
33331   lineEnd: function() {
33332     switch (this._point) {
33333       case 3: point$2(this, this._x1, this._y1); // proceed
33334       case 2: this._context.lineTo(this._x1, this._y1); break;
33335     }
33336     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33337     this._line = 1 - this._line;
33338   },
33339   point: function(x, y) {
33340     x = +x, y = +y;
33341     switch (this._point) {
33342       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33343       case 1: this._point = 2; break;
33344       case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed
33345       default: point$2(this, x, y); break;
33346     }
33347     this._x0 = this._x1, this._x1 = x;
33348     this._y0 = this._y1, this._y1 = y;
33349   }
33350 };
33351
33352 var basis$2 = function(context) {
33353   return new Basis(context);
33354 };
33355
33356 function BasisClosed(context) {
33357   this._context = context;
33358 }
33359
33360 BasisClosed.prototype = {
33361   areaStart: noop$2,
33362   areaEnd: noop$2,
33363   lineStart: function() {
33364     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =
33365     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;
33366     this._point = 0;
33367   },
33368   lineEnd: function() {
33369     switch (this._point) {
33370       case 1: {
33371         this._context.moveTo(this._x2, this._y2);
33372         this._context.closePath();
33373         break;
33374       }
33375       case 2: {
33376         this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);
33377         this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);
33378         this._context.closePath();
33379         break;
33380       }
33381       case 3: {
33382         this.point(this._x2, this._y2);
33383         this.point(this._x3, this._y3);
33384         this.point(this._x4, this._y4);
33385         break;
33386       }
33387     }
33388   },
33389   point: function(x, y) {
33390     x = +x, y = +y;
33391     switch (this._point) {
33392       case 0: this._point = 1; this._x2 = x, this._y2 = y; break;
33393       case 1: this._point = 2; this._x3 = x, this._y3 = y; break;
33394       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;
33395       default: point$2(this, x, y); break;
33396     }
33397     this._x0 = this._x1, this._x1 = x;
33398     this._y0 = this._y1, this._y1 = y;
33399   }
33400 };
33401
33402 var basisClosed$1 = function(context) {
33403   return new BasisClosed(context);
33404 };
33405
33406 function BasisOpen(context) {
33407   this._context = context;
33408 }
33409
33410 BasisOpen.prototype = {
33411   areaStart: function() {
33412     this._line = 0;
33413   },
33414   areaEnd: function() {
33415     this._line = NaN;
33416   },
33417   lineStart: function() {
33418     this._x0 = this._x1 =
33419     this._y0 = this._y1 = NaN;
33420     this._point = 0;
33421   },
33422   lineEnd: function() {
33423     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33424     this._line = 1 - this._line;
33425   },
33426   point: function(x, y) {
33427     x = +x, y = +y;
33428     switch (this._point) {
33429       case 0: this._point = 1; break;
33430       case 1: this._point = 2; break;
33431       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;
33432       case 3: this._point = 4; // proceed
33433       default: point$2(this, x, y); break;
33434     }
33435     this._x0 = this._x1, this._x1 = x;
33436     this._y0 = this._y1, this._y1 = y;
33437   }
33438 };
33439
33440 var basisOpen = function(context) {
33441   return new BasisOpen(context);
33442 };
33443
33444 function Bundle(context, beta) {
33445   this._basis = new Basis(context);
33446   this._beta = beta;
33447 }
33448
33449 Bundle.prototype = {
33450   lineStart: function() {
33451     this._x = [];
33452     this._y = [];
33453     this._basis.lineStart();
33454   },
33455   lineEnd: function() {
33456     var x = this._x,
33457         y = this._y,
33458         j = x.length - 1;
33459
33460     if (j > 0) {
33461       var x0 = x[0],
33462           y0 = y[0],
33463           dx = x[j] - x0,
33464           dy = y[j] - y0,
33465           i = -1,
33466           t;
33467
33468       while (++i <= j) {
33469         t = i / j;
33470         this._basis.point(
33471           this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),
33472           this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)
33473         );
33474       }
33475     }
33476
33477     this._x = this._y = null;
33478     this._basis.lineEnd();
33479   },
33480   point: function(x, y) {
33481     this._x.push(+x);
33482     this._y.push(+y);
33483   }
33484 };
33485
33486 var bundle = ((function custom(beta) {
33487
33488   function bundle(context) {
33489     return beta === 1 ? new Basis(context) : new Bundle(context, beta);
33490   }
33491
33492   bundle.beta = function(beta) {
33493     return custom(+beta);
33494   };
33495
33496   return bundle;
33497 }))(0.85);
33498
33499 function point$3(that, x, y) {
33500   that._context.bezierCurveTo(
33501     that._x1 + that._k * (that._x2 - that._x0),
33502     that._y1 + that._k * (that._y2 - that._y0),
33503     that._x2 + that._k * (that._x1 - x),
33504     that._y2 + that._k * (that._y1 - y),
33505     that._x2,
33506     that._y2
33507   );
33508 }
33509
33510 function Cardinal(context, tension) {
33511   this._context = context;
33512   this._k = (1 - tension) / 6;
33513 }
33514
33515 Cardinal.prototype = {
33516   areaStart: function() {
33517     this._line = 0;
33518   },
33519   areaEnd: function() {
33520     this._line = NaN;
33521   },
33522   lineStart: function() {
33523     this._x0 = this._x1 = this._x2 =
33524     this._y0 = this._y1 = this._y2 = NaN;
33525     this._point = 0;
33526   },
33527   lineEnd: function() {
33528     switch (this._point) {
33529       case 2: this._context.lineTo(this._x2, this._y2); break;
33530       case 3: point$3(this, this._x1, this._y1); break;
33531     }
33532     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33533     this._line = 1 - this._line;
33534   },
33535   point: function(x, y) {
33536     x = +x, y = +y;
33537     switch (this._point) {
33538       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33539       case 1: this._point = 2; this._x1 = x, this._y1 = y; break;
33540       case 2: this._point = 3; // proceed
33541       default: point$3(this, x, y); break;
33542     }
33543     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33544     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33545   }
33546 };
33547
33548 var cardinal = ((function custom(tension) {
33549
33550   function cardinal(context) {
33551     return new Cardinal(context, tension);
33552   }
33553
33554   cardinal.tension = function(tension) {
33555     return custom(+tension);
33556   };
33557
33558   return cardinal;
33559 }))(0);
33560
33561 function CardinalClosed(context, tension) {
33562   this._context = context;
33563   this._k = (1 - tension) / 6;
33564 }
33565
33566 CardinalClosed.prototype = {
33567   areaStart: noop$2,
33568   areaEnd: noop$2,
33569   lineStart: function() {
33570     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
33571     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
33572     this._point = 0;
33573   },
33574   lineEnd: function() {
33575     switch (this._point) {
33576       case 1: {
33577         this._context.moveTo(this._x3, this._y3);
33578         this._context.closePath();
33579         break;
33580       }
33581       case 2: {
33582         this._context.lineTo(this._x3, this._y3);
33583         this._context.closePath();
33584         break;
33585       }
33586       case 3: {
33587         this.point(this._x3, this._y3);
33588         this.point(this._x4, this._y4);
33589         this.point(this._x5, this._y5);
33590         break;
33591       }
33592     }
33593   },
33594   point: function(x, y) {
33595     x = +x, y = +y;
33596     switch (this._point) {
33597       case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
33598       case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
33599       case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
33600       default: point$3(this, x, y); break;
33601     }
33602     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33603     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33604   }
33605 };
33606
33607 var cardinalClosed = ((function custom(tension) {
33608
33609   function cardinal$$1(context) {
33610     return new CardinalClosed(context, tension);
33611   }
33612
33613   cardinal$$1.tension = function(tension) {
33614     return custom(+tension);
33615   };
33616
33617   return cardinal$$1;
33618 }))(0);
33619
33620 function CardinalOpen(context, tension) {
33621   this._context = context;
33622   this._k = (1 - tension) / 6;
33623 }
33624
33625 CardinalOpen.prototype = {
33626   areaStart: function() {
33627     this._line = 0;
33628   },
33629   areaEnd: function() {
33630     this._line = NaN;
33631   },
33632   lineStart: function() {
33633     this._x0 = this._x1 = this._x2 =
33634     this._y0 = this._y1 = this._y2 = NaN;
33635     this._point = 0;
33636   },
33637   lineEnd: function() {
33638     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33639     this._line = 1 - this._line;
33640   },
33641   point: function(x, y) {
33642     x = +x, y = +y;
33643     switch (this._point) {
33644       case 0: this._point = 1; break;
33645       case 1: this._point = 2; break;
33646       case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
33647       case 3: this._point = 4; // proceed
33648       default: point$3(this, x, y); break;
33649     }
33650     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33651     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33652   }
33653 };
33654
33655 var cardinalOpen = ((function custom(tension) {
33656
33657   function cardinal$$1(context) {
33658     return new CardinalOpen(context, tension);
33659   }
33660
33661   cardinal$$1.tension = function(tension) {
33662     return custom(+tension);
33663   };
33664
33665   return cardinal$$1;
33666 }))(0);
33667
33668 function point$4(that, x, y) {
33669   var x1 = that._x1,
33670       y1 = that._y1,
33671       x2 = that._x2,
33672       y2 = that._y2;
33673
33674   if (that._l01_a > epsilon$3) {
33675     var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,
33676         n = 3 * that._l01_a * (that._l01_a + that._l12_a);
33677     x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;
33678     y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;
33679   }
33680
33681   if (that._l23_a > epsilon$3) {
33682     var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,
33683         m = 3 * that._l23_a * (that._l23_a + that._l12_a);
33684     x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;
33685     y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;
33686   }
33687
33688   that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);
33689 }
33690
33691 function CatmullRom(context, alpha) {
33692   this._context = context;
33693   this._alpha = alpha;
33694 }
33695
33696 CatmullRom.prototype = {
33697   areaStart: function() {
33698     this._line = 0;
33699   },
33700   areaEnd: function() {
33701     this._line = NaN;
33702   },
33703   lineStart: function() {
33704     this._x0 = this._x1 = this._x2 =
33705     this._y0 = this._y1 = this._y2 = NaN;
33706     this._l01_a = this._l12_a = this._l23_a =
33707     this._l01_2a = this._l12_2a = this._l23_2a =
33708     this._point = 0;
33709   },
33710   lineEnd: function() {
33711     switch (this._point) {
33712       case 2: this._context.lineTo(this._x2, this._y2); break;
33713       case 3: this.point(this._x2, this._y2); break;
33714     }
33715     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33716     this._line = 1 - this._line;
33717   },
33718   point: function(x, y) {
33719     x = +x, y = +y;
33720
33721     if (this._point) {
33722       var x23 = this._x2 - x,
33723           y23 = this._y2 - y;
33724       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33725     }
33726
33727     switch (this._point) {
33728       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33729       case 1: this._point = 2; break;
33730       case 2: this._point = 3; // proceed
33731       default: point$4(this, x, y); break;
33732     }
33733
33734     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33735     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33736     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33737     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33738   }
33739 };
33740
33741 var catmullRom = ((function custom(alpha) {
33742
33743   function catmullRom(context) {
33744     return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0);
33745   }
33746
33747   catmullRom.alpha = function(alpha) {
33748     return custom(+alpha);
33749   };
33750
33751   return catmullRom;
33752 }))(0.5);
33753
33754 function CatmullRomClosed(context, alpha) {
33755   this._context = context;
33756   this._alpha = alpha;
33757 }
33758
33759 CatmullRomClosed.prototype = {
33760   areaStart: noop$2,
33761   areaEnd: noop$2,
33762   lineStart: function() {
33763     this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
33764     this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
33765     this._l01_a = this._l12_a = this._l23_a =
33766     this._l01_2a = this._l12_2a = this._l23_2a =
33767     this._point = 0;
33768   },
33769   lineEnd: function() {
33770     switch (this._point) {
33771       case 1: {
33772         this._context.moveTo(this._x3, this._y3);
33773         this._context.closePath();
33774         break;
33775       }
33776       case 2: {
33777         this._context.lineTo(this._x3, this._y3);
33778         this._context.closePath();
33779         break;
33780       }
33781       case 3: {
33782         this.point(this._x3, this._y3);
33783         this.point(this._x4, this._y4);
33784         this.point(this._x5, this._y5);
33785         break;
33786       }
33787     }
33788   },
33789   point: function(x, y) {
33790     x = +x, y = +y;
33791
33792     if (this._point) {
33793       var x23 = this._x2 - x,
33794           y23 = this._y2 - y;
33795       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33796     }
33797
33798     switch (this._point) {
33799       case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
33800       case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
33801       case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
33802       default: point$4(this, x, y); break;
33803     }
33804
33805     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33806     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33807     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33808     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33809   }
33810 };
33811
33812 var catmullRomClosed = ((function custom(alpha) {
33813
33814   function catmullRom$$1(context) {
33815     return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0);
33816   }
33817
33818   catmullRom$$1.alpha = function(alpha) {
33819     return custom(+alpha);
33820   };
33821
33822   return catmullRom$$1;
33823 }))(0.5);
33824
33825 function CatmullRomOpen(context, alpha) {
33826   this._context = context;
33827   this._alpha = alpha;
33828 }
33829
33830 CatmullRomOpen.prototype = {
33831   areaStart: function() {
33832     this._line = 0;
33833   },
33834   areaEnd: function() {
33835     this._line = NaN;
33836   },
33837   lineStart: function() {
33838     this._x0 = this._x1 = this._x2 =
33839     this._y0 = this._y1 = this._y2 = NaN;
33840     this._l01_a = this._l12_a = this._l23_a =
33841     this._l01_2a = this._l12_2a = this._l23_2a =
33842     this._point = 0;
33843   },
33844   lineEnd: function() {
33845     if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
33846     this._line = 1 - this._line;
33847   },
33848   point: function(x, y) {
33849     x = +x, y = +y;
33850
33851     if (this._point) {
33852       var x23 = this._x2 - x,
33853           y23 = this._y2 - y;
33854       this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
33855     }
33856
33857     switch (this._point) {
33858       case 0: this._point = 1; break;
33859       case 1: this._point = 2; break;
33860       case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
33861       case 3: this._point = 4; // proceed
33862       default: point$4(this, x, y); break;
33863     }
33864
33865     this._l01_a = this._l12_a, this._l12_a = this._l23_a;
33866     this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
33867     this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
33868     this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
33869   }
33870 };
33871
33872 var catmullRomOpen = ((function custom(alpha) {
33873
33874   function catmullRom$$1(context) {
33875     return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0);
33876   }
33877
33878   catmullRom$$1.alpha = function(alpha) {
33879     return custom(+alpha);
33880   };
33881
33882   return catmullRom$$1;
33883 }))(0.5);
33884
33885 function LinearClosed(context) {
33886   this._context = context;
33887 }
33888
33889 LinearClosed.prototype = {
33890   areaStart: noop$2,
33891   areaEnd: noop$2,
33892   lineStart: function() {
33893     this._point = 0;
33894   },
33895   lineEnd: function() {
33896     if (this._point) this._context.closePath();
33897   },
33898   point: function(x, y) {
33899     x = +x, y = +y;
33900     if (this._point) this._context.lineTo(x, y);
33901     else this._point = 1, this._context.moveTo(x, y);
33902   }
33903 };
33904
33905 var linearClosed = function(context) {
33906   return new LinearClosed(context);
33907 };
33908
33909 function sign$1(x) {
33910   return x < 0 ? -1 : 1;
33911 }
33912
33913 // Calculate the slopes of the tangents (Hermite-type interpolation) based on
33914 // the following paper: Steffen, M. 1990. A Simple Method for Monotonic
33915 // Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.
33916 // NOV(II), P. 443, 1990.
33917 function slope3(that, x2, y2) {
33918   var h0 = that._x1 - that._x0,
33919       h1 = x2 - that._x1,
33920       s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),
33921       s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),
33922       p = (s0 * h1 + s1 * h0) / (h0 + h1);
33923   return (sign$1(s0) + sign$1(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
33924 }
33925
33926 // Calculate a one-sided slope.
33927 function slope2(that, t) {
33928   var h = that._x1 - that._x0;
33929   return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;
33930 }
33931
33932 // According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations
33933 // "you can express cubic Hermite interpolation in terms of cubic Bézier curves
33934 // with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1".
33935 function point$5(that, t0, t1) {
33936   var x0 = that._x0,
33937       y0 = that._y0,
33938       x1 = that._x1,
33939       y1 = that._y1,
33940       dx = (x1 - x0) / 3;
33941   that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);
33942 }
33943
33944 function MonotoneX(context) {
33945   this._context = context;
33946 }
33947
33948 MonotoneX.prototype = {
33949   areaStart: function() {
33950     this._line = 0;
33951   },
33952   areaEnd: function() {
33953     this._line = NaN;
33954   },
33955   lineStart: function() {
33956     this._x0 = this._x1 =
33957     this._y0 = this._y1 =
33958     this._t0 = NaN;
33959     this._point = 0;
33960   },
33961   lineEnd: function() {
33962     switch (this._point) {
33963       case 2: this._context.lineTo(this._x1, this._y1); break;
33964       case 3: point$5(this, this._t0, slope2(this, this._t0)); break;
33965     }
33966     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
33967     this._line = 1 - this._line;
33968   },
33969   point: function(x, y) {
33970     var t1 = NaN;
33971
33972     x = +x, y = +y;
33973     if (x === this._x1 && y === this._y1) return; // Ignore coincident points.
33974     switch (this._point) {
33975       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
33976       case 1: this._point = 2; break;
33977       case 2: this._point = 3; point$5(this, slope2(this, t1 = slope3(this, x, y)), t1); break;
33978       default: point$5(this, this._t0, t1 = slope3(this, x, y)); break;
33979     }
33980
33981     this._x0 = this._x1, this._x1 = x;
33982     this._y0 = this._y1, this._y1 = y;
33983     this._t0 = t1;
33984   }
33985 };
33986
33987 function MonotoneY(context) {
33988   this._context = new ReflectContext(context);
33989 }
33990
33991 (MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {
33992   MonotoneX.prototype.point.call(this, y, x);
33993 };
33994
33995 function ReflectContext(context) {
33996   this._context = context;
33997 }
33998
33999 ReflectContext.prototype = {
34000   moveTo: function(x, y) { this._context.moveTo(y, x); },
34001   closePath: function() { this._context.closePath(); },
34002   lineTo: function(x, y) { this._context.lineTo(y, x); },
34003   bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }
34004 };
34005
34006 function monotoneX(context) {
34007   return new MonotoneX(context);
34008 }
34009
34010 function monotoneY(context) {
34011   return new MonotoneY(context);
34012 }
34013
34014 function Natural(context) {
34015   this._context = context;
34016 }
34017
34018 Natural.prototype = {
34019   areaStart: function() {
34020     this._line = 0;
34021   },
34022   areaEnd: function() {
34023     this._line = NaN;
34024   },
34025   lineStart: function() {
34026     this._x = [];
34027     this._y = [];
34028   },
34029   lineEnd: function() {
34030     var x = this._x,
34031         y = this._y,
34032         n = x.length;
34033
34034     if (n) {
34035       this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);
34036       if (n === 2) {
34037         this._context.lineTo(x[1], y[1]);
34038       } else {
34039         var px = controlPoints(x),
34040             py = controlPoints(y);
34041         for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {
34042           this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);
34043         }
34044       }
34045     }
34046
34047     if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();
34048     this._line = 1 - this._line;
34049     this._x = this._y = null;
34050   },
34051   point: function(x, y) {
34052     this._x.push(+x);
34053     this._y.push(+y);
34054   }
34055 };
34056
34057 // See https://www.particleincell.com/2012/bezier-splines/ for derivation.
34058 function controlPoints(x) {
34059   var i,
34060       n = x.length - 1,
34061       m,
34062       a = new Array(n),
34063       b = new Array(n),
34064       r = new Array(n);
34065   a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];
34066   for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];
34067   a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];
34068   for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];
34069   a[n - 1] = r[n - 1] / b[n - 1];
34070   for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];
34071   b[n - 1] = (x[n] + a[n - 1]) / 2;
34072   for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];
34073   return [a, b];
34074 }
34075
34076 var natural = function(context) {
34077   return new Natural(context);
34078 };
34079
34080 function Step(context, t) {
34081   this._context = context;
34082   this._t = t;
34083 }
34084
34085 Step.prototype = {
34086   areaStart: function() {
34087     this._line = 0;
34088   },
34089   areaEnd: function() {
34090     this._line = NaN;
34091   },
34092   lineStart: function() {
34093     this._x = this._y = NaN;
34094     this._point = 0;
34095   },
34096   lineEnd: function() {
34097     if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
34098     if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
34099     if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
34100   },
34101   point: function(x, y) {
34102     x = +x, y = +y;
34103     switch (this._point) {
34104       case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
34105       case 1: this._point = 2; // proceed
34106       default: {
34107         if (this._t <= 0) {
34108           this._context.lineTo(this._x, y);
34109           this._context.lineTo(x, y);
34110         } else {
34111           var x1 = this._x * (1 - this._t) + x * this._t;
34112           this._context.lineTo(x1, this._y);
34113           this._context.lineTo(x1, y);
34114         }
34115         break;
34116       }
34117     }
34118     this._x = x, this._y = y;
34119   }
34120 };
34121
34122 var step = function(context) {
34123   return new Step(context, 0.5);
34124 };
34125
34126 function stepBefore(context) {
34127   return new Step(context, 0);
34128 }
34129
34130 function stepAfter(context) {
34131   return new Step(context, 1);
34132 }
34133
34134 var none$1 = function(series, order) {
34135   if (!((n = series.length) > 1)) return;
34136   for (var i = 1, j, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {
34137     s0 = s1, s1 = series[order[i]];
34138     for (j = 0; j < m; ++j) {
34139       s1[j][1] += s1[j][0] = isNaN(s0[j][1]) ? s0[j][0] : s0[j][1];
34140     }
34141   }
34142 };
34143
34144 var none$2 = function(series) {
34145   var n = series.length, o = new Array(n);
34146   while (--n >= 0) o[n] = n;
34147   return o;
34148 };
34149
34150 function stackValue(d, key) {
34151   return d[key];
34152 }
34153
34154 var stack = function() {
34155   var keys = constant$10([]),
34156       order = none$2,
34157       offset = none$1,
34158       value = stackValue;
34159
34160   function stack(data) {
34161     var kz = keys.apply(this, arguments),
34162         i,
34163         m = data.length,
34164         n = kz.length,
34165         sz = new Array(n),
34166         oz;
34167
34168     for (i = 0; i < n; ++i) {
34169       for (var ki = kz[i], si = sz[i] = new Array(m), j = 0, sij; j < m; ++j) {
34170         si[j] = sij = [0, +value(data[j], ki, j, data)];
34171         sij.data = data[j];
34172       }
34173       si.key = ki;
34174     }
34175
34176     for (i = 0, oz = order(sz); i < n; ++i) {
34177       sz[oz[i]].index = i;
34178     }
34179
34180     offset(sz, oz);
34181     return sz;
34182   }
34183
34184   stack.keys = function(_) {
34185     return arguments.length ? (keys = typeof _ === "function" ? _ : constant$10(slice$5.call(_)), stack) : keys;
34186   };
34187
34188   stack.value = function(_) {
34189     return arguments.length ? (value = typeof _ === "function" ? _ : constant$10(+_), stack) : value;
34190   };
34191
34192   stack.order = function(_) {
34193     return arguments.length ? (order = _ == null ? none$2 : typeof _ === "function" ? _ : constant$10(slice$5.call(_)), stack) : order;
34194   };
34195
34196   stack.offset = function(_) {
34197     return arguments.length ? (offset = _ == null ? none$1 : _, stack) : offset;
34198   };
34199
34200   return stack;
34201 };
34202
34203 var expand = function(series, order) {
34204   if (!((n = series.length) > 0)) return;
34205   for (var i, n, j = 0, m = series[0].length, y; j < m; ++j) {
34206     for (y = i = 0; i < n; ++i) y += series[i][j][1] || 0;
34207     if (y) for (i = 0; i < n; ++i) series[i][j][1] /= y;
34208   }
34209   none$1(series, order);
34210 };
34211
34212 var diverging = function(series, order) {
34213   if (!((n = series.length) > 1)) return;
34214   for (var i, j = 0, d, dy, yp, yn, n, m = series[order[0]].length; j < m; ++j) {
34215     for (yp = yn = 0, i = 0; i < n; ++i) {
34216       if ((dy = (d = series[order[i]][j])[1] - d[0]) >= 0) {
34217         d[0] = yp, d[1] = yp += dy;
34218       } else if (dy < 0) {
34219         d[1] = yn, d[0] = yn += dy;
34220       } else {
34221         d[0] = yp;
34222       }
34223     }
34224   }
34225 };
34226
34227 var silhouette = function(series, order) {
34228   if (!((n = series.length) > 0)) return;
34229   for (var j = 0, s0 = series[order[0]], n, m = s0.length; j < m; ++j) {
34230     for (var i = 0, y = 0; i < n; ++i) y += series[i][j][1] || 0;
34231     s0[j][1] += s0[j][0] = -y / 2;
34232   }
34233   none$1(series, order);
34234 };
34235
34236 var wiggle = function(series, order) {
34237   if (!((n = series.length) > 0) || !((m = (s0 = series[order[0]]).length) > 0)) return;
34238   for (var y = 0, j = 1, s0, m, n; j < m; ++j) {
34239     for (var i = 0, s1 = 0, s2 = 0; i < n; ++i) {
34240       var si = series[order[i]],
34241           sij0 = si[j][1] || 0,
34242           sij1 = si[j - 1][1] || 0,
34243           s3 = (sij0 - sij1) / 2;
34244       for (var k = 0; k < i; ++k) {
34245         var sk = series[order[k]],
34246             skj0 = sk[j][1] || 0,
34247             skj1 = sk[j - 1][1] || 0;
34248         s3 += skj0 - skj1;
34249       }
34250       s1 += sij0, s2 += s3 * sij0;
34251     }
34252     s0[j - 1][1] += s0[j - 1][0] = y;
34253     if (s1) y -= s2 / s1;
34254   }
34255   s0[j - 1][1] += s0[j - 1][0] = y;
34256   none$1(series, order);
34257 };
34258
34259 var ascending$2 = function(series) {
34260   var sums = series.map(sum$2);
34261   return none$2(series).sort(function(a, b) { return sums[a] - sums[b]; });
34262 };
34263
34264 function sum$2(series) {
34265   var s = 0, i = -1, n = series.length, v;
34266   while (++i < n) if (v = +series[i][1]) s += v;
34267   return s;
34268 }
34269
34270 var descending$2 = function(series) {
34271   return ascending$2(series).reverse();
34272 };
34273
34274 var insideOut = function(series) {
34275   var n = series.length,
34276       i,
34277       j,
34278       sums = series.map(sum$2),
34279       order = none$2(series).sort(function(a, b) { return sums[b] - sums[a]; }),
34280       top = 0,
34281       bottom = 0,
34282       tops = [],
34283       bottoms = [];
34284
34285   for (i = 0; i < n; ++i) {
34286     j = order[i];
34287     if (top < bottom) {
34288       top += sums[j];
34289       tops.push(j);
34290     } else {
34291       bottom += sums[j];
34292       bottoms.push(j);
34293     }
34294   }
34295
34296   return bottoms.reverse().concat(tops);
34297 };
34298
34299 var reverse = function(series) {
34300   return none$2(series).reverse();
34301 };
34302
34303 var constant$11 = function(x) {
34304   return function() {
34305     return x;
34306   };
34307 };
34308
34309 function x$4(d) {
34310   return d[0];
34311 }
34312
34313 function y$4(d) {
34314   return d[1];
34315 }
34316
34317 function RedBlackTree() {
34318   this._ = null; // root node
34319 }
34320
34321 function RedBlackNode(node) {
34322   node.U = // parent node
34323   node.C = // color - true for red, false for black
34324   node.L = // left node
34325   node.R = // right node
34326   node.P = // previous node
34327   node.N = null; // next node
34328 }
34329
34330 RedBlackTree.prototype = {
34331   constructor: RedBlackTree,
34332
34333   insert: function(after, node) {
34334     var parent, grandpa, uncle;
34335
34336     if (after) {
34337       node.P = after;
34338       node.N = after.N;
34339       if (after.N) after.N.P = node;
34340       after.N = node;
34341       if (after.R) {
34342         after = after.R;
34343         while (after.L) after = after.L;
34344         after.L = node;
34345       } else {
34346         after.R = node;
34347       }
34348       parent = after;
34349     } else if (this._) {
34350       after = RedBlackFirst(this._);
34351       node.P = null;
34352       node.N = after;
34353       after.P = after.L = node;
34354       parent = after;
34355     } else {
34356       node.P = node.N = null;
34357       this._ = node;
34358       parent = null;
34359     }
34360     node.L = node.R = null;
34361     node.U = parent;
34362     node.C = true;
34363
34364     after = node;
34365     while (parent && parent.C) {
34366       grandpa = parent.U;
34367       if (parent === grandpa.L) {
34368         uncle = grandpa.R;
34369         if (uncle && uncle.C) {
34370           parent.C = uncle.C = false;
34371           grandpa.C = true;
34372           after = grandpa;
34373         } else {
34374           if (after === parent.R) {
34375             RedBlackRotateLeft(this, parent);
34376             after = parent;
34377             parent = after.U;
34378           }
34379           parent.C = false;
34380           grandpa.C = true;
34381           RedBlackRotateRight(this, grandpa);
34382         }
34383       } else {
34384         uncle = grandpa.L;
34385         if (uncle && uncle.C) {
34386           parent.C = uncle.C = false;
34387           grandpa.C = true;
34388           after = grandpa;
34389         } else {
34390           if (after === parent.L) {
34391             RedBlackRotateRight(this, parent);
34392             after = parent;
34393             parent = after.U;
34394           }
34395           parent.C = false;
34396           grandpa.C = true;
34397           RedBlackRotateLeft(this, grandpa);
34398         }
34399       }
34400       parent = after.U;
34401     }
34402     this._.C = false;
34403   },
34404
34405   remove: function(node) {
34406     if (node.N) node.N.P = node.P;
34407     if (node.P) node.P.N = node.N;
34408     node.N = node.P = null;
34409
34410     var parent = node.U,
34411         sibling,
34412         left = node.L,
34413         right = node.R,
34414         next,
34415         red;
34416
34417     if (!left) next = right;
34418     else if (!right) next = left;
34419     else next = RedBlackFirst(right);
34420
34421     if (parent) {
34422       if (parent.L === node) parent.L = next;
34423       else parent.R = next;
34424     } else {
34425       this._ = next;
34426     }
34427
34428     if (left && right) {
34429       red = next.C;
34430       next.C = node.C;
34431       next.L = left;
34432       left.U = next;
34433       if (next !== right) {
34434         parent = next.U;
34435         next.U = node.U;
34436         node = next.R;
34437         parent.L = node;
34438         next.R = right;
34439         right.U = next;
34440       } else {
34441         next.U = parent;
34442         parent = next;
34443         node = next.R;
34444       }
34445     } else {
34446       red = node.C;
34447       node = next;
34448     }
34449
34450     if (node) node.U = parent;
34451     if (red) return;
34452     if (node && node.C) { node.C = false; return; }
34453
34454     do {
34455       if (node === this._) break;
34456       if (node === parent.L) {
34457         sibling = parent.R;
34458         if (sibling.C) {
34459           sibling.C = false;
34460           parent.C = true;
34461           RedBlackRotateLeft(this, parent);
34462           sibling = parent.R;
34463         }
34464         if ((sibling.L && sibling.L.C)
34465             || (sibling.R && sibling.R.C)) {
34466           if (!sibling.R || !sibling.R.C) {
34467             sibling.L.C = false;
34468             sibling.C = true;
34469             RedBlackRotateRight(this, sibling);
34470             sibling = parent.R;
34471           }
34472           sibling.C = parent.C;
34473           parent.C = sibling.R.C = false;
34474           RedBlackRotateLeft(this, parent);
34475           node = this._;
34476           break;
34477         }
34478       } else {
34479         sibling = parent.L;
34480         if (sibling.C) {
34481           sibling.C = false;
34482           parent.C = true;
34483           RedBlackRotateRight(this, parent);
34484           sibling = parent.L;
34485         }
34486         if ((sibling.L && sibling.L.C)
34487           || (sibling.R && sibling.R.C)) {
34488           if (!sibling.L || !sibling.L.C) {
34489             sibling.R.C = false;
34490             sibling.C = true;
34491             RedBlackRotateLeft(this, sibling);
34492             sibling = parent.L;
34493           }
34494           sibling.C = parent.C;
34495           parent.C = sibling.L.C = false;
34496           RedBlackRotateRight(this, parent);
34497           node = this._;
34498           break;
34499         }
34500       }
34501       sibling.C = true;
34502       node = parent;
34503       parent = parent.U;
34504     } while (!node.C);
34505
34506     if (node) node.C = false;
34507   }
34508 };
34509
34510 function RedBlackRotateLeft(tree, node) {
34511   var p = node,
34512       q = node.R,
34513       parent = p.U;
34514
34515   if (parent) {
34516     if (parent.L === p) parent.L = q;
34517     else parent.R = q;
34518   } else {
34519     tree._ = q;
34520   }
34521
34522   q.U = parent;
34523   p.U = q;
34524   p.R = q.L;
34525   if (p.R) p.R.U = p;
34526   q.L = p;
34527 }
34528
34529 function RedBlackRotateRight(tree, node) {
34530   var p = node,
34531       q = node.L,
34532       parent = p.U;
34533
34534   if (parent) {
34535     if (parent.L === p) parent.L = q;
34536     else parent.R = q;
34537   } else {
34538     tree._ = q;
34539   }
34540
34541   q.U = parent;
34542   p.U = q;
34543   p.L = q.R;
34544   if (p.L) p.L.U = p;
34545   q.R = p;
34546 }
34547
34548 function RedBlackFirst(node) {
34549   while (node.L) node = node.L;
34550   return node;
34551 }
34552
34553 function createEdge(left, right, v0, v1) {
34554   var edge = [null, null],
34555       index = edges.push(edge) - 1;
34556   edge.left = left;
34557   edge.right = right;
34558   if (v0) setEdgeEnd(edge, left, right, v0);
34559   if (v1) setEdgeEnd(edge, right, left, v1);
34560   cells[left.index].halfedges.push(index);
34561   cells[right.index].halfedges.push(index);
34562   return edge;
34563 }
34564
34565 function createBorderEdge(left, v0, v1) {
34566   var edge = [v0, v1];
34567   edge.left = left;
34568   return edge;
34569 }
34570
34571 function setEdgeEnd(edge, left, right, vertex) {
34572   if (!edge[0] && !edge[1]) {
34573     edge[0] = vertex;
34574     edge.left = left;
34575     edge.right = right;
34576   } else if (edge.left === right) {
34577     edge[1] = vertex;
34578   } else {
34579     edge[0] = vertex;
34580   }
34581 }
34582
34583 // Liang–Barsky line clipping.
34584 function clipEdge(edge, x0, y0, x1, y1) {
34585   var a = edge[0],
34586       b = edge[1],
34587       ax = a[0],
34588       ay = a[1],
34589       bx = b[0],
34590       by = b[1],
34591       t0 = 0,
34592       t1 = 1,
34593       dx = bx - ax,
34594       dy = by - ay,
34595       r;
34596
34597   r = x0 - ax;
34598   if (!dx && r > 0) return;
34599   r /= dx;
34600   if (dx < 0) {
34601     if (r < t0) return;
34602     if (r < t1) t1 = r;
34603   } else if (dx > 0) {
34604     if (r > t1) return;
34605     if (r > t0) t0 = r;
34606   }
34607
34608   r = x1 - ax;
34609   if (!dx && r < 0) return;
34610   r /= dx;
34611   if (dx < 0) {
34612     if (r > t1) return;
34613     if (r > t0) t0 = r;
34614   } else if (dx > 0) {
34615     if (r < t0) return;
34616     if (r < t1) t1 = r;
34617   }
34618
34619   r = y0 - ay;
34620   if (!dy && r > 0) return;
34621   r /= dy;
34622   if (dy < 0) {
34623     if (r < t0) return;
34624     if (r < t1) t1 = r;
34625   } else if (dy > 0) {
34626     if (r > t1) return;
34627     if (r > t0) t0 = r;
34628   }
34629
34630   r = y1 - ay;
34631   if (!dy && r < 0) return;
34632   r /= dy;
34633   if (dy < 0) {
34634     if (r > t1) return;
34635     if (r > t0) t0 = r;
34636   } else if (dy > 0) {
34637     if (r < t0) return;
34638     if (r < t1) t1 = r;
34639   }
34640
34641   if (!(t0 > 0) && !(t1 < 1)) return true; // TODO Better check?
34642
34643   if (t0 > 0) edge[0] = [ax + t0 * dx, ay + t0 * dy];
34644   if (t1 < 1) edge[1] = [ax + t1 * dx, ay + t1 * dy];
34645   return true;
34646 }
34647
34648 function connectEdge(edge, x0, y0, x1, y1) {
34649   var v1 = edge[1];
34650   if (v1) return true;
34651
34652   var v0 = edge[0],
34653       left = edge.left,
34654       right = edge.right,
34655       lx = left[0],
34656       ly = left[1],
34657       rx = right[0],
34658       ry = right[1],
34659       fx = (lx + rx) / 2,
34660       fy = (ly + ry) / 2,
34661       fm,
34662       fb;
34663
34664   if (ry === ly) {
34665     if (fx < x0 || fx >= x1) return;
34666     if (lx > rx) {
34667       if (!v0) v0 = [fx, y0];
34668       else if (v0[1] >= y1) return;
34669       v1 = [fx, y1];
34670     } else {
34671       if (!v0) v0 = [fx, y1];
34672       else if (v0[1] < y0) return;
34673       v1 = [fx, y0];
34674     }
34675   } else {
34676     fm = (lx - rx) / (ry - ly);
34677     fb = fy - fm * fx;
34678     if (fm < -1 || fm > 1) {
34679       if (lx > rx) {
34680         if (!v0) v0 = [(y0 - fb) / fm, y0];
34681         else if (v0[1] >= y1) return;
34682         v1 = [(y1 - fb) / fm, y1];
34683       } else {
34684         if (!v0) v0 = [(y1 - fb) / fm, y1];
34685         else if (v0[1] < y0) return;
34686         v1 = [(y0 - fb) / fm, y0];
34687       }
34688     } else {
34689       if (ly < ry) {
34690         if (!v0) v0 = [x0, fm * x0 + fb];
34691         else if (v0[0] >= x1) return;
34692         v1 = [x1, fm * x1 + fb];
34693       } else {
34694         if (!v0) v0 = [x1, fm * x1 + fb];
34695         else if (v0[0] < x0) return;
34696         v1 = [x0, fm * x0 + fb];
34697       }
34698     }
34699   }
34700
34701   edge[0] = v0;
34702   edge[1] = v1;
34703   return true;
34704 }
34705
34706 function clipEdges(x0, y0, x1, y1) {
34707   var i = edges.length,
34708       edge;
34709
34710   while (i--) {
34711     if (!connectEdge(edge = edges[i], x0, y0, x1, y1)
34712         || !clipEdge(edge, x0, y0, x1, y1)
34713         || !(Math.abs(edge[0][0] - edge[1][0]) > epsilon$4
34714             || Math.abs(edge[0][1] - edge[1][1]) > epsilon$4)) {
34715       delete edges[i];
34716     }
34717   }
34718 }
34719
34720 function createCell(site) {
34721   return cells[site.index] = {
34722     site: site,
34723     halfedges: []
34724   };
34725 }
34726
34727 function cellHalfedgeAngle(cell, edge) {
34728   var site = cell.site,
34729       va = edge.left,
34730       vb = edge.right;
34731   if (site === vb) vb = va, va = site;
34732   if (vb) return Math.atan2(vb[1] - va[1], vb[0] - va[0]);
34733   if (site === va) va = edge[1], vb = edge[0];
34734   else va = edge[0], vb = edge[1];
34735   return Math.atan2(va[0] - vb[0], vb[1] - va[1]);
34736 }
34737
34738 function cellHalfedgeStart(cell, edge) {
34739   return edge[+(edge.left !== cell.site)];
34740 }
34741
34742 function cellHalfedgeEnd(cell, edge) {
34743   return edge[+(edge.left === cell.site)];
34744 }
34745
34746 function sortCellHalfedges() {
34747   for (var i = 0, n = cells.length, cell, halfedges, j, m; i < n; ++i) {
34748     if ((cell = cells[i]) && (m = (halfedges = cell.halfedges).length)) {
34749       var index = new Array(m),
34750           array = new Array(m);
34751       for (j = 0; j < m; ++j) index[j] = j, array[j] = cellHalfedgeAngle(cell, edges[halfedges[j]]);
34752       index.sort(function(i, j) { return array[j] - array[i]; });
34753       for (j = 0; j < m; ++j) array[j] = halfedges[index[j]];
34754       for (j = 0; j < m; ++j) halfedges[j] = array[j];
34755     }
34756   }
34757 }
34758
34759 function clipCells(x0, y0, x1, y1) {
34760   var nCells = cells.length,
34761       iCell,
34762       cell,
34763       site,
34764       iHalfedge,
34765       halfedges,
34766       nHalfedges,
34767       start,
34768       startX,
34769       startY,
34770       end,
34771       endX,
34772       endY,
34773       cover = true;
34774
34775   for (iCell = 0; iCell < nCells; ++iCell) {
34776     if (cell = cells[iCell]) {
34777       site = cell.site;
34778       halfedges = cell.halfedges;
34779       iHalfedge = halfedges.length;
34780
34781       // Remove any dangling clipped edges.
34782       while (iHalfedge--) {
34783         if (!edges[halfedges[iHalfedge]]) {
34784           halfedges.splice(iHalfedge, 1);
34785         }
34786       }
34787
34788       // Insert any border edges as necessary.
34789       iHalfedge = 0, nHalfedges = halfedges.length;
34790       while (iHalfedge < nHalfedges) {
34791         end = cellHalfedgeEnd(cell, edges[halfedges[iHalfedge]]), endX = end[0], endY = end[1];
34792         start = cellHalfedgeStart(cell, edges[halfedges[++iHalfedge % nHalfedges]]), startX = start[0], startY = start[1];
34793         if (Math.abs(endX - startX) > epsilon$4 || Math.abs(endY - startY) > epsilon$4) {
34794           halfedges.splice(iHalfedge, 0, edges.push(createBorderEdge(site, end,
34795               Math.abs(endX - x0) < epsilon$4 && y1 - endY > epsilon$4 ? [x0, Math.abs(startX - x0) < epsilon$4 ? startY : y1]
34796               : Math.abs(endY - y1) < epsilon$4 && x1 - endX > epsilon$4 ? [Math.abs(startY - y1) < epsilon$4 ? startX : x1, y1]
34797               : Math.abs(endX - x1) < epsilon$4 && endY - y0 > epsilon$4 ? [x1, Math.abs(startX - x1) < epsilon$4 ? startY : y0]
34798               : Math.abs(endY - y0) < epsilon$4 && endX - x0 > epsilon$4 ? [Math.abs(startY - y0) < epsilon$4 ? startX : x0, y0]
34799               : null)) - 1);
34800           ++nHalfedges;
34801         }
34802       }
34803
34804       if (nHalfedges) cover = false;
34805     }
34806   }
34807
34808   // If there weren’t any edges, have the closest site cover the extent.
34809   // It doesn’t matter which corner of the extent we measure!
34810   if (cover) {
34811     var dx, dy, d2, dc = Infinity;
34812
34813     for (iCell = 0, cover = null; iCell < nCells; ++iCell) {
34814       if (cell = cells[iCell]) {
34815         site = cell.site;
34816         dx = site[0] - x0;
34817         dy = site[1] - y0;
34818         d2 = dx * dx + dy * dy;
34819         if (d2 < dc) dc = d2, cover = cell;
34820       }
34821     }
34822
34823     if (cover) {
34824       var v00 = [x0, y0], v01 = [x0, y1], v11 = [x1, y1], v10 = [x1, y0];
34825       cover.halfedges.push(
34826         edges.push(createBorderEdge(site = cover.site, v00, v01)) - 1,
34827         edges.push(createBorderEdge(site, v01, v11)) - 1,
34828         edges.push(createBorderEdge(site, v11, v10)) - 1,
34829         edges.push(createBorderEdge(site, v10, v00)) - 1
34830       );
34831     }
34832   }
34833
34834   // Lastly delete any cells with no edges; these were entirely clipped.
34835   for (iCell = 0; iCell < nCells; ++iCell) {
34836     if (cell = cells[iCell]) {
34837       if (!cell.halfedges.length) {
34838         delete cells[iCell];
34839       }
34840     }
34841   }
34842 }
34843
34844 var circlePool = [];
34845
34846 var firstCircle;
34847
34848 function Circle() {
34849   RedBlackNode(this);
34850   this.x =
34851   this.y =
34852   this.arc =
34853   this.site =
34854   this.cy = null;
34855 }
34856
34857 function attachCircle(arc) {
34858   var lArc = arc.P,
34859       rArc = arc.N;
34860
34861   if (!lArc || !rArc) return;
34862
34863   var lSite = lArc.site,
34864       cSite = arc.site,
34865       rSite = rArc.site;
34866
34867   if (lSite === rSite) return;
34868
34869   var bx = cSite[0],
34870       by = cSite[1],
34871       ax = lSite[0] - bx,
34872       ay = lSite[1] - by,
34873       cx = rSite[0] - bx,
34874       cy = rSite[1] - by;
34875
34876   var d = 2 * (ax * cy - ay * cx);
34877   if (d >= -epsilon2$2) return;
34878
34879   var ha = ax * ax + ay * ay,
34880       hc = cx * cx + cy * cy,
34881       x = (cy * ha - ay * hc) / d,
34882       y = (ax * hc - cx * ha) / d;
34883
34884   var circle = circlePool.pop() || new Circle;
34885   circle.arc = arc;
34886   circle.site = cSite;
34887   circle.x = x + bx;
34888   circle.y = (circle.cy = y + by) + Math.sqrt(x * x + y * y); // y bottom
34889
34890   arc.circle = circle;
34891
34892   var before = null,
34893       node = circles._;
34894
34895   while (node) {
34896     if (circle.y < node.y || (circle.y === node.y && circle.x <= node.x)) {
34897       if (node.L) node = node.L;
34898       else { before = node.P; break; }
34899     } else {
34900       if (node.R) node = node.R;
34901       else { before = node; break; }
34902     }
34903   }
34904
34905   circles.insert(before, circle);
34906   if (!before) firstCircle = circle;
34907 }
34908
34909 function detachCircle(arc) {
34910   var circle = arc.circle;
34911   if (circle) {
34912     if (!circle.P) firstCircle = circle.N;
34913     circles.remove(circle);
34914     circlePool.push(circle);
34915     RedBlackNode(circle);
34916     arc.circle = null;
34917   }
34918 }
34919
34920 var beachPool = [];
34921
34922 function Beach() {
34923   RedBlackNode(this);
34924   this.edge =
34925   this.site =
34926   this.circle = null;
34927 }
34928
34929 function createBeach(site) {
34930   var beach = beachPool.pop() || new Beach;
34931   beach.site = site;
34932   return beach;
34933 }
34934
34935 function detachBeach(beach) {
34936   detachCircle(beach);
34937   beaches.remove(beach);
34938   beachPool.push(beach);
34939   RedBlackNode(beach);
34940 }
34941
34942 function removeBeach(beach) {
34943   var circle = beach.circle,
34944       x = circle.x,
34945       y = circle.cy,
34946       vertex = [x, y],
34947       previous = beach.P,
34948       next = beach.N,
34949       disappearing = [beach];
34950
34951   detachBeach(beach);
34952
34953   var lArc = previous;
34954   while (lArc.circle
34955       && Math.abs(x - lArc.circle.x) < epsilon$4
34956       && Math.abs(y - lArc.circle.cy) < epsilon$4) {
34957     previous = lArc.P;
34958     disappearing.unshift(lArc);
34959     detachBeach(lArc);
34960     lArc = previous;
34961   }
34962
34963   disappearing.unshift(lArc);
34964   detachCircle(lArc);
34965
34966   var rArc = next;
34967   while (rArc.circle
34968       && Math.abs(x - rArc.circle.x) < epsilon$4
34969       && Math.abs(y - rArc.circle.cy) < epsilon$4) {
34970     next = rArc.N;
34971     disappearing.push(rArc);
34972     detachBeach(rArc);
34973     rArc = next;
34974   }
34975
34976   disappearing.push(rArc);
34977   detachCircle(rArc);
34978
34979   var nArcs = disappearing.length,
34980       iArc;
34981   for (iArc = 1; iArc < nArcs; ++iArc) {
34982     rArc = disappearing[iArc];
34983     lArc = disappearing[iArc - 1];
34984     setEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
34985   }
34986
34987   lArc = disappearing[0];
34988   rArc = disappearing[nArcs - 1];
34989   rArc.edge = createEdge(lArc.site, rArc.site, null, vertex);
34990
34991   attachCircle(lArc);
34992   attachCircle(rArc);
34993 }
34994
34995 function addBeach(site) {
34996   var x = site[0],
34997       directrix = site[1],
34998       lArc,
34999       rArc,
35000       dxl,
35001       dxr,
35002       node = beaches._;
35003
35004   while (node) {
35005     dxl = leftBreakPoint(node, directrix) - x;
35006     if (dxl > epsilon$4) node = node.L; else {
35007       dxr = x - rightBreakPoint(node, directrix);
35008       if (dxr > epsilon$4) {
35009         if (!node.R) {
35010           lArc = node;
35011           break;
35012         }
35013         node = node.R;
35014       } else {
35015         if (dxl > -epsilon$4) {
35016           lArc = node.P;
35017           rArc = node;
35018         } else if (dxr > -epsilon$4) {
35019           lArc = node;
35020           rArc = node.N;
35021         } else {
35022           lArc = rArc = node;
35023         }
35024         break;
35025       }
35026     }
35027   }
35028
35029   createCell(site);
35030   var newArc = createBeach(site);
35031   beaches.insert(lArc, newArc);
35032
35033   if (!lArc && !rArc) return;
35034
35035   if (lArc === rArc) {
35036     detachCircle(lArc);
35037     rArc = createBeach(lArc.site);
35038     beaches.insert(newArc, rArc);
35039     newArc.edge = rArc.edge = createEdge(lArc.site, newArc.site);
35040     attachCircle(lArc);
35041     attachCircle(rArc);
35042     return;
35043   }
35044
35045   if (!rArc) { // && lArc
35046     newArc.edge = createEdge(lArc.site, newArc.site);
35047     return;
35048   }
35049
35050   // else lArc !== rArc
35051   detachCircle(lArc);
35052   detachCircle(rArc);
35053
35054   var lSite = lArc.site,
35055       ax = lSite[0],
35056       ay = lSite[1],
35057       bx = site[0] - ax,
35058       by = site[1] - ay,
35059       rSite = rArc.site,
35060       cx = rSite[0] - ax,
35061       cy = rSite[1] - ay,
35062       d = 2 * (bx * cy - by * cx),
35063       hb = bx * bx + by * by,
35064       hc = cx * cx + cy * cy,
35065       vertex = [(cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay];
35066
35067   setEdgeEnd(rArc.edge, lSite, rSite, vertex);
35068   newArc.edge = createEdge(lSite, site, null, vertex);
35069   rArc.edge = createEdge(site, rSite, null, vertex);
35070   attachCircle(lArc);
35071   attachCircle(rArc);
35072 }
35073
35074 function leftBreakPoint(arc, directrix) {
35075   var site = arc.site,
35076       rfocx = site[0],
35077       rfocy = site[1],
35078       pby2 = rfocy - directrix;
35079
35080   if (!pby2) return rfocx;
35081
35082   var lArc = arc.P;
35083   if (!lArc) return -Infinity;
35084
35085   site = lArc.site;
35086   var lfocx = site[0],
35087       lfocy = site[1],
35088       plby2 = lfocy - directrix;
35089
35090   if (!plby2) return lfocx;
35091
35092   var hl = lfocx - rfocx,
35093       aby2 = 1 / pby2 - 1 / plby2,
35094       b = hl / plby2;
35095
35096   if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
35097
35098   return (rfocx + lfocx) / 2;
35099 }
35100
35101 function rightBreakPoint(arc, directrix) {
35102   var rArc = arc.N;
35103   if (rArc) return leftBreakPoint(rArc, directrix);
35104   var site = arc.site;
35105   return site[1] === directrix ? site[0] : Infinity;
35106 }
35107
35108 var epsilon$4 = 1e-6;
35109 var epsilon2$2 = 1e-12;
35110 var beaches;
35111 var cells;
35112 var circles;
35113 var edges;
35114
35115 function triangleArea(a, b, c) {
35116   return (a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]);
35117 }
35118
35119 function lexicographic(a, b) {
35120   return b[1] - a[1]
35121       || b[0] - a[0];
35122 }
35123
35124 function Diagram(sites, extent) {
35125   var site = sites.sort(lexicographic).pop(),
35126       x,
35127       y,
35128       circle;
35129
35130   edges = [];
35131   cells = new Array(sites.length);
35132   beaches = new RedBlackTree;
35133   circles = new RedBlackTree;
35134
35135   while (true) {
35136     circle = firstCircle;
35137     if (site && (!circle || site[1] < circle.y || (site[1] === circle.y && site[0] < circle.x))) {
35138       if (site[0] !== x || site[1] !== y) {
35139         addBeach(site);
35140         x = site[0], y = site[1];
35141       }
35142       site = sites.pop();
35143     } else if (circle) {
35144       removeBeach(circle.arc);
35145     } else {
35146       break;
35147     }
35148   }
35149
35150   sortCellHalfedges();
35151
35152   if (extent) {
35153     var x0 = +extent[0][0],
35154         y0 = +extent[0][1],
35155         x1 = +extent[1][0],
35156         y1 = +extent[1][1];
35157     clipEdges(x0, y0, x1, y1);
35158     clipCells(x0, y0, x1, y1);
35159   }
35160
35161   this.edges = edges;
35162   this.cells = cells;
35163
35164   beaches =
35165   circles =
35166   edges =
35167   cells = null;
35168 }
35169
35170 Diagram.prototype = {
35171   constructor: Diagram,
35172
35173   polygons: function() {
35174     var edges = this.edges;
35175
35176     return this.cells.map(function(cell) {
35177       var polygon = cell.halfedges.map(function(i) { return cellHalfedgeStart(cell, edges[i]); });
35178       polygon.data = cell.site.data;
35179       return polygon;
35180     });
35181   },
35182
35183   triangles: function() {
35184     var triangles = [],
35185         edges = this.edges;
35186
35187     this.cells.forEach(function(cell, i) {
35188       if (!(m = (halfedges = cell.halfedges).length)) return;
35189       var site = cell.site,
35190           halfedges,
35191           j = -1,
35192           m,
35193           s0,
35194           e1 = edges[halfedges[m - 1]],
35195           s1 = e1.left === site ? e1.right : e1.left;
35196
35197       while (++j < m) {
35198         s0 = s1;
35199         e1 = edges[halfedges[j]];
35200         s1 = e1.left === site ? e1.right : e1.left;
35201         if (s0 && s1 && i < s0.index && i < s1.index && triangleArea(site, s0, s1) < 0) {
35202           triangles.push([site.data, s0.data, s1.data]);
35203         }
35204       }
35205     });
35206
35207     return triangles;
35208   },
35209
35210   links: function() {
35211     return this.edges.filter(function(edge) {
35212       return edge.right;
35213     }).map(function(edge) {
35214       return {
35215         source: edge.left.data,
35216         target: edge.right.data
35217       };
35218     });
35219   },
35220
35221   find: function(x, y, radius) {
35222     var that = this, i0, i1 = that._found || 0, n = that.cells.length, cell;
35223
35224     // Use the previously-found cell, or start with an arbitrary one.
35225     while (!(cell = that.cells[i1])) if (++i1 >= n) return null;
35226     var dx = x - cell.site[0], dy = y - cell.site[1], d2 = dx * dx + dy * dy;
35227
35228     // Traverse the half-edges to find a closer cell, if any.
35229     do {
35230       cell = that.cells[i0 = i1], i1 = null;
35231       cell.halfedges.forEach(function(e) {
35232         var edge = that.edges[e], v = edge.left;
35233         if ((v === cell.site || !v) && !(v = edge.right)) return;
35234         var vx = x - v[0], vy = y - v[1], v2 = vx * vx + vy * vy;
35235         if (v2 < d2) d2 = v2, i1 = v.index;
35236       });
35237     } while (i1 !== null);
35238
35239     that._found = i0;
35240
35241     return radius == null || d2 <= radius * radius ? cell.site : null;
35242   }
35243 };
35244
35245 var voronoi = function() {
35246   var x = x$4,
35247       y = y$4,
35248       extent = null;
35249
35250   function voronoi(data) {
35251     return new Diagram(data.map(function(d, i) {
35252       var s = [Math.round(x(d, i, data) / epsilon$4) * epsilon$4, Math.round(y(d, i, data) / epsilon$4) * epsilon$4];
35253       s.index = i;
35254       s.data = d;
35255       return s;
35256     }), extent);
35257   }
35258
35259   voronoi.polygons = function(data) {
35260     return voronoi(data).polygons();
35261   };
35262
35263   voronoi.links = function(data) {
35264     return voronoi(data).links();
35265   };
35266
35267   voronoi.triangles = function(data) {
35268     return voronoi(data).triangles();
35269   };
35270
35271   voronoi.x = function(_) {
35272     return arguments.length ? (x = typeof _ === "function" ? _ : constant$11(+_), voronoi) : x;
35273   };
35274
35275   voronoi.y = function(_) {
35276     return arguments.length ? (y = typeof _ === "function" ? _ : constant$11(+_), voronoi) : y;
35277   };
35278
35279   voronoi.extent = function(_) {
35280     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]]];
35281   };
35282
35283   voronoi.size = function(_) {
35284     return arguments.length ? (extent = _ == null ? null : [[0, 0], [+_[0], +_[1]]], voronoi) : extent && [extent[1][0] - extent[0][0], extent[1][1] - extent[0][1]];
35285   };
35286
35287   return voronoi;
35288 };
35289
35290 var constant$12 = function(x) {
35291   return function() {
35292     return x;
35293   };
35294 };
35295
35296 function ZoomEvent(target, type, transform) {
35297   this.target = target;
35298   this.type = type;
35299   this.transform = transform;
35300 }
35301
35302 function Transform(k, x, y) {
35303   this.k = k;
35304   this.x = x;
35305   this.y = y;
35306 }
35307
35308 Transform.prototype = {
35309   constructor: Transform,
35310   scale: function(k) {
35311     return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
35312   },
35313   translate: function(x, y) {
35314     return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
35315   },
35316   apply: function(point) {
35317     return [point[0] * this.k + this.x, point[1] * this.k + this.y];
35318   },
35319   applyX: function(x) {
35320     return x * this.k + this.x;
35321   },
35322   applyY: function(y) {
35323     return y * this.k + this.y;
35324   },
35325   invert: function(location) {
35326     return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
35327   },
35328   invertX: function(x) {
35329     return (x - this.x) / this.k;
35330   },
35331   invertY: function(y) {
35332     return (y - this.y) / this.k;
35333   },
35334   rescaleX: function(x) {
35335     return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
35336   },
35337   rescaleY: function(y) {
35338     return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
35339   },
35340   toString: function() {
35341     return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
35342   }
35343 };
35344
35345 var identity$8 = new Transform(1, 0, 0);
35346
35347 transform$1.prototype = Transform.prototype;
35348
35349 function transform$1(node) {
35350   return node.__zoom || identity$8;
35351 }
35352
35353 function nopropagation$2() {
35354   event.stopImmediatePropagation();
35355 }
35356
35357 var noevent$2 = function() {
35358   event.preventDefault();
35359   event.stopImmediatePropagation();
35360 };
35361
35362 // Ignore right-click, since that should open the context menu.
35363 function defaultFilter$2() {
35364   return !event.button;
35365 }
35366
35367 function defaultExtent$1() {
35368   var e = this, w, h;
35369   if (e instanceof SVGElement) {
35370     e = e.ownerSVGElement || e;
35371     w = e.width.baseVal.value;
35372     h = e.height.baseVal.value;
35373   } else {
35374     w = e.clientWidth;
35375     h = e.clientHeight;
35376   }
35377   return [[0, 0], [w, h]];
35378 }
35379
35380 function defaultTransform() {
35381   return this.__zoom || identity$8;
35382 }
35383
35384 var zoom = function() {
35385   var filter = defaultFilter$2,
35386       extent = defaultExtent$1,
35387       k0 = 0,
35388       k1 = Infinity,
35389       x0 = -k1,
35390       x1 = k1,
35391       y0 = x0,
35392       y1 = x1,
35393       duration = 250,
35394       interpolate = interpolateZoom,
35395       gestures = [],
35396       listeners = dispatch("start", "zoom", "end"),
35397       touchstarting,
35398       touchending,
35399       touchDelay = 500,
35400       wheelDelay = 150,
35401       clickDistance2 = 0;
35402
35403   function zoom(selection$$1) {
35404     selection$$1
35405         .on("wheel.zoom", wheeled)
35406         .on("mousedown.zoom", mousedowned)
35407         .on("dblclick.zoom", dblclicked)
35408         .on("touchstart.zoom", touchstarted)
35409         .on("touchmove.zoom", touchmoved)
35410         .on("touchend.zoom touchcancel.zoom", touchended)
35411         .style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
35412         .property("__zoom", defaultTransform);
35413   }
35414
35415   zoom.transform = function(collection, transform$$1) {
35416     var selection$$1 = collection.selection ? collection.selection() : collection;
35417     selection$$1.property("__zoom", defaultTransform);
35418     if (collection !== selection$$1) {
35419       schedule(collection, transform$$1);
35420     } else {
35421       selection$$1.interrupt().each(function() {
35422         gesture(this, arguments)
35423             .start()
35424             .zoom(null, typeof transform$$1 === "function" ? transform$$1.apply(this, arguments) : transform$$1)
35425             .end();
35426       });
35427     }
35428   };
35429
35430   zoom.scaleBy = function(selection$$1, k) {
35431     zoom.scaleTo(selection$$1, function() {
35432       var k0 = this.__zoom.k,
35433           k1 = typeof k === "function" ? k.apply(this, arguments) : k;
35434       return k0 * k1;
35435     });
35436   };
35437
35438   zoom.scaleTo = function(selection$$1, k) {
35439     zoom.transform(selection$$1, function() {
35440       var e = extent.apply(this, arguments),
35441           t0 = this.__zoom,
35442           p0 = centroid(e),
35443           p1 = t0.invert(p0),
35444           k1 = typeof k === "function" ? k.apply(this, arguments) : k;
35445       return constrain(translate(scale(t0, k1), p0, p1), e);
35446     });
35447   };
35448
35449   zoom.translateBy = function(selection$$1, x, y) {
35450     zoom.transform(selection$$1, function() {
35451       return constrain(this.__zoom.translate(
35452         typeof x === "function" ? x.apply(this, arguments) : x,
35453         typeof y === "function" ? y.apply(this, arguments) : y
35454       ), extent.apply(this, arguments));
35455     });
35456   };
35457
35458   function scale(transform$$1, k) {
35459     k = Math.max(k0, Math.min(k1, k));
35460     return k === transform$$1.k ? transform$$1 : new Transform(k, transform$$1.x, transform$$1.y);
35461   }
35462
35463   function translate(transform$$1, p0, p1) {
35464     var x = p0[0] - p1[0] * transform$$1.k, y = p0[1] - p1[1] * transform$$1.k;
35465     return x === transform$$1.x && y === transform$$1.y ? transform$$1 : new Transform(transform$$1.k, x, y);
35466   }
35467
35468   function constrain(transform$$1, extent) {
35469     var dx0 = transform$$1.invertX(extent[0][0]) - x0,
35470         dx1 = transform$$1.invertX(extent[1][0]) - x1,
35471         dy0 = transform$$1.invertY(extent[0][1]) - y0,
35472         dy1 = transform$$1.invertY(extent[1][1]) - y1;
35473     return transform$$1.translate(
35474       dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1),
35475       dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1)
35476     );
35477   }
35478
35479   function centroid(extent) {
35480     return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
35481   }
35482
35483   function schedule(transition$$1, transform$$1, center) {
35484     transition$$1
35485         .on("start.zoom", function() { gesture(this, arguments).start(); })
35486         .on("interrupt.zoom end.zoom", function() { gesture(this, arguments).end(); })
35487         .tween("zoom", function() {
35488           var that = this,
35489               args = arguments,
35490               g = gesture(that, args),
35491               e = extent.apply(that, args),
35492               p = center || centroid(e),
35493               w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
35494               a = that.__zoom,
35495               b = typeof transform$$1 === "function" ? transform$$1.apply(that, args) : transform$$1,
35496               i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
35497           return function(t) {
35498             if (t === 1) t = b; // Avoid rounding error on end.
35499             else { var l = i(t), k = w / l[2]; t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k); }
35500             g.zoom(null, t);
35501           };
35502         });
35503   }
35504
35505   function gesture(that, args) {
35506     for (var i = 0, n = gestures.length, g; i < n; ++i) {
35507       if ((g = gestures[i]).that === that) {
35508         return g;
35509       }
35510     }
35511     return new Gesture(that, args);
35512   }
35513
35514   function Gesture(that, args) {
35515     this.that = that;
35516     this.args = args;
35517     this.index = -1;
35518     this.active = 0;
35519     this.extent = extent.apply(that, args);
35520   }
35521
35522   Gesture.prototype = {
35523     start: function() {
35524       if (++this.active === 1) {
35525         this.index = gestures.push(this) - 1;
35526         this.emit("start");
35527       }
35528       return this;
35529     },
35530     zoom: function(key, transform$$1) {
35531       if (this.mouse && key !== "mouse") this.mouse[1] = transform$$1.invert(this.mouse[0]);
35532       if (this.touch0 && key !== "touch") this.touch0[1] = transform$$1.invert(this.touch0[0]);
35533       if (this.touch1 && key !== "touch") this.touch1[1] = transform$$1.invert(this.touch1[0]);
35534       this.that.__zoom = transform$$1;
35535       this.emit("zoom");
35536       return this;
35537     },
35538     end: function() {
35539       if (--this.active === 0) {
35540         gestures.splice(this.index, 1);
35541         this.index = -1;
35542         this.emit("end");
35543       }
35544       return this;
35545     },
35546     emit: function(type) {
35547       customEvent(new ZoomEvent(zoom, type, this.that.__zoom), listeners.apply, listeners, [type, this.that, this.args]);
35548     }
35549   };
35550
35551   function wheeled() {
35552     if (!filter.apply(this, arguments)) return;
35553     var g = gesture(this, arguments),
35554         t = this.__zoom,
35555         k = Math.max(k0, Math.min(k1, t.k * Math.pow(2, -event.deltaY * (event.deltaMode ? 120 : 1) / 500))),
35556         p = mouse(this);
35557
35558     // If the mouse is in the same location as before, reuse it.
35559     // If there were recent wheel events, reset the wheel idle timeout.
35560     if (g.wheel) {
35561       if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
35562         g.mouse[1] = t.invert(g.mouse[0] = p);
35563       }
35564       clearTimeout(g.wheel);
35565     }
35566
35567     // If this wheel event won’t trigger a transform change, ignore it.
35568     else if (t.k === k) return;
35569
35570     // Otherwise, capture the mouse point and location at the start.
35571     else {
35572       g.mouse = [p, t.invert(p)];
35573       interrupt(this);
35574       g.start();
35575     }
35576
35577     noevent$2();
35578     g.wheel = setTimeout(wheelidled, wheelDelay);
35579     g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent));
35580
35581     function wheelidled() {
35582       g.wheel = null;
35583       g.end();
35584     }
35585   }
35586
35587   function mousedowned() {
35588     if (touchending || !filter.apply(this, arguments)) return;
35589     var g = gesture(this, arguments),
35590         v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
35591         p = mouse(this),
35592         x0 = event.clientX,
35593         y0 = event.clientY;
35594
35595     dragDisable(event.view);
35596     nopropagation$2();
35597     g.mouse = [p, this.__zoom.invert(p)];
35598     interrupt(this);
35599     g.start();
35600
35601     function mousemoved() {
35602       noevent$2();
35603       if (!g.moved) {
35604         var dx = event.clientX - x0, dy = event.clientY - y0;
35605         g.moved = dx * dx + dy * dy > clickDistance2;
35606       }
35607       g.zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = mouse(g.that), g.mouse[1]), g.extent));
35608     }
35609
35610     function mouseupped() {
35611       v.on("mousemove.zoom mouseup.zoom", null);
35612       yesdrag(event.view, g.moved);
35613       noevent$2();
35614       g.end();
35615     }
35616   }
35617
35618   function dblclicked() {
35619     if (!filter.apply(this, arguments)) return;
35620     var t0 = this.__zoom,
35621         p0 = mouse(this),
35622         p1 = t0.invert(p0),
35623         k1 = t0.k * (event.shiftKey ? 0.5 : 2),
35624         t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, arguments));
35625
35626     noevent$2();
35627     if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0);
35628     else select(this).call(zoom.transform, t1);
35629   }
35630
35631   function touchstarted() {
35632     if (!filter.apply(this, arguments)) return;
35633     var g = gesture(this, arguments),
35634         touches$$1 = event.changedTouches,
35635         started,
35636         n = touches$$1.length, i, t, p;
35637
35638     nopropagation$2();
35639     for (i = 0; i < n; ++i) {
35640       t = touches$$1[i], p = touch(this, touches$$1, t.identifier);
35641       p = [p, this.__zoom.invert(p), t.identifier];
35642       if (!g.touch0) g.touch0 = p, started = true;
35643       else if (!g.touch1) g.touch1 = p;
35644     }
35645
35646     // If this is a dbltap, reroute to the (optional) dblclick.zoom handler.
35647     if (touchstarting) {
35648       touchstarting = clearTimeout(touchstarting);
35649       if (!g.touch1) {
35650         g.end();
35651         p = select(this).on("dblclick.zoom");
35652         if (p) p.apply(this, arguments);
35653         return;
35654       }
35655     }
35656
35657     if (started) {
35658       touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay);
35659       interrupt(this);
35660       g.start();
35661     }
35662   }
35663
35664   function touchmoved() {
35665     var g = gesture(this, arguments),
35666         touches$$1 = event.changedTouches,
35667         n = touches$$1.length, i, t, p, l;
35668
35669     noevent$2();
35670     if (touchstarting) touchstarting = clearTimeout(touchstarting);
35671     for (i = 0; i < n; ++i) {
35672       t = touches$$1[i], p = touch(this, touches$$1, t.identifier);
35673       if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p;
35674       else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p;
35675     }
35676     t = g.that.__zoom;
35677     if (g.touch1) {
35678       var p0 = g.touch0[0], l0 = g.touch0[1],
35679           p1 = g.touch1[0], l1 = g.touch1[1],
35680           dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
35681           dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
35682       t = scale(t, Math.sqrt(dp / dl));
35683       p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
35684       l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
35685     }
35686     else if (g.touch0) p = g.touch0[0], l = g.touch0[1];
35687     else return;
35688     g.zoom("touch", constrain(translate(t, p, l), g.extent));
35689   }
35690
35691   function touchended() {
35692     var g = gesture(this, arguments),
35693         touches$$1 = event.changedTouches,
35694         n = touches$$1.length, i, t;
35695
35696     nopropagation$2();
35697     if (touchending) clearTimeout(touchending);
35698     touchending = setTimeout(function() { touchending = null; }, touchDelay);
35699     for (i = 0; i < n; ++i) {
35700       t = touches$$1[i];
35701       if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;
35702       else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
35703     }
35704     if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
35705     if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);
35706     else g.end();
35707   }
35708
35709   zoom.filter = function(_) {
35710     return arguments.length ? (filter = typeof _ === "function" ? _ : constant$12(!!_), zoom) : filter;
35711   };
35712
35713   zoom.extent = function(_) {
35714     return arguments.length ? (extent = typeof _ === "function" ? _ : constant$12([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
35715   };
35716
35717   zoom.scaleExtent = function(_) {
35718     return arguments.length ? (k0 = +_[0], k1 = +_[1], zoom) : [k0, k1];
35719   };
35720
35721   zoom.translateExtent = function(_) {
35722     return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], zoom) : [[x0, y0], [x1, y1]];
35723   };
35724
35725   zoom.duration = function(_) {
35726     return arguments.length ? (duration = +_, zoom) : duration;
35727   };
35728
35729   zoom.interpolate = function(_) {
35730     return arguments.length ? (interpolate = _, zoom) : interpolate;
35731   };
35732
35733   zoom.on = function() {
35734     var value = listeners.on.apply(listeners, arguments);
35735     return value === listeners ? zoom : value;
35736   };
35737
35738   zoom.clickDistance = function(_) {
35739     return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
35740   };
35741     
35742   return zoom;
35743 };
35744
35745
35746
35747 var index$2 = Object.freeze({
35748         version: version,
35749         bisect: bisectRight,
35750         bisectRight: bisectRight,
35751         bisectLeft: bisectLeft,
35752         ascending: ascending,
35753         bisector: bisector,
35754         cross: cross,
35755         descending: descending,
35756         deviation: deviation,
35757         extent: extent,
35758         histogram: histogram,
35759         thresholdFreedmanDiaconis: freedmanDiaconis,
35760         thresholdScott: scott,
35761         thresholdSturges: sturges,
35762         max: max,
35763         mean: mean,
35764         median: median,
35765         merge: merge,
35766         min: min,
35767         pairs: pairs,
35768         permute: permute,
35769         quantile: threshold,
35770         range: sequence,
35771         scan: scan,
35772         shuffle: shuffle,
35773         sum: sum,
35774         ticks: ticks,
35775         tickIncrement: tickIncrement,
35776         tickStep: tickStep,
35777         transpose: transpose,
35778         variance: variance,
35779         zip: zip,
35780         axisTop: axisTop,
35781         axisRight: axisRight,
35782         axisBottom: axisBottom,
35783         axisLeft: axisLeft,
35784         brush: brush,
35785         brushX: brushX,
35786         brushY: brushY,
35787         brushSelection: brushSelection,
35788         chord: chord,
35789         ribbon: ribbon,
35790         nest: nest,
35791         set: set$2,
35792         map: map$1,
35793         keys: keys,
35794         values: values,
35795         entries: entries,
35796         color: color,
35797         rgb: rgb,
35798         hsl: hsl,
35799         lab: lab,
35800         hcl: hcl,
35801         cubehelix: cubehelix,
35802         dispatch: dispatch,
35803         drag: drag,
35804         dragDisable: dragDisable,
35805         dragEnable: yesdrag,
35806         dsvFormat: dsv,
35807         csvParse: csvParse,
35808         csvParseRows: csvParseRows,
35809         csvFormat: csvFormat,
35810         csvFormatRows: csvFormatRows,
35811         tsvParse: tsvParse,
35812         tsvParseRows: tsvParseRows,
35813         tsvFormat: tsvFormat,
35814         tsvFormatRows: tsvFormatRows,
35815         easeLinear: linear$1,
35816         easeQuad: quadInOut,
35817         easeQuadIn: quadIn,
35818         easeQuadOut: quadOut,
35819         easeQuadInOut: quadInOut,
35820         easeCubic: cubicInOut,
35821         easeCubicIn: cubicIn,
35822         easeCubicOut: cubicOut,
35823         easeCubicInOut: cubicInOut,
35824         easePoly: polyInOut,
35825         easePolyIn: polyIn,
35826         easePolyOut: polyOut,
35827         easePolyInOut: polyInOut,
35828         easeSin: sinInOut,
35829         easeSinIn: sinIn,
35830         easeSinOut: sinOut,
35831         easeSinInOut: sinInOut,
35832         easeExp: expInOut,
35833         easeExpIn: expIn,
35834         easeExpOut: expOut,
35835         easeExpInOut: expInOut,
35836         easeCircle: circleInOut,
35837         easeCircleIn: circleIn,
35838         easeCircleOut: circleOut,
35839         easeCircleInOut: circleInOut,
35840         easeBounce: bounceOut,
35841         easeBounceIn: bounceIn,
35842         easeBounceOut: bounceOut,
35843         easeBounceInOut: bounceInOut,
35844         easeBack: backInOut,
35845         easeBackIn: backIn,
35846         easeBackOut: backOut,
35847         easeBackInOut: backInOut,
35848         easeElastic: elasticOut,
35849         easeElasticIn: elasticIn,
35850         easeElasticOut: elasticOut,
35851         easeElasticInOut: elasticInOut,
35852         forceCenter: center$1,
35853         forceCollide: collide,
35854         forceLink: link,
35855         forceManyBody: manyBody,
35856         forceSimulation: simulation,
35857         forceX: x$2,
35858         forceY: y$2,
35859         formatDefaultLocale: defaultLocale,
35860         get format () { return format; },
35861         get formatPrefix () { return formatPrefix; },
35862         formatLocale: formatLocale,
35863         formatSpecifier: formatSpecifier,
35864         precisionFixed: precisionFixed,
35865         precisionPrefix: precisionPrefix,
35866         precisionRound: precisionRound,
35867         geoArea: area,
35868         geoBounds: bounds,
35869         geoCentroid: d3GeoCentroid,
35870         geoCircle: circle,
35871         geoClipExtent: extent$1,
35872         geoContains: contains,
35873         geoDistance: distance,
35874         geoGraticule: graticule,
35875         geoGraticule10: graticule10,
35876         geoInterpolate: interpolate$1,
35877         geoLength: d3GeoLength,
35878         geoPath: index$4,
35879         geoAlbers: albers,
35880         geoAlbersUsa: albersUsa,
35881         geoAzimuthalEqualArea: azimuthalEqualArea,
35882         geoAzimuthalEqualAreaRaw: azimuthalEqualAreaRaw,
35883         geoAzimuthalEquidistant: azimuthalEquidistant,
35884         geoAzimuthalEquidistantRaw: azimuthalEquidistantRaw,
35885         geoConicConformal: conicConformal,
35886         geoConicConformalRaw: conicConformalRaw,
35887         geoConicEqualArea: conicEqualArea,
35888         geoConicEqualAreaRaw: conicEqualAreaRaw,
35889         geoConicEquidistant: conicEquidistant,
35890         geoConicEquidistantRaw: conicEquidistantRaw,
35891         geoEquirectangular: equirectangular,
35892         geoEquirectangularRaw: equirectangularRaw,
35893         geoGnomonic: gnomonic,
35894         geoGnomonicRaw: gnomonicRaw,
35895         geoIdentity: identity$5,
35896         geoProjection: projection,
35897         geoProjectionMutator: projectionMutator,
35898         geoMercator: mercator,
35899         geoMercatorRaw: mercatorRaw,
35900         geoOrthographic: orthographic,
35901         geoOrthographicRaw: orthographicRaw,
35902         geoStereographic: stereographic,
35903         geoStereographicRaw: stereographicRaw,
35904         geoTransverseMercator: transverseMercator,
35905         geoTransverseMercatorRaw: transverseMercatorRaw,
35906         geoRotation: rotation,
35907         geoStream: geoStream,
35908         geoTransform: transform,
35909         cluster: cluster,
35910         hierarchy: hierarchy,
35911         pack: index$5,
35912         packSiblings: siblings,
35913         packEnclose: enclose,
35914         partition: partition,
35915         stratify: stratify,
35916         tree: tree,
35917         treemap: index$6,
35918         treemapBinary: binary,
35919         treemapDice: treemapDice,
35920         treemapSlice: treemapSlice,
35921         treemapSliceDice: sliceDice,
35922         treemapSquarify: squarify,
35923         treemapResquarify: resquarify,
35924         interpolate: interpolateValue,
35925         interpolateArray: array$1,
35926         interpolateBasis: basis$1,
35927         interpolateBasisClosed: basisClosed,
35928         interpolateDate: date,
35929         interpolateNumber: reinterpolate,
35930         interpolateObject: object,
35931         interpolateRound: interpolateRound,
35932         interpolateString: interpolateString,
35933         interpolateTransformCss: interpolateTransformCss,
35934         interpolateTransformSvg: interpolateTransformSvg,
35935         interpolateZoom: interpolateZoom,
35936         interpolateRgb: interpolateRgb,
35937         interpolateRgbBasis: rgbBasis,
35938         interpolateRgbBasisClosed: rgbBasisClosed,
35939         interpolateHsl: hsl$2,
35940         interpolateHslLong: hslLong,
35941         interpolateLab: lab$1,
35942         interpolateHcl: hcl$2,
35943         interpolateHclLong: hclLong,
35944         interpolateCubehelix: cubehelix$2,
35945         interpolateCubehelixLong: cubehelixLong,
35946         quantize: quantize,
35947         path: path,
35948         polygonArea: d3polygonArea,
35949         polygonCentroid: d3polygonCentroid,
35950         polygonHull: d3polygonHull,
35951         polygonContains: contains$1,
35952         polygonLength: length$1,
35953         quadtree: quadtree,
35954         queue: queue,
35955         randomUniform: uniform,
35956         randomNormal: normal,
35957         randomLogNormal: logNormal,
35958         randomBates: bates,
35959         randomIrwinHall: irwinHall,
35960         randomExponential: exponential$1,
35961         request: request,
35962         html: html,
35963         json: json,
35964         text: text,
35965         xml: xml,
35966         csv: csv$1,
35967         tsv: tsv$1,
35968         scaleBand: band,
35969         scalePoint: point$1,
35970         scaleIdentity: identity$6,
35971         scaleLinear: linear$2,
35972         scaleLog: log$1,
35973         scaleOrdinal: ordinal,
35974         scaleImplicit: implicit,
35975         scalePow: pow$1,
35976         scaleSqrt: sqrt$1,
35977         scaleQuantile: quantile,
35978         scaleQuantize: quantize$1,
35979         scaleThreshold: threshold$1,
35980         scaleTime: time,
35981         scaleUtc: utcTime,
35982         schemeCategory10: category10,
35983         schemeCategory20b: category20b,
35984         schemeCategory20c: category20c,
35985         schemeCategory20: category20,
35986         interpolateCubehelixDefault: cubehelix$3,
35987         interpolateRainbow: rainbow$1,
35988         interpolateWarm: warm,
35989         interpolateCool: cool,
35990         interpolateViridis: viridis,
35991         interpolateMagma: magma,
35992         interpolateInferno: inferno,
35993         interpolatePlasma: plasma,
35994         scaleSequential: sequential,
35995         creator: creator,
35996         local: local$1,
35997         matcher: matcher$1,
35998         mouse: mouse,
35999         namespace: namespace,
36000         namespaces: namespaces,
36001         select: select,
36002         selectAll: selectAll,
36003         selection: selection,
36004         selector: selector,
36005         selectorAll: selectorAll,
36006         style: styleValue,
36007         touch: touch,
36008         touches: touches,
36009         window: defaultView,
36010         get event () { return event; },
36011         customEvent: customEvent,
36012         arc: arc,
36013         area: area$1,
36014         line: line,
36015         pie: pie,
36016         radialArea: radialArea,
36017         radialLine: radialLine$1,
36018         linkHorizontal: linkHorizontal,
36019         linkVertical: linkVertical,
36020         linkRadial: linkRadial,
36021         symbol: symbol,
36022         symbols: symbols,
36023         symbolCircle: circle$2,
36024         symbolCross: cross$2,
36025         symbolDiamond: diamond,
36026         symbolSquare: square,
36027         symbolStar: star,
36028         symbolTriangle: triangle,
36029         symbolWye: wye,
36030         curveBasisClosed: basisClosed$1,
36031         curveBasisOpen: basisOpen,
36032         curveBasis: basis$2,
36033         curveBundle: bundle,
36034         curveCardinalClosed: cardinalClosed,
36035         curveCardinalOpen: cardinalOpen,
36036         curveCardinal: cardinal,
36037         curveCatmullRomClosed: catmullRomClosed,
36038         curveCatmullRomOpen: catmullRomOpen,
36039         curveCatmullRom: catmullRom,
36040         curveLinearClosed: linearClosed,
36041         curveLinear: curveLinear,
36042         curveMonotoneX: monotoneX,
36043         curveMonotoneY: monotoneY,
36044         curveNatural: natural,
36045         curveStep: step,
36046         curveStepAfter: stepAfter,
36047         curveStepBefore: stepBefore,
36048         stack: stack,
36049         stackOffsetExpand: expand,
36050         stackOffsetDiverging: diverging,
36051         stackOffsetNone: none$1,
36052         stackOffsetSilhouette: silhouette,
36053         stackOffsetWiggle: wiggle,
36054         stackOrderAscending: ascending$2,
36055         stackOrderDescending: descending$2,
36056         stackOrderInsideOut: insideOut,
36057         stackOrderNone: none$2,
36058         stackOrderReverse: reverse,
36059         timeInterval: newInterval,
36060         timeMillisecond: millisecond,
36061         timeMilliseconds: milliseconds,
36062         utcMillisecond: millisecond,
36063         utcMilliseconds: milliseconds,
36064         timeSecond: second,
36065         timeSeconds: seconds,
36066         utcSecond: second,
36067         utcSeconds: seconds,
36068         timeMinute: minute,
36069         timeMinutes: minutes,
36070         timeHour: hour,
36071         timeHours: hours,
36072         timeDay: day,
36073         timeDays: days,
36074         timeWeek: sunday,
36075         timeWeeks: sundays,
36076         timeSunday: sunday,
36077         timeSundays: sundays,
36078         timeMonday: monday,
36079         timeMondays: mondays,
36080         timeTuesday: tuesday,
36081         timeTuesdays: tuesdays,
36082         timeWednesday: wednesday,
36083         timeWednesdays: wednesdays,
36084         timeThursday: thursday,
36085         timeThursdays: thursdays,
36086         timeFriday: friday,
36087         timeFridays: fridays,
36088         timeSaturday: saturday,
36089         timeSaturdays: saturdays,
36090         timeMonth: month,
36091         timeMonths: months,
36092         timeYear: year,
36093         timeYears: years,
36094         utcMinute: utcMinute,
36095         utcMinutes: utcMinutes,
36096         utcHour: utcHour,
36097         utcHours: utcHours,
36098         utcDay: utcDay,
36099         utcDays: utcDays,
36100         utcWeek: utcSunday,
36101         utcWeeks: utcSundays,
36102         utcSunday: utcSunday,
36103         utcSundays: utcSundays,
36104         utcMonday: utcMonday,
36105         utcMondays: utcMondays,
36106         utcTuesday: utcTuesday,
36107         utcTuesdays: utcTuesdays,
36108         utcWednesday: utcWednesday,
36109         utcWednesdays: utcWednesdays,
36110         utcThursday: utcThursday,
36111         utcThursdays: utcThursdays,
36112         utcFriday: utcFriday,
36113         utcFridays: utcFridays,
36114         utcSaturday: utcSaturday,
36115         utcSaturdays: utcSaturdays,
36116         utcMonth: utcMonth,
36117         utcMonths: utcMonths,
36118         utcYear: utcYear,
36119         utcYears: utcYears,
36120         timeFormatDefaultLocale: defaultLocale$1,
36121         get timeFormat () { return timeFormat; },
36122         get timeParse () { return timeParse; },
36123         get utcFormat () { return utcFormat; },
36124         get utcParse () { return utcParse; },
36125         timeFormatLocale: formatLocale$1,
36126         isoFormat: formatIso,
36127         isoParse: parseIso,
36128         now: now,
36129         timer: timer,
36130         timerFlush: timerFlush,
36131         timeout: timeout$1,
36132         interval: interval$1,
36133         transition: transition,
36134         active: active,
36135         interrupt: interrupt,
36136         voronoi: voronoi,
36137         zoom: zoom,
36138         zoomTransform: transform$1,
36139         zoomIdentity: identity$8
36140 });
36141
36142 /*
36143     Bypasses features of D3's default projection stream pipeline that are unnecessary:
36144     * Antimeridian clipping
36145     * Spherical rotation
36146     * Resampling
36147 */
36148 function geoRawMercator() {
36149     var project = mercatorRaw,
36150         k = 512 / Math.PI, // scale
36151         x = 0, y = 0, // translate
36152         clipExtent = [[0, 0], [0, 0]];
36153
36154
36155     function projection$$1(point) {
36156         point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
36157         return [point[0] * k + x, y - point[1] * k];
36158     }
36159
36160
36161     projection$$1.invert = function(point) {
36162         point = project.invert((point[0] - x) / k, (y - point[1]) / k);
36163         return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
36164     };
36165
36166
36167     projection$$1.scale = function(_) {
36168         if (!arguments.length) return k;
36169         k = +_;
36170         return projection$$1;
36171     };
36172
36173
36174     projection$$1.translate = function(_) {
36175         if (!arguments.length) return [x, y];
36176         x = +_[0];
36177         y = +_[1];
36178         return projection$$1;
36179     };
36180
36181
36182     projection$$1.clipExtent = function(_) {
36183         if (!arguments.length) return clipExtent;
36184         clipExtent = _;
36185         return projection$$1;
36186     };
36187
36188
36189     projection$$1.transform = function(_) {
36190         if (!arguments.length) return identity$8.translate(x, y).scale(k);
36191         x = +_.x;
36192         y = +_.y;
36193         k = +_.k;
36194         return projection$$1;
36195     };
36196
36197
36198     projection$$1.stream = transform({
36199         point: function(x, y) {
36200             x = projection$$1([x, y]);
36201             this.stream.point(x[0], x[1]);
36202         }
36203     }).stream;
36204
36205
36206     return projection$$1;
36207 }
36208
36209 function osmChangeset() {
36210     if (!(this instanceof osmChangeset)) {
36211         return (new osmChangeset()).initialize(arguments);
36212     } else if (arguments.length) {
36213         this.initialize(arguments);
36214     }
36215 }
36216
36217
36218 osmEntity$$1.changeset = osmChangeset;
36219
36220 osmChangeset.prototype = Object.create(osmEntity$$1.prototype);
36221
36222 lodash.extend(osmChangeset.prototype, {
36223
36224     type: 'changeset',
36225
36226
36227     extent: function() {
36228         return new geoExtent$$1();
36229     },
36230
36231
36232     geometry: function() {
36233         return 'changeset';
36234     },
36235
36236
36237     asJXON: function() {
36238         return {
36239             osm: {
36240                 changeset: {
36241                     tag: lodash.map(this.tags, function(value, key) {
36242                         return { '@k': key, '@v': value };
36243                     }),
36244                     '@version': 0.6,
36245                     '@generator': 'iD'
36246                 }
36247             }
36248         };
36249     },
36250
36251
36252     // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
36253     // XML. Returns a string.
36254     osmChangeJXON: function(changes) {
36255         var changeset_id = this.id;
36256
36257         function nest(x, order) {
36258             var groups = {};
36259             for (var i = 0; i < x.length; i++) {
36260                 var tagName = Object.keys(x[i])[0];
36261                 if (!groups[tagName]) groups[tagName] = [];
36262                 groups[tagName].push(x[i][tagName]);
36263             }
36264             var ordered = {};
36265             order.forEach(function(o) {
36266                 if (groups[o]) ordered[o] = groups[o];
36267             });
36268             return ordered;
36269         }
36270
36271
36272         // sort relations in a changeset by dependencies
36273         function sort(changes) {
36274
36275             // find a referenced relation in the current changeset
36276             function resolve(item) {
36277                 return lodash.find(relations, function(relation) {
36278                     return item.keyAttributes.type === 'relation'
36279                         && item.keyAttributes.ref === relation['@id'];
36280                 });
36281             }
36282
36283             // a new item is an item that has not been already processed
36284             function isNew(item) {
36285                 return !sorted[ item['@id'] ] && !lodash.find(processing, function(proc) {
36286                     return proc['@id'] === item['@id'];
36287                 });
36288             }
36289
36290             var processing = [],
36291                 sorted = {},
36292                 relations = changes.relation;
36293
36294             if (!relations) return changes;
36295
36296             for (var i = 0; i < relations.length; i++) {
36297                 var relation = relations[i];
36298
36299                 // skip relation if already sorted
36300                 if (!sorted[relation['@id']]) {
36301                     processing.push(relation);
36302                 }
36303
36304                 while (processing.length > 0) {
36305                     var next = processing[0],
36306                     deps = lodash.filter(lodash.compact(next.member.map(resolve)), isNew);
36307                     if (deps.length === 0) {
36308                         sorted[next['@id']] = next;
36309                         processing.shift();
36310                     } else {
36311                         processing = deps.concat(processing);
36312                     }
36313                 }
36314             }
36315
36316             changes.relation = lodash.values(sorted);
36317             return changes;
36318         }
36319
36320         function rep(entity) {
36321             return entity.asJXON(changeset_id);
36322         }
36323
36324         return {
36325             osmChange: {
36326                 '@version': 0.6,
36327                 '@generator': 'iD',
36328                 'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
36329                 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
36330                 'delete': lodash.extend(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), { '@if-unused': true })
36331             }
36332         };
36333     },
36334
36335
36336     asGeoJSON: function() {
36337         return {};
36338     }
36339
36340 });
36341
36342 function osmNode() {
36343     if (!(this instanceof osmNode)) {
36344         return (new osmNode()).initialize(arguments);
36345     } else if (arguments.length) {
36346         this.initialize(arguments);
36347     }
36348 }
36349
36350 osmEntity$$1.node = osmNode;
36351
36352 osmNode.prototype = Object.create(osmEntity$$1.prototype);
36353
36354 lodash.extend(osmNode.prototype, {
36355
36356     type: 'node',
36357
36358
36359     extent: function() {
36360         return new geoExtent$$1(this.loc);
36361     },
36362
36363
36364     geometry: function(graph) {
36365         return graph.transient(this, 'geometry', function() {
36366             return graph.isPoi(this) ? 'point' : 'vertex';
36367         });
36368     },
36369
36370
36371     move: function(loc) {
36372         return this.update({loc: loc});
36373     },
36374
36375
36376     isDegenerate: function() {
36377         return !(
36378             Array.isArray(this.loc) && this.loc.length === 2 &&
36379             this.loc[0] >= -180 && this.loc[0] <= 180 &&
36380             this.loc[1] >= -90 && this.loc[1] <= 90
36381         );
36382     },
36383
36384
36385     isEndpoint: function(resolver) {
36386         return resolver.transient(this, 'isEndpoint', function() {
36387             var id = this.id;
36388             return resolver.parentWays(this).filter(function(parent) {
36389                 return !parent.isClosed() && !!parent.affix(id);
36390             }).length > 0;
36391         });
36392     },
36393
36394
36395     isConnected: function(resolver) {
36396         return resolver.transient(this, 'isConnected', function() {
36397             var parents = resolver.parentWays(this);
36398
36399             function isLine(entity) {
36400                 return entity.geometry(resolver) === 'line' &&
36401                     entity.hasInterestingTags();
36402             }
36403
36404             // vertex is connected to multiple parent lines
36405             if (parents.length > 1 && lodash.some(parents, isLine)) {
36406                 return true;
36407
36408             } else if (parents.length === 1) {
36409                 var way = parents[0],
36410                     nodes = way.nodes.slice();
36411                 if (way.isClosed()) { nodes.pop(); }  // ignore connecting node if closed
36412
36413                 // return true if vertex appears multiple times (way is self intersecting)
36414                 return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
36415             }
36416
36417             return false;
36418         });
36419     },
36420
36421
36422     isIntersection: function(resolver) {
36423         return resolver.transient(this, 'isIntersection', function() {
36424             return resolver.parentWays(this).filter(function(parent) {
36425                 return (parent.tags.highway ||
36426                     parent.tags.waterway ||
36427                     parent.tags.railway ||
36428                     parent.tags.aeroway) &&
36429                     parent.geometry(resolver) === 'line';
36430             }).length > 1;
36431         });
36432     },
36433
36434
36435     isHighwayIntersection: function(resolver) {
36436         return resolver.transient(this, 'isHighwayIntersection', function() {
36437             return resolver.parentWays(this).filter(function(parent) {
36438                 return parent.tags.highway && parent.geometry(resolver) === 'line';
36439             }).length > 1;
36440         });
36441     },
36442
36443
36444     isOnAddressLine: function(resolver) {
36445         return resolver.transient(this, 'isOnAddressLine', function() {
36446             return resolver.parentWays(this).filter(function(parent) {
36447                 return parent.tags.hasOwnProperty('addr:interpolation') &&
36448                     parent.geometry(resolver) === 'line';
36449             }).length > 0;
36450         });
36451     },
36452
36453
36454     asJXON: function(changeset_id) {
36455         var r = {
36456             node: {
36457                 '@id': this.osmId(),
36458                 '@lon': this.loc[0],
36459                 '@lat': this.loc[1],
36460                 '@version': (this.version || 0),
36461                 tag: lodash.map(this.tags, function(v, k) {
36462                     return { keyAttributes: { k: k, v: v } };
36463                 })
36464             }
36465         };
36466         if (changeset_id) r.node['@changeset'] = changeset_id;
36467         return r;
36468     },
36469
36470
36471     asGeoJSON: function() {
36472         return {
36473             type: 'Point',
36474             coordinates: this.loc
36475         };
36476     }
36477 });
36478
36479 /*
36480   Order the nodes of a way in reverse order and reverse any direction dependent tags
36481   other than `oneway`. (We assume that correcting a backwards oneway is the primary
36482   reason for reversing a way.)
36483
36484   The following transforms are performed:
36485
36486     Keys:
36487           *:right=* ⟺ *:left=*
36488         *:forward=* ⟺ *:backward=*
36489        direction=up ⟺ direction=down
36490          incline=up ⟺ incline=down
36491             *=right ⟺ *=left
36492
36493     Relation members:
36494        role=forward ⟺ role=backward
36495          role=north ⟺ role=south
36496           role=east ⟺ role=west
36497
36498    In addition, numeric-valued `incline` tags are negated.
36499
36500    The JOSM implementation was used as a guide, but transformations that were of unclear benefit
36501    or adjusted tags that don't seem to be used in practice were omitted.
36502
36503    Also, each node on the way is examined for its own tags and the following transformations are performed
36504    in order to ensure associated nodes (eg a Stop Sign) is also reversed
36505
36506     Node Keys:
36507         direction=forward ⟺ direction=backward
36508         direction=left ⟺ direction=right
36509         *:forward=* ⟺ *:backward=*
36510         *:left=* ⟺ *:right=*
36511
36512    References:
36513       http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
36514       http://wiki.openstreetmap.org/wiki/Key:direction#Steps
36515       http://wiki.openstreetmap.org/wiki/Key:incline
36516       http://wiki.openstreetmap.org/wiki/Route#Members
36517       http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
36518       http://wiki.openstreetmap.org/wiki/Tag:highway%3Dstop
36519       http://wiki.openstreetmap.org/wiki/Key:traffic_sign#On_a_way_or_area
36520  */
36521 function actionReverse(wayId, options) {
36522     var replacements = [
36523             [/:right$/, ':left'], [/:left$/, ':right'],
36524             [/:forward$/, ':backward'], [/:backward$/, ':forward']
36525         ],
36526         numeric = /^([+\-]?)(?=[\d.])/,
36527         roleReversals = {
36528             forward: 'backward',
36529             backward: 'forward',
36530             north: 'south',
36531             south: 'north',
36532             east: 'west',
36533             west: 'east'
36534         };
36535
36536
36537     function reverseKey(key) {
36538         for (var i = 0; i < replacements.length; ++i) {
36539             var replacement = replacements[i];
36540             if (replacement[0].test(key)) {
36541                 return key.replace(replacement[0], replacement[1]);
36542             }
36543         }
36544         return key;
36545     }
36546
36547
36548     function reverseValue(key, value) {
36549         if (key === 'incline' && numeric.test(value)) {
36550             return value.replace(numeric, function(_, sign) { return sign === '-' ? '' : '-'; });
36551         } else if (key === 'incline' || key === 'direction') {
36552             return {up: 'down', down: 'up'}[value] || value;
36553         } else if (options && options.reverseOneway && key === 'oneway') {
36554             return {yes: '-1', '1': '-1', '-1': 'yes'}[value] || value;
36555         } else {
36556             return {left: 'right', right: 'left'}[value] || value;
36557         }
36558     }
36559
36560
36561     function reverseDirectionTags(node) {
36562         // Update the direction based tags as appropriate then return an updated node
36563         return node.update({tags: lodash.transform(node.tags, function(acc, tagValue, tagKey) {
36564             // See if this is a direction tag and reverse (or use existing value if not recognised)
36565             if (tagKey === 'direction') {
36566                 acc[tagKey] = {forward: 'backward', backward: 'forward', left: 'right', right: 'left'}[tagValue] || tagValue;
36567             } else {
36568                 // Use the reverseKey method to cater for situations such as traffic_sign:forward=stop
36569                 // This will pass through other tags unchanged
36570                 acc[reverseKey(tagKey)] = tagValue;
36571             }
36572             return acc;
36573         }, {})});
36574     }
36575
36576
36577     function reverseTagsOnNodes(graph, nodeIds) {
36578         // Reverse the direction of appropriate tags attached to the nodes (#3076)
36579         return lodash(nodeIds)
36580             // Get each node from the graph
36581             .map(function(nodeId) { return graph.entity(nodeId);})
36582             // Check tags on the node, if there aren't any, we can skip
36583             .filter(function(existingNode) { return existingNode.tags !== undefined;})
36584             // Get a new version of each node with the appropriate tags reversed
36585             .map(function(existingNode) { return reverseDirectionTags(existingNode);})
36586             // Chain together consecutive updates to the graph for each updated node and return
36587             .reduce(function (accGraph, value) { return accGraph.replace(value); }, graph);
36588     }
36589
36590
36591     return function(graph) {
36592         var way = graph.entity(wayId),
36593             nodes = way.nodes.slice().reverse(),
36594             tags = {}, key, role;
36595
36596         for (key in way.tags) {
36597             tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
36598         }
36599
36600         graph.parentRelations(way).forEach(function(relation) {
36601             relation.members.forEach(function(member, index) {
36602                 if (member.id === way.id && (role = roleReversals[member.role])) {
36603                     relation = relation.updateMember({role: role}, index);
36604                     graph = graph.replace(relation);
36605                 }
36606             });
36607         });
36608
36609         // Reverse any associated directions on nodes on the way and then replace
36610         // the way itself with the reversed node ids and updated way tags
36611         return reverseTagsOnNodes(graph, nodes).replace(way.update({nodes: nodes, tags: tags}));
36612     };
36613 }
36614
36615 // For fixing up rendering of multipolygons with tags on the outer member.
36616 // https://github.com/openstreetmap/iD/issues/613
36617 function osmIsSimpleMultipolygonOuterMember(entity, graph) {
36618     if (entity.type !== 'way' || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0)
36619         return false;
36620
36621     var parents = graph.parentRelations(entity);
36622     if (parents.length !== 1)
36623         return false;
36624
36625     var parent = parents[0];
36626     if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1)
36627         return false;
36628
36629     var members = parent.members, member;
36630     for (var i = 0; i < members.length; i++) {
36631         member = members[i];
36632         if (member.id === entity.id && member.role && member.role !== 'outer')
36633             return false; // Not outer member
36634         if (member.id !== entity.id && (!member.role || member.role === 'outer'))
36635             return false; // Not a simple multipolygon
36636     }
36637
36638     return parent;
36639 }
36640
36641
36642 function osmSimpleMultipolygonOuterMember(entity, graph) {
36643     if (entity.type !== 'way')
36644         return false;
36645
36646     var parents = graph.parentRelations(entity);
36647     if (parents.length !== 1)
36648         return false;
36649
36650     var parent = parents[0];
36651     if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1)
36652         return false;
36653
36654     var members = parent.members, member, outerMember;
36655     for (var i = 0; i < members.length; i++) {
36656         member = members[i];
36657         if (!member.role || member.role === 'outer') {
36658             if (outerMember)
36659                 return false; // Not a simple multipolygon
36660             outerMember = member;
36661         }
36662     }
36663
36664     if (!outerMember)
36665         return false;
36666
36667     var outerEntity = graph.hasEntity(outerMember.id);
36668     if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length)
36669         return false;
36670
36671     return outerEntity;
36672 }
36673
36674
36675 // Join `array` into sequences of connecting ways.
36676 //
36677 // Segments which share identical start/end nodes will, as much as possible,
36678 // be connected with each other.
36679 //
36680 // The return value is a nested array. Each constituent array contains elements
36681 // of `array` which have been determined to connect. Each consitituent array
36682 // also has a `nodes` property whose value is an ordered array of member nodes,
36683 // with appropriate order reversal and start/end coordinate de-duplication.
36684 //
36685 // Members of `array` must have, at minimum, `type` and `id` properties.
36686 // Thus either an array of `osmWay`s or a relation member array may be
36687 // used.
36688 //
36689 // If an member has a `tags` property, its tags will be reversed via
36690 // `actionReverse` in the output.
36691 //
36692 // Incomplete members (those for which `graph.hasEntity(element.id)` returns
36693 // false) and non-way members are ignored.
36694 //
36695 function osmJoinWays(array, graph) {
36696     var joined = [], member, current, nodes, first, last, i, how, what;
36697
36698     array = array.filter(function(member) {
36699         return member.type === 'way' && graph.hasEntity(member.id);
36700     });
36701
36702     function resolve(member) {
36703         return graph.childNodes(graph.entity(member.id));
36704     }
36705
36706     function reverse(member) {
36707         return member.tags ? actionReverse(member.id, { reverseOneway: true })(graph).entity(member.id) : member;
36708     }
36709
36710     while (array.length) {
36711         member = array.shift();
36712         current = [member];
36713         current.nodes = nodes = resolve(member).slice();
36714         joined.push(current);
36715
36716         while (array.length && lodash.first(nodes) !== lodash.last(nodes)) {
36717             first = lodash.first(nodes);
36718             last  = lodash.last(nodes);
36719
36720             for (i = 0; i < array.length; i++) {
36721                 member = array[i];
36722                 what = resolve(member);
36723
36724                 if (last === lodash.first(what)) {
36725                     how  = nodes.push;
36726                     what = what.slice(1);
36727                     break;
36728                 } else if (last === lodash.last(what)) {
36729                     how  = nodes.push;
36730                     what = what.slice(0, -1).reverse();
36731                     member = reverse(member);
36732                     break;
36733                 } else if (first === lodash.last(what)) {
36734                     how  = nodes.unshift;
36735                     what = what.slice(0, -1);
36736                     break;
36737                 } else if (first === lodash.first(what)) {
36738                     how  = nodes.unshift;
36739                     what = what.slice(1).reverse();
36740                     member = reverse(member);
36741                     break;
36742                 } else {
36743                     what = how = null;
36744                 }
36745             }
36746
36747             if (!what)
36748                 break; // No more joinable ways.
36749
36750             how.apply(current, [member]);
36751             how.apply(nodes, what);
36752
36753             array.splice(i, 1);
36754         }
36755     }
36756
36757     return joined;
36758 }
36759
36760 function osmRelation() {
36761     if (!(this instanceof osmRelation)) {
36762         return (new osmRelation()).initialize(arguments);
36763     } else if (arguments.length) {
36764         this.initialize(arguments);
36765     }
36766 }
36767
36768
36769 osmEntity$$1.relation = osmRelation;
36770
36771 osmRelation.prototype = Object.create(osmEntity$$1.prototype);
36772
36773
36774 osmRelation.creationOrder = function(a, b) {
36775     var aId = parseInt(osmEntity$$1.id.toOSM(a.id), 10);
36776     var bId = parseInt(osmEntity$$1.id.toOSM(b.id), 10);
36777
36778     if (aId < 0 || bId < 0) return aId - bId;
36779     return bId - aId;
36780 };
36781
36782
36783 lodash.extend(osmRelation.prototype, {
36784     type: 'relation',
36785     members: [],
36786
36787
36788     copy: function(resolver, copies) {
36789         if (copies[this.id])
36790             return copies[this.id];
36791
36792         var copy = osmEntity$$1.prototype.copy.call(this, resolver, copies);
36793
36794         var members = this.members.map(function(member) {
36795             return lodash.extend({}, member, { id: resolver.entity(member.id).copy(resolver, copies).id });
36796         });
36797
36798         copy = copy.update({members: members});
36799         copies[this.id] = copy;
36800
36801         return copy;
36802     },
36803
36804
36805     extent: function(resolver, memo) {
36806         return resolver.transient(this, 'extent', function() {
36807             if (memo && memo[this.id]) return geoExtent$$1();
36808             memo = memo || {};
36809             memo[this.id] = true;
36810
36811             var extent$$1 = geoExtent$$1();
36812             for (var i = 0; i < this.members.length; i++) {
36813                 var member = resolver.hasEntity(this.members[i].id);
36814                 if (member) {
36815                     extent$$1._extend(member.extent(resolver, memo));
36816                 }
36817             }
36818             return extent$$1;
36819         });
36820     },
36821
36822
36823     geometry: function(graph) {
36824         return graph.transient(this, 'geometry', function() {
36825             return this.isMultipolygon() ? 'area' : 'relation';
36826         });
36827     },
36828
36829
36830     isDegenerate: function() {
36831         return this.members.length === 0;
36832     },
36833
36834
36835     // Return an array of members, each extended with an 'index' property whose value
36836     // is the member index.
36837     indexedMembers: function() {
36838         var result = new Array(this.members.length);
36839         for (var i = 0; i < this.members.length; i++) {
36840             result[i] = lodash.extend({}, this.members[i], {index: i});
36841         }
36842         return result;
36843     },
36844
36845
36846     // Return the first member with the given role. A copy of the member object
36847     // is returned, extended with an 'index' property whose value is the member index.
36848     memberByRole: function(role) {
36849         for (var i = 0; i < this.members.length; i++) {
36850             if (this.members[i].role === role) {
36851                 return lodash.extend({}, this.members[i], {index: i});
36852             }
36853         }
36854     },
36855
36856
36857     // Return the first member with the given id. A copy of the member object
36858     // is returned, extended with an 'index' property whose value is the member index.
36859     memberById: function(id) {
36860         for (var i = 0; i < this.members.length; i++) {
36861             if (this.members[i].id === id) {
36862                 return lodash.extend({}, this.members[i], {index: i});
36863             }
36864         }
36865     },
36866
36867
36868     // Return the first member with the given id and role. A copy of the member object
36869     // is returned, extended with an 'index' property whose value is the member index.
36870     memberByIdAndRole: function(id, role) {
36871         for (var i = 0; i < this.members.length; i++) {
36872             if (this.members[i].id === id && this.members[i].role === role) {
36873                 return lodash.extend({}, this.members[i], {index: i});
36874             }
36875         }
36876     },
36877
36878
36879     addMember: function(member, index) {
36880         var members = this.members.slice();
36881         members.splice(index === undefined ? members.length : index, 0, member);
36882         return this.update({members: members});
36883     },
36884
36885
36886     updateMember: function(member, index) {
36887         var members = this.members.slice();
36888         members.splice(index, 1, lodash.extend({}, members[index], member));
36889         return this.update({members: members});
36890     },
36891
36892
36893     removeMember: function(index) {
36894         var members = this.members.slice();
36895         members.splice(index, 1);
36896         return this.update({members: members});
36897     },
36898
36899
36900     removeMembersWithID: function(id) {
36901         var members = lodash.reject(this.members, function(m) { return m.id === id; });
36902         return this.update({members: members});
36903     },
36904
36905
36906     // Wherever a member appears with id `needle.id`, replace it with a member
36907     // with id `replacement.id`, type `replacement.type`, and the original role,
36908     // unless a member already exists with that id and role. Return an updated
36909     // relation.
36910     replaceMember: function(needle, replacement) {
36911         if (!this.memberById(needle.id))
36912             return this;
36913
36914         var members = [];
36915
36916         for (var i = 0; i < this.members.length; i++) {
36917             var member = this.members[i];
36918             if (member.id !== needle.id) {
36919                 members.push(member);
36920             } else if (!this.memberByIdAndRole(replacement.id, member.role)) {
36921                 members.push({id: replacement.id, type: replacement.type, role: member.role});
36922             }
36923         }
36924
36925         return this.update({members: members});
36926     },
36927
36928
36929     asJXON: function(changeset_id) {
36930         var r = {
36931             relation: {
36932                 '@id': this.osmId(),
36933                 '@version': this.version || 0,
36934                 member: lodash.map(this.members, function(member) {
36935                     return {
36936                         keyAttributes: {
36937                             type: member.type,
36938                             role: member.role,
36939                             ref: osmEntity$$1.id.toOSM(member.id)
36940                         }
36941                     };
36942                 }),
36943                 tag: lodash.map(this.tags, function(v, k) {
36944                     return { keyAttributes: { k: k, v: v } };
36945                 })
36946             }
36947         };
36948         if (changeset_id) r.relation['@changeset'] = changeset_id;
36949         return r;
36950     },
36951
36952
36953     asGeoJSON: function(resolver) {
36954         return resolver.transient(this, 'GeoJSON', function () {
36955             if (this.isMultipolygon()) {
36956                 return {
36957                     type: 'MultiPolygon',
36958                     coordinates: this.multipolygon(resolver)
36959                 };
36960             } else {
36961                 return {
36962                     type: 'FeatureCollection',
36963                     properties: this.tags,
36964                     features: this.members.map(function (member) {
36965                         return lodash.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
36966                     })
36967                 };
36968             }
36969         });
36970     },
36971
36972
36973     area: function(resolver) {
36974         return resolver.transient(this, 'area', function() {
36975             return area(this.asGeoJSON(resolver));
36976         });
36977     },
36978
36979
36980     isMultipolygon: function() {
36981         return this.tags.type === 'multipolygon';
36982     },
36983
36984
36985     isComplete: function(resolver) {
36986         for (var i = 0; i < this.members.length; i++) {
36987             if (!resolver.hasEntity(this.members[i].id)) {
36988                 return false;
36989             }
36990         }
36991         return true;
36992     },
36993
36994
36995     isRestriction: function() {
36996         return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
36997     },
36998
36999
37000     // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
37001     // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
37002     //
37003     // This corresponds to the structure needed for rendering a multipolygon path using a
37004     // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
37005     //
37006     // In the case of invalid geometries, this function will still return a result which
37007     // includes the nodes of all way members, but some Nds may be unclosed and some inner
37008     // rings not matched with the intended outer ring.
37009     //
37010     multipolygon: function(resolver) {
37011         var outers = this.members.filter(function(m) { return 'outer' === (m.role || 'outer'); }),
37012             inners = this.members.filter(function(m) { return 'inner' === m.role; });
37013
37014         outers = osmJoinWays(outers, resolver);
37015         inners = osmJoinWays(inners, resolver);
37016
37017         outers = outers.map(function(outer) { return lodash.map(outer.nodes, 'loc'); });
37018         inners = inners.map(function(inner) { return lodash.map(inner.nodes, 'loc'); });
37019
37020         var result = outers.map(function(o) {
37021             // Heuristic for detecting counterclockwise winding order. Assumes
37022             // that OpenStreetMap polygons are not hemisphere-spanning.
37023             return [area({ type: 'Polygon', coordinates: [o] }) > 2 * Math.PI ? o.reverse() : o];
37024         });
37025
37026         function findOuter(inner) {
37027             var o, outer;
37028
37029             for (o = 0; o < outers.length; o++) {
37030                 outer = outers[o];
37031                 if (geoPolygonContainsPolygon(outer, inner))
37032                     return o;
37033             }
37034
37035             for (o = 0; o < outers.length; o++) {
37036                 outer = outers[o];
37037                 if (geoPolygonIntersectsPolygon(outer, inner, false))
37038                     return o;
37039             }
37040         }
37041
37042         for (var i = 0; i < inners.length; i++) {
37043             var inner = inners[i];
37044
37045             if (area({ type: 'Polygon', coordinates: [inner] }) < 2 * Math.PI) {
37046                 inner = inner.reverse();
37047             }
37048
37049             var o = findOuter(inners[i]);
37050             if (o !== undefined)
37051                 result[o].push(inners[i]);
37052             else
37053                 result.push([inners[i]]); // Invalid geometry
37054         }
37055
37056         return result;
37057     }
37058 });
37059
37060 function osmLanes(entity) {
37061     if (entity.type !== 'way') return null;
37062     if (!entity.tags.highway) return null;
37063
37064     var tags = entity.tags;
37065     var isOneWay = entity.isOneWay();
37066     var laneCount = getLaneCount(tags, isOneWay);
37067     var maxspeed = parseMaxspeed(tags);
37068
37069     var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
37070     var forward = laneDirections.forward;
37071     var backward = laneDirections.backward;
37072     var bothways = laneDirections.bothways;
37073
37074     // parse the piped string 'x|y|z' format
37075     var turnLanes = {};
37076     turnLanes.unspecified = parseTurnLanes(tags['turn:lanes']);
37077     turnLanes.forward = parseTurnLanes(tags['turn:lanes:forward']);
37078     turnLanes.backward = parseTurnLanes(tags['turn:lanes:backward']);
37079
37080     var maxspeedLanes = {};
37081     maxspeedLanes.unspecified = parseMaxspeedLanes(tags['maxspeed:lanes'], maxspeed);
37082     maxspeedLanes.forward = parseMaxspeedLanes(tags['maxspeed:lanes:forward'], maxspeed);
37083     maxspeedLanes.backward = parseMaxspeedLanes(tags['maxspeed:lanes:backward'], maxspeed);
37084
37085     var psvLanes = {};
37086     psvLanes.unspecified = parseMiscLanes(tags['psv:lanes']);
37087     psvLanes.forward = parseMiscLanes(tags['psv:lanes:forward']);
37088     psvLanes.backward = parseMiscLanes(tags['psv:lanes:backward']);
37089
37090     var busLanes = {};
37091     busLanes.unspecified = parseMiscLanes(tags['bus:lanes']);
37092     busLanes.forward = parseMiscLanes(tags['bus:lanes:forward']);
37093     busLanes.backward = parseMiscLanes(tags['bus:lanes:backward']);
37094
37095     var taxiLanes = {};
37096     taxiLanes.unspecified = parseMiscLanes(tags['taxi:lanes']);
37097     taxiLanes.forward = parseMiscLanes(tags['taxi:lanes:forward']);
37098     taxiLanes.backward = parseMiscLanes(tags['taxi:lanes:backward']);
37099
37100     var hovLanes = {};
37101     hovLanes.unspecified = parseMiscLanes(tags['hov:lanes']);
37102     hovLanes.forward = parseMiscLanes(tags['hov:lanes:forward']);
37103     hovLanes.backward = parseMiscLanes(tags['hov:lanes:backward']);
37104
37105     var hgvLanes = {};
37106     hgvLanes.unspecified = parseMiscLanes(tags['hgv:lanes']);
37107     hgvLanes.forward = parseMiscLanes(tags['hgv:lanes:forward']);
37108     hgvLanes.backward = parseMiscLanes(tags['hgv:lanes:backward']);
37109
37110     var bicyclewayLanes = {};
37111     bicyclewayLanes.unspecified = parseBicycleWay(tags['bicycleway:lanes']);
37112     bicyclewayLanes.forward = parseBicycleWay(tags['bicycleway:lanes:forward']);
37113     bicyclewayLanes.backward = parseBicycleWay(tags['bicycleway:lanes:backward']);
37114
37115     var lanesObj = {
37116         forward: [],
37117         backward: [],
37118         unspecified: []
37119     };
37120
37121     // map forward/backward/unspecified of each lane type to lanesObj
37122     mapToLanesObj(lanesObj, turnLanes, 'turnLane');
37123     mapToLanesObj(lanesObj, maxspeedLanes, 'maxspeed');
37124     mapToLanesObj(lanesObj, psvLanes, 'psv');
37125     mapToLanesObj(lanesObj, busLanes, 'bus');
37126     mapToLanesObj(lanesObj, taxiLanes, 'taxi');
37127     mapToLanesObj(lanesObj, hovLanes, 'hov');
37128     mapToLanesObj(lanesObj, hgvLanes, 'hgv');
37129     mapToLanesObj(lanesObj, bicyclewayLanes, 'bicycleway');
37130
37131     return {
37132         metadata: {
37133             count: laneCount,
37134             oneway: isOneWay,
37135             forward: forward,
37136             backward: backward,
37137             bothways: bothways,
37138             turnLanes: turnLanes,
37139             maxspeed: maxspeed,
37140             maxspeedLanes: maxspeedLanes,
37141             psvLanes: psvLanes,
37142             busLanes: busLanes,
37143             taxiLanes: taxiLanes,
37144             hovLanes: hovLanes,
37145             hgvLanes: hgvLanes,
37146             bicyclewayLanes: bicyclewayLanes
37147         },
37148         lanes: lanesObj
37149     };
37150 }
37151
37152
37153 function getLaneCount(tags, isOneWay) {
37154     var count;
37155     if (tags.lanes) {
37156         count = parseInt(tags.lanes, 10);
37157         if (count > 0) {
37158             return count;
37159         }
37160     }
37161
37162
37163     switch (tags.highway) {
37164         case 'trunk':
37165         case 'motorway':
37166             count = isOneWay ? 2 : 4;
37167             break;
37168         default:
37169             count = isOneWay ? 1 : 2;
37170             break;
37171     }
37172
37173     return count;
37174 }
37175
37176
37177 function parseMaxspeed(tags) {
37178     var maxspeed = tags.maxspeed;
37179     if (lodash.isNumber(maxspeed)) return maxspeed;
37180     if (lodash.isString(maxspeed)) {
37181         maxspeed = maxspeed.match(/^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/g);
37182         if (!maxspeed) return;
37183         return parseInt(maxspeed, 10);
37184     }
37185 }
37186
37187
37188 function parseLaneDirections(tags, isOneWay, laneCount) {
37189     var forward = parseInt(tags['lanes:forward'], 10);
37190     var backward = parseInt(tags['lanes:backward'], 10);
37191     var bothways = parseInt(tags['lanes:both_ways'], 10) > 0 ? 1 : 0;
37192
37193     if (parseInt(tags.oneway, 10) === -1) {
37194         forward = 0;
37195         bothways = 0;
37196         backward = laneCount;
37197     }
37198     else if (isOneWay) {
37199         forward = laneCount;
37200         bothways = 0;
37201         backward = 0;
37202     }
37203     else if (lodash.isNaN(forward) && lodash.isNaN(backward)) {
37204         backward = Math.floor((laneCount - bothways) / 2);
37205         forward = laneCount - bothways - backward;
37206     }
37207     else if (lodash.isNaN(forward)) {
37208         if (backward > laneCount - bothways) {
37209             backward = laneCount - bothways;
37210         }
37211         forward = laneCount - bothways - backward;
37212     }
37213     else if (lodash.isNaN(backward)) {
37214         if (forward > laneCount - bothways) {
37215             forward = laneCount - bothways;
37216         }
37217         backward = laneCount - bothways - forward;
37218     }
37219     return {
37220         forward: forward,
37221         backward: backward,
37222         bothways: bothways
37223     };
37224 }
37225
37226
37227 function parseTurnLanes(tag){
37228     if (!tag) return;
37229
37230     var validValues = [
37231         'left', 'slight_left', 'sharp_left', 'through', 'right', 'slight_right',
37232         'sharp_right', 'reverse', 'merge_to_left', 'merge_to_right', 'none'
37233     ];
37234
37235     return tag.split('|')
37236         .map(function (s) {
37237             if (s === '') s = 'none';
37238             return s.split(';')
37239                 .map(function (d) {
37240                     return validValues.indexOf(d) === -1 ? 'unknown': d;
37241                 });
37242         });
37243 }
37244
37245
37246 function parseMaxspeedLanes(tag, maxspeed) {
37247     if (!tag) return;
37248
37249     return tag.split('|')
37250         .map(function (s) {
37251             if (s === 'none') return s;
37252             var m = parseInt(s, 10);
37253             if (s === '' || m === maxspeed) return null;
37254             return lodash.isNaN(m) ? 'unknown': m;
37255         });
37256 }
37257
37258
37259 function parseMiscLanes(tag) {
37260     if (!tag) return;
37261
37262     var validValues = [
37263         'yes', 'no', 'designated'
37264     ];
37265
37266     return tag.split('|')
37267         .map(function (s) {
37268             if (s === '') s = 'no';
37269             return validValues.indexOf(s) === -1 ? 'unknown': s;
37270         });
37271 }
37272
37273
37274 function parseBicycleWay(tag) {
37275     if (!tag) return;
37276
37277     var validValues = [
37278         'yes', 'no', 'designated', 'lane'
37279     ];
37280
37281     return tag.split('|')
37282         .map(function (s) {
37283             if (s === '') s = 'no';
37284             return validValues.indexOf(s) === -1 ? 'unknown': s;
37285         });
37286 }
37287
37288
37289 function mapToLanesObj(lanesObj, data, key) {
37290     if (data.forward) data.forward.forEach(function(l, i) {
37291         if (!lanesObj.forward[i]) lanesObj.forward[i] = {};
37292         lanesObj.forward[i][key] = l;
37293     });
37294     if (data.backward) data.backward.forEach(function(l, i) {
37295         if (!lanesObj.backward[i]) lanesObj.backward[i] = {};
37296         lanesObj.backward[i][key] = l;
37297     });
37298     if (data.unspecified) data.unspecified.forEach(function(l, i) {
37299         if (!lanesObj.unspecified[i]) lanesObj.unspecified[i] = {};
37300         lanesObj.unspecified[i][key] = l;
37301     });
37302 }
37303
37304 var translations = Object.create(null);
37305
37306 var currentLocale = 'en';
37307 var textDirection = 'ltr';
37308
37309 function setLocale(_) {
37310     if (translations[_] !== undefined) {
37311         currentLocale = _;
37312     } else if (translations[_.split('-')[0]]) {
37313         currentLocale = _.split('-')[0];
37314     }
37315 }
37316
37317 function addTranslation(id, value) {
37318     translations[id] = value;
37319 }
37320
37321 /**
37322  * Given a string identifier, try to find that string in the current
37323  * language, and return it.
37324  *
37325  * @param {string} s string identifier
37326  * @returns {string?} locale string
37327  */
37328 function t(s, o, loc) {
37329     loc = loc || currentLocale;
37330
37331     var path = s.split('.').reverse();
37332     var rep = translations[loc];
37333
37334     while (rep !== undefined && path.length) rep = rep[path.pop()];
37335
37336     if (rep !== undefined) {
37337         if (o) for (var k in o) rep = rep.replace('{' + k + '}', o[k]);
37338         return rep;
37339     }
37340
37341     if (loc !== 'en') {
37342         return t(s, o, 'en');
37343     }
37344
37345     if (o && 'default' in o) {
37346         return o.default;
37347     }
37348
37349     var missing = 'Missing ' + loc + ' translation: ' + s;
37350     if (typeof console !== 'undefined') console.error(missing); // eslint-disable-line
37351
37352     return missing;
37353 }
37354
37355 /**
37356  * Given string 'ltr' or 'rtl', save that setting
37357  *
37358  * @param {string} s ltr or rtl
37359  */
37360
37361 function setTextDirection(dir) {
37362     textDirection = dir;
37363 }
37364
37365 var detected;
37366
37367 function utilDetect(force) {
37368     if (detected && !force) return detected;
37369     detected = {};
37370
37371     var ua = navigator.userAgent,
37372         m = null;
37373
37374     m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i);   // Edge
37375     if (m !== null) {
37376         detected.browser = m[1];
37377         detected.version = m[2];
37378     }
37379     if (!detected.browser) {
37380         m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i);   // IE11
37381         if (m !== null) {
37382             detected.browser = 'msie';
37383             detected.version = m[1];
37384         }
37385     }
37386     if (!detected.browser) {
37387         m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i);   // Opera 15+
37388         if (m !== null) {
37389             detected.browser = 'Opera';
37390             detected.version = m[2];
37391         }
37392     }
37393     if (!detected.browser) {
37394         m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
37395         if (m !== null) {
37396             detected.browser = m[1];
37397             detected.version = m[2];
37398             m = ua.match(/version\/([\.\d]+)/i);
37399             if (m !== null) detected.version = m[1];
37400         }
37401     }
37402     if (!detected.browser) {
37403         detected.browser = navigator.appName;
37404         detected.version = navigator.appVersion;
37405     }
37406
37407     // keep major.minor version only..
37408     detected.version = detected.version.split(/\W/).slice(0,2).join('.');
37409
37410     if (detected.browser.toLowerCase() === 'msie') {
37411         detected.ie = true;
37412         detected.browser = 'Internet Explorer';
37413         detected.support = parseFloat(detected.version) >= 11;
37414     } else {
37415         detected.ie = false;
37416         detected.support = true;
37417     }
37418
37419     // Added due to incomplete svg style support. See #715
37420     detected.opera = (detected.browser.toLowerCase() === 'opera' && parseFloat(detected.version) < 15 );
37421
37422     detected.locale = (navigator.language || navigator.userLanguage || 'en-US');
37423     detected.language = detected.locale.split('-')[0];
37424
37425     // Search `navigator.languages` for a better locale.. Prefer the first language,
37426     // unless the second language is a culture-specific version of the first one, see #3842
37427     if (navigator.languages && navigator.languages.length > 0) {
37428         var code0 = navigator.languages[0],
37429             parts0 = code0.split('-');
37430
37431         detected.locale = code0;
37432         detected.language = parts0[0];
37433
37434         if (navigator.languages.length > 1 && parts0.length === 1) {
37435             var code1 = navigator.languages[1],
37436                 parts1 = code1.split('-');
37437
37438             if (parts1[0] === parts0[0]) {
37439                 detected.locale = code1;
37440             }
37441         }
37442     }
37443
37444     // Loaded locale is stored in currentLocale
37445     // return that instead (except in the situation where 'en' might override 'en-US')
37446     var loadedLocale = currentLocale || 'en';
37447     if (loadedLocale !== 'en') {
37448         detected.locale = loadedLocale;
37449         detected.language = detected.locale.split('-')[0];
37450     }
37451
37452     // detect text direction
37453     var q = utilStringQs(window.location.hash.substring(1));
37454     var lang = dataLocales[detected.locale];
37455     if ((lang && lang.rtl) || q.hasOwnProperty('rtl')) {
37456         detected.textDirection = 'rtl';
37457     } else {
37458         detected.textDirection = 'ltr';
37459     }
37460     setTextDirection(detected.textDirection);
37461
37462     // detect host
37463     var loc = window.top.location;
37464     var origin = loc.origin;
37465     if (!origin) {  // for unpatched IE11
37466         origin = loc.protocol + '//' + loc.hostname + (loc.port ? ':' + loc.port: '');
37467     }
37468
37469     detected.host = origin + loc.pathname;
37470
37471     detected.filedrop = (window.FileReader && 'ondrop' in window);
37472
37473     function nav(x) {
37474         return navigator.userAgent.indexOf(x) !== -1;
37475     }
37476
37477     if (nav('Win')) {
37478         detected.os = 'win';
37479         detected.platform = 'Windows';
37480     }
37481     else if (nav('Mac')) {
37482         detected.os = 'mac';
37483         detected.platform = 'Macintosh';
37484     }
37485     else if (nav('X11') || nav('Linux')) {
37486         detected.os = 'linux';
37487         detected.platform = 'Linux';
37488     }
37489     else {
37490         detected.os = 'win';
37491         detected.platform = 'Unknown';
37492     }
37493
37494     return detected;
37495 }
37496
37497 var remove$1 = removeDiacritics;
37498
37499 var replacementList = [
37500   {
37501     base: ' ',
37502     chars: "\u00A0",
37503   }, {
37504     base: '0',
37505     chars: "\u07C0",
37506   }, {
37507     base: 'A',
37508     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",
37509   }, {
37510     base: 'AA',
37511     chars: "\uA732",
37512   }, {
37513     base: 'AE',
37514     chars: "\u00C6\u01FC\u01E2",
37515   }, {
37516     base: 'AO',
37517     chars: "\uA734",
37518   }, {
37519     base: 'AU',
37520     chars: "\uA736",
37521   }, {
37522     base: 'AV',
37523     chars: "\uA738\uA73A",
37524   }, {
37525     base: 'AY',
37526     chars: "\uA73C",
37527   }, {
37528     base: 'B',
37529     chars: "\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0181",
37530   }, {
37531     base: 'C',
37532     chars: "\u24b8\uff23\uA73E\u1E08\u0106\u0043\u0108\u010A\u010C\u00C7\u0187\u023B",
37533   }, {
37534     base: 'D',
37535     chars: "\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018A\u0189\u1D05\uA779",
37536   }, {
37537     base: 'Dh',
37538     chars: "\u00D0",
37539   }, {
37540     base: 'DZ',
37541     chars: "\u01F1\u01C4",
37542   }, {
37543     base: 'Dz',
37544     chars: "\u01F2\u01C5",
37545   }, {
37546     base: 'E',
37547     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",
37548   }, {
37549     base: 'F',
37550     chars: "\uA77C\u24BB\uFF26\u1E1E\u0191\uA77B",
37551   }, {
37552     base: 'G',
37553     chars: "\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E\u0262",
37554   }, {
37555     base: 'H',
37556     chars: "\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D",
37557   }, {
37558     base: 'I',
37559     chars: "\u24BE\uFF29\xCC\xCD\xCE\u0128\u012A\u012C\u0130\xCF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197",
37560   }, {
37561     base: 'J',
37562     chars: "\u24BF\uFF2A\u0134\u0248\u0237",
37563   }, {
37564     base: 'K',
37565     chars: "\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2",
37566   }, {
37567     base: 'L',
37568     chars: "\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780",
37569   }, {
37570     base: 'LJ',
37571     chars: "\u01C7",
37572   }, {
37573     base: 'Lj',
37574     chars: "\u01C8",
37575   }, {
37576     base: 'M',
37577     chars: "\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C\u03FB",
37578   }, {
37579     base: 'N',
37580     chars: "\uA7A4\u0220\u24C3\uFF2E\u01F8\u0143\xD1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u019D\uA790\u1D0E",
37581   }, {
37582     base: 'NJ',
37583     chars: "\u01CA",
37584   }, {
37585     base: 'Nj',
37586     chars: "\u01CB",
37587   }, {
37588     base: 'O',
37589     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",
37590   }, {
37591     base: 'OE',
37592     chars: "\u0152",
37593   }, {
37594     base: 'OI',
37595     chars: "\u01A2",
37596   }, {
37597     base: 'OO',
37598     chars: "\uA74E",
37599   }, {
37600     base: 'OU',
37601     chars: "\u0222",
37602   }, {
37603     base: 'P',
37604     chars: "\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754",
37605   }, {
37606     base: 'Q',
37607     chars: "\u24C6\uFF31\uA756\uA758\u024A",
37608   }, {
37609     base: 'R',
37610     chars: "\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782",
37611   }, {
37612     base: 'S',
37613     chars: "\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784",
37614   }, {
37615     base: 'T',
37616     chars: "\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786",
37617   }, {
37618     base: 'Th',
37619     chars: "\u00DE",
37620   }, {
37621     base: 'TZ',
37622     chars: "\uA728",
37623   }, {
37624     base: 'U',
37625     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",
37626   }, {
37627     base: 'V',
37628     chars: "\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245",
37629   }, {
37630     base: 'VY',
37631     chars: "\uA760",
37632   }, {
37633     base: 'W',
37634     chars: "\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72",
37635   }, {
37636     base: 'X',
37637     chars: "\u24CD\uFF38\u1E8A\u1E8C",
37638   }, {
37639     base: 'Y',
37640     chars: "\u24CE\uFF39\u1EF2\xDD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE",
37641   }, {
37642     base: 'Z',
37643     chars: "\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762",
37644   }, {
37645     base: 'a',
37646     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",
37647   }, {
37648     base: 'aa',
37649     chars: "\uA733",
37650   }, {
37651     base: 'ae',
37652     chars: "\u00E6\u01FD\u01E3",
37653   }, {
37654     base: 'ao',
37655     chars: "\uA735",
37656   }, {
37657     base: 'au',
37658     chars: "\uA737",
37659   }, {
37660     base: 'av',
37661     chars: "\uA739\uA73B",
37662   }, {
37663     base: 'ay',
37664     chars: "\uA73D",
37665   }, {
37666     base: 'b',
37667     chars: "\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0182",
37668   }, {
37669     base: 'c',
37670     chars: "\uFF43\u24D2\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184",
37671   }, {
37672     base: 'd',
37673     chars: "\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\u018B\u13E7\u0501\uA7AA",
37674   }, {
37675     base: 'dh',
37676     chars: "\u00F0",
37677   }, {
37678     base: 'dz',
37679     chars: "\u01F3\u01C6",
37680   }, {
37681     base: 'e',
37682     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",
37683   }, {
37684     base: 'f',
37685     chars: "\u24D5\uFF46\u1E1F\u0192",
37686   }, {
37687     base: 'ff',
37688     chars: "\uFB00",
37689   }, {
37690     base: 'fi',
37691     chars: "\uFB01",
37692   }, {
37693     base: 'fl',
37694     chars: "\uFB02",
37695   }, {
37696     base: 'ffi',
37697     chars: "\uFB03",
37698   }, {
37699     base: 'ffl',
37700     chars: "\uFB04",
37701   }, {
37702     base: 'g',
37703     chars: "\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\uA77F\u1D79",
37704   }, {
37705     base: 'h',
37706     chars: "\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265",
37707   }, {
37708     base: 'hv',
37709     chars: "\u0195",
37710   }, {
37711     base: 'i',
37712     chars: "\u24D8\uFF49\xEC\xED\xEE\u0129\u012B\u012D\xEF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131",
37713   }, {
37714     base: 'j',
37715     chars: "\u24D9\uFF4A\u0135\u01F0\u0249",
37716   }, {
37717     base: 'k',
37718     chars: "\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3",
37719   }, {
37720     base: 'l',
37721     chars: "\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u026D",
37722   }, {
37723     base: 'lj',
37724     chars: "\u01C9",
37725   }, {
37726     base: 'm',
37727     chars: "\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F",
37728   }, {
37729     base: 'n',
37730     chars: "\u24DD\uFF4E\u01F9\u0144\xF1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u043B\u0509",
37731   }, {
37732     base: 'nj',
37733     chars: "\u01CC",
37734   }, {
37735     base: 'o',
37736     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",
37737   }, {
37738     base: 'oe',
37739     chars: "\u0153",
37740   }, {
37741     base: 'oi',
37742     chars: "\u01A3",
37743   }, {
37744     base: 'oo',
37745     chars: "\uA74F",
37746   }, {
37747     base: 'ou',
37748     chars: "\u0223",
37749   }, {
37750     base: 'p',
37751     chars: "\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u03C1",
37752   }, {
37753     base: 'q',
37754     chars: "\u24E0\uFF51\u024B\uA757\uA759",
37755   }, {
37756     base: 'r',
37757     chars: "\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783",
37758   }, {
37759     base: 's',
37760     chars: "\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0282",
37761   }, {
37762     base: 'ss',
37763     chars: "\xDF",
37764   }, {
37765     base: 't',
37766     chars: "\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787",
37767   }, {
37768     base: 'th',
37769     chars: "\u00FE",
37770   }, {
37771     base: 'tz',
37772     chars: "\uA729",
37773   }, {
37774     base: 'u',
37775     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",
37776   }, {
37777     base: 'v',
37778     chars: "\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C",
37779   }, {
37780     base: 'vy',
37781     chars: "\uA761",
37782   }, {
37783     base: 'w',
37784     chars: "\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73",
37785   }, {
37786     base: 'x',
37787     chars: "\u24E7\uFF58\u1E8B\u1E8D",
37788   }, {
37789     base: 'y',
37790     chars: "\u24E8\uFF59\u1EF3\xFD\u0177\u1EF9\u0233\u1E8F\xFF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF",
37791   }, {
37792     base: 'z',
37793     chars: "\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763",
37794   }
37795 ];
37796
37797 var diacriticsMap = {};
37798 for (var i = 0; i < replacementList.length; i += 1) {
37799   var chars = replacementList[i].chars;
37800   for (var j = 0; j < chars.length; j += 1) {
37801     diacriticsMap[chars[j]] = replacementList[i].base;
37802   }
37803 }
37804
37805 function removeDiacritics(str) {
37806   return str.replace(/[^\u0000-\u007e]/g, function(c) {
37807     return diacriticsMap[c] || c;
37808   });
37809 }
37810
37811 // see https://github.com/openstreetmap/iD/pull/3707
37812 // https://gist.github.com/mapmeld/556b09ddec07a2044c76e1ef45f01c60
37813
37814 var chars$1 = {
37815     // madda above alef
37816     1570: { initial: 'آ‎', isolated: 'ﺁ', medial: 'ﺁ', final: 'ﺂ' },
37817
37818     // hamza above and below alef
37819     1571: { initial: 'أ', isolated: 'ﺃ', medial: '', final: 'ﺄ' },
37820     // 1572 is ؤ
37821     1573: { initial: 'إ', isolated: 'ﺇ', medial: '', final: 'ﺈ' },
37822     // 1574 is ئ
37823     1575: { initial: 'ا', isolated: 'ا', medial: '', final: 'ﺎ' },
37824     1576: { initial: 'ﺑ', isolated: 'ﺏ', medial: 'ﺒ', final: 'ﺐ' },
37825
37826     // 1577 ة
37827     1577: { initial: '', isolated: 'ة', medial: '', final: 'ﺔ' },
37828
37829     1578: { initial: 'ﺗ', isolated: 'ﺕ', medial: 'ﺘ', final: 'ﺖ' },
37830     1579: { initial: 'ﺛ', isolated: 'ﺙ', medial: 'ﺜ', final: 'ﺚ' },
37831     1580: { initial: 'ﺟ', isolated: 'ﺝ', medial: 'ﺠ', final: 'ﺞ' },
37832     1581: { initial: 'ﺣ', isolated: 'ﺡ', medial: 'ﺤ', final: 'ﺢ' },
37833     1582: { initial: 'ﺧ', isolated: 'ﺥ', medial: 'ﺨ', final: 'ﺦ' },
37834     1583: { initial: 'ﺩ', isolated: 'ﺩ', medial: '', final: 'ﺪ' },
37835     1584: { initial: 'ﺫ', isolated: 'ﺫ', medial: '', final: 'ﺬ' },
37836     1585: { initial: 'ﺭ', isolated: 'ﺭ', medial: '', final: 'ﺮ' },
37837     1586: { initial: 'ﺯ', isolated: 'ﺯ', medial: '', final: 'ﺰ' },
37838     1688: { initial: 'ﮊ', isolated: 'ﮊ', medial: '', final: 'ﮋ' },
37839     1587: { initial: 'ﺳ', isolated: 'ﺱ', medial: 'ﺴ', final: 'ﺲ' },
37840     1588: { initial: 'ﺷ', isolated: 'ﺵ', medial: 'ﺸ', final: 'ﺶ' },
37841     1589: { initial: 'ﺻ', isolated: 'ﺹ', medial: 'ﺼ', final: 'ﺺ' },
37842     1590: { initial: 'ﺿ', isolated: 'ﺽ', medial: 'ﻀ', final: 'ﺾ' },
37843     1591: { initial: 'ﻃ', isolated: 'ﻁ', medial: 'ﻄ', final: 'ﻂ' },
37844     1592: { initial: 'ﻇ', isolated: 'ﻅ', medial: 'ﻈ', final: 'ﻆ' },
37845     1593: { initial: 'ﻋ', isolated: 'ﻉ', medial: 'ﻌ', final: 'ﻊ' },
37846     1594: { initial: 'ﻏ', isolated: 'ﻍ', medial: 'ﻐ', final: 'ﻎ' },
37847
37848     // 1595 ػ - may be very rare
37849
37850     1601: { initial: 'ﻓ', isolated: 'ﻑ', medial: 'ﻔ', final: 'ﻒ' },
37851     1602: { initial: 'ﻗ', isolated: 'ﻕ', medial: 'ﻘ', final: 'ﻖ' },
37852     1604: { initial: 'ﻟ', isolated: 'ﻝ', medial: 'ﻠ', final: 'ﻞ' },
37853     1605: { initial: 'ﻣ', isolated: 'ﻡ', medial: 'ﻤ', final: 'ﻢ' },
37854     1606: { initial: 'ﻧ', isolated: 'ﻥ', medial: 'ﻨ', final: 'ﻦ' },
37855     1607: { initial: 'ﻫ', isolated: 'ﻩ', medial: 'ﻬ', final: 'ﻪ' },
37856     1608: { initial: 'ﻭ', isolated: 'ﻭ', medial: '', final: 'ﻮ' },
37857
37858     // 1609 ى
37859     1609: { initial: 'ﯨ', isolated: 'ﻯ', medial: 'ﯩ', final: 'ﻰ' },
37860     // 1610 ي
37861     1610: { initial: 'ﻳ', isolated: 'ﻱ', medial: 'ﻴ', final: 'ﻲ' },
37862
37863     // short vowel sounds / tashkil markings
37864
37865     1662: { initial: 'ﭘ', isolated: 'ﭖ', medial: 'ﭙ', final: 'ﭗ' },
37866
37867     1670: { initial: 'ﭼ', isolated: 'ﭺ', medial: 'ﭽ', final: 'ﭻ' },
37868     1603: { initial: 'ﻛ', isolated: 'ﻙ', medial: 'ﻜ', final: 'ﻚ' },
37869     1705: { initial: 'ﻛ', isolated: 'ﮎ', medial: 'ﻜ', final: 'ﮏ' },
37870     1711: { initial: 'ﮔ', isolated: 'ﮒ', medial: 'ﮕ', final: 'ﮓ' },
37871     1740: { initial: 'ﻳ', isolated: 'ﻯ', medial: 'ﻴ', final: 'ﻰ' },
37872     5000: { initial: 'ﻻ', isolated: 'ﻻ', medial: '', final: 'ﻼ' }
37873 };
37874
37875 var rtlRegex = /[\u0590-\u05FF\u0600-\u06FF\u0780-\u07BF]/;
37876
37877 function fixRTLTextForSvg(inputText) {
37878     var context = true;
37879     var ret = '';
37880     var rtlBuffer = [];
37881     var arabicRegex = /[\u0600-\u06FF]/g;
37882     var arabicTashkil = /[\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06DC\u06DF-\u06E4\u06E7\u06E8\u06EA-\u06ED]/;
37883     var thaanaVowel = /[\u07A6-\u07B0]/;
37884     var hebrewSign = /[\u0591-\u05bd\u05bf\u05c1-\u05c5\u05c7]/;
37885
37886     if (!arabicRegex.test(inputText)) {
37887         // Hebrew or Thaana RTL script
37888         for (var n = 0; n < inputText.length; n++) {
37889             var c = inputText[n];
37890             if ((thaanaVowel.test(c) || hebrewSign.test(c)) && rtlBuffer.length) {
37891                 rtlBuffer[rtlBuffer.length - 1] += c;
37892             } else if (rtlRegex.test(c)) {
37893                 rtlBuffer.push(c);
37894             } else if (c === ' ' && rtlBuffer.length) {
37895                 // whitespace within RTL text
37896                 rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
37897             } else {
37898                 // non-RTL character
37899                 ret += rtlBuffer.reverse().join('') + c;
37900                 rtlBuffer = [];
37901             }
37902         }
37903     } else {
37904         for (var i = 0, l = inputText.length; i < l; i++) {
37905             var code = inputText[i].charCodeAt(0);
37906             var nextCode = inputText[i + 1] ? inputText[i + 1].charCodeAt(0) : 0;
37907
37908             if (!chars$1[code]) {
37909                 if (code === 32 && rtlBuffer.length) {
37910                     // whitespace
37911                     rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
37912                 } else if (arabicTashkil.test(inputText[i]) && rtlBuffer.length) {
37913                     // tashkil mark
37914                     rtlBuffer[rtlBuffer.length - 1] += inputText[i];
37915                 } else {
37916                     // non-RTL character
37917                     ret += rtlBuffer.reverse().join('') + inputText[i];
37918                     rtlBuffer = [];
37919                 }
37920                 continue;
37921             }
37922             if (context) {
37923                 if (i === l - 1 || nextCode === 32) {
37924                     rtlBuffer.push(chars$1[code].isolated);
37925                 } else {
37926                     // special case for لا
37927                     if (code === 1604 && nextCode === 1575) {
37928                         rtlBuffer.push(chars$1[5000].initial);
37929                         i++;
37930                         context = true;
37931                         continue;
37932                     }
37933                     rtlBuffer.push(chars$1[code].initial);
37934                 }
37935             } else {
37936                 if (i === l - 1 || nextCode === 32){
37937                     rtlBuffer.push(chars$1[code].final);
37938                 } else {
37939                     // special case for ﻼ
37940                     if (code === 1604 && nextCode === 1575){
37941                         rtlBuffer.push(chars$1[5000].final);
37942                         i++;
37943                         context = true;
37944                         continue;
37945                     }
37946                     if (chars$1[code].medial === ''){
37947                         rtlBuffer.push(chars$1[code].final);
37948                     } else {
37949                         rtlBuffer.push(chars$1[code].medial);
37950                     }
37951                 }
37952             }
37953             context = (chars$1[code].medial === '') || nextCode === 32;
37954         }
37955     }
37956     ret += rtlBuffer.reverse().join('');
37957     return ret;
37958 }
37959
37960 function utilTagText(entity) {
37961     return entries(entity.tags).map(function(e) {
37962         return e.key + '=' + e.value;
37963     }).join(', ');
37964 }
37965
37966
37967 function utilEntitySelector(ids) {
37968     return ids.length ? '.' + ids.join(',.') : 'nothing';
37969 }
37970
37971
37972 function utilEntityOrMemberSelector(ids, graph) {
37973     var s = utilEntitySelector(ids);
37974
37975     ids.forEach(function(id) {
37976         var entity = graph.hasEntity(id);
37977         if (entity && entity.type === 'relation') {
37978             entity.members.forEach(function(member) {
37979                 s += ',.' + member.id;
37980             });
37981         }
37982     });
37983
37984     return s;
37985 }
37986
37987
37988 function utilGetAllNodes(ids, graph) {
37989     var seen = {};
37990     var nodes = [];
37991     ids.forEach(getNodes);
37992     return nodes;
37993
37994     function getNodes(id) {
37995         if (seen[id]) return;
37996         seen[id] = true;
37997
37998         var entity = graph.hasEntity(id);
37999         if (!entity) return;
38000
38001         if (entity.type === 'node') {
38002             nodes.push(entity);
38003         } else if (entity.type === 'way') {
38004             entity.nodes.forEach(getNodes);
38005         } else {
38006             entity.members.map(function(member) { return member.id; }).forEach(getNodes);
38007         }
38008     }
38009 }
38010
38011
38012 function utilDisplayName(entity) {
38013     var localizedNameKey = 'name:' + utilDetect().locale.toLowerCase().split('-')[0],
38014         name = entity.tags[localizedNameKey] || entity.tags.name || '',
38015         network = entity.tags.cycle_network || entity.tags.network;
38016
38017     if (!name && entity.tags.ref) {
38018         name = entity.tags.ref;
38019         if (network) {
38020             name = network + ' ' + name;
38021         }
38022     }
38023
38024     return name;
38025 }
38026
38027
38028 function utilDisplayNameForPath(entity) {
38029     var name = utilDisplayName(entity);
38030     var isFirefox = utilDetect().browser.toLowerCase().indexOf('firefox') > -1;
38031
38032     if (!isFirefox && name && rtlRegex.test(name)) {
38033         name = fixRTLTextForSvg(name);
38034     }
38035
38036     return name;
38037 }
38038
38039
38040 function utilDisplayType(id) {
38041     return {
38042         n: t('inspector.node'),
38043         w: t('inspector.way'),
38044         r: t('inspector.relation')
38045     }[id.charAt(0)];
38046 }
38047
38048
38049 function utilStringQs(str) {
38050     return str.split('&').reduce(function(obj, pair){
38051         var parts = pair.split('=');
38052         if (parts.length === 2) {
38053             obj[parts[0]] = (null === parts[1]) ? '' : decodeURIComponent(parts[1]);
38054         }
38055         return obj;
38056     }, {});
38057 }
38058
38059
38060 function utilQsString(obj, noencode) {
38061     function softEncode(s) {
38062       // encode everything except special characters used in certain hash parameters:
38063       // "/" in map states, ":", ",", {" and "}" in background
38064       return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
38065     }
38066     return Object.keys(obj).sort().map(function(key) {
38067         return encodeURIComponent(key) + '=' + (
38068             noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
38069     }).join('&');
38070 }
38071
38072
38073 function utilPrefixDOMProperty(property) {
38074     var prefixes = ['webkit', 'ms', 'moz', 'o'],
38075         i = -1,
38076         n = prefixes.length,
38077         s = document.body;
38078
38079     if (property in s)
38080         return property;
38081
38082     property = property.substr(0, 1).toUpperCase() + property.substr(1);
38083
38084     while (++i < n)
38085         if (prefixes[i] + property in s)
38086             return prefixes[i] + property;
38087
38088     return false;
38089 }
38090
38091
38092 function utilPrefixCSSProperty(property) {
38093     var prefixes = ['webkit', 'ms', 'Moz', 'O'],
38094         i = -1,
38095         n = prefixes.length,
38096         s = document.body.style;
38097
38098     if (property.toLowerCase() in s)
38099         return property.toLowerCase();
38100
38101     while (++i < n)
38102         if (prefixes[i] + property in s)
38103             return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
38104
38105     return false;
38106 }
38107
38108
38109 var transformProperty;
38110 function utilSetTransform(el, x, y, scale) {
38111     var prop = transformProperty = transformProperty || utilPrefixCSSProperty('Transform'),
38112         translate = utilDetect().opera ?
38113             'translate('   + x + 'px,' + y + 'px)' :
38114             'translate3d(' + x + 'px,' + y + 'px,0)';
38115     return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
38116 }
38117
38118
38119 // Calculates Levenshtein distance between two strings
38120 // see:  https://en.wikipedia.org/wiki/Levenshtein_distance
38121 // first converts the strings to lowercase and replaces diacritic marks with ascii equivalents.
38122 function utilEditDistance(a, b) {
38123     a = remove$1(a.toLowerCase());
38124     b = remove$1(b.toLowerCase());
38125     if (a.length === 0) return b.length;
38126     if (b.length === 0) return a.length;
38127     var matrix = [];
38128     for (var i = 0; i <= b.length; i++) { matrix[i] = [i]; }
38129     for (var j = 0; j <= a.length; j++) { matrix[0][j] = j; }
38130     for (i = 1; i <= b.length; i++) {
38131         for (j = 1; j <= a.length; j++) {
38132             if (b.charAt(i-1) === a.charAt(j-1)) {
38133                 matrix[i][j] = matrix[i-1][j-1];
38134             } else {
38135                 matrix[i][j] = Math.min(matrix[i-1][j-1] + 1, // substitution
38136                     Math.min(matrix[i][j-1] + 1, // insertion
38137                     matrix[i-1][j] + 1)); // deletion
38138             }
38139         }
38140     }
38141     return matrix[b.length][a.length];
38142 }
38143
38144
38145 // a d3.mouse-alike which
38146 // 1. Only works on HTML elements, not SVG
38147 // 2. Does not cause style recalculation
38148 function utilFastMouse(container) {
38149     var rect = container.getBoundingClientRect(),
38150         rectLeft = rect.left,
38151         rectTop = rect.top,
38152         clientLeft = +container.clientLeft,
38153         clientTop = +container.clientTop;
38154     if (textDirection === 'rtl') {
38155         rectLeft = 0;
38156     }
38157     return function(e) {
38158         return [
38159             e.clientX - rectLeft - clientLeft,
38160             e.clientY - rectTop - clientTop];
38161     };
38162 }
38163
38164
38165 /* eslint-disable no-proto */
38166 var utilGetPrototypeOf = Object.getPrototypeOf || function(obj) { return obj.__proto__; };
38167 /* eslint-enable no-proto */
38168
38169
38170 function utilAsyncMap(inputs, func, callback) {
38171     var remaining = inputs.length,
38172         results = [],
38173         errors = [];
38174
38175     inputs.forEach(function(d, i) {
38176         func(d, function done(err, data) {
38177             errors[i] = err;
38178             results[i] = data;
38179             remaining--;
38180             if (!remaining) callback(errors, results);
38181         });
38182     });
38183 }
38184
38185
38186 // wraps an index to an interval [0..length-1]
38187 function utilWrap(index, length) {
38188     if (index < 0)
38189         index += Math.ceil(-index/length)*length;
38190     return index % length;
38191 }
38192
38193
38194 /**
38195  * a replacement for functor
38196  *
38197  * @param {*} value any value
38198  * @returns {Function} a function that returns that value or the value if it's a function
38199  */
38200 function utilFunctor(value) {
38201     if (typeof value === 'function') return value;
38202     return function() {
38203         return value;
38204     };
38205 }
38206
38207
38208 function utilNoAuto(selection$$1) {
38209     return selection$$1
38210         .attr('autocomplete', 'off')
38211         .attr('autocorrect', 'off')
38212         .attr('autocapitalize', 'off')
38213         .attr('spellcheck', 'false');
38214 }
38215
38216 // Like selection.property('value', ...), but avoids no-op value sets,
38217 // which can result in layout/repaint thrashing in some situations.
38218 function utilGetSetValue(selection, value) {
38219     function d3_selection_value(value) {
38220         function valueNull() {
38221             delete this.value;
38222         }
38223
38224         function valueConstant() {
38225             if (this.value !== value) {
38226                 this.value = value;
38227             }
38228         }
38229
38230         function valueFunction() {
38231             var x = value.apply(this, arguments);
38232             if (x == null) {
38233                 delete this.value;
38234             } else if (this.value !== x) {
38235                 this.value = x;
38236             }
38237         }
38238
38239         return value == null
38240             ? valueNull : (typeof value === 'function'
38241             ? valueFunction : valueConstant);
38242     }
38243
38244     if (arguments.length === 1) {
38245         return selection.property('value');
38246     }
38247
38248     return selection.each(d3_selection_value(value));
38249 }
38250
38251 // Copies a variable number of methods from source to target.
38252 function utilRebind(target, source) {
38253     var i = 1, n = arguments.length, method;
38254     while (++i < n) {
38255         target[method = arguments[i]] = d3_rebind(target, source, source[method]);
38256     }
38257     return target;
38258 }
38259
38260 // Method is assumed to be a standard D3 getter-setter:
38261 // If passed with no arguments, gets the value.
38262 // If passed with arguments, sets the value and returns the target.
38263 function d3_rebind(target, source, method) {
38264     return function() {
38265         var value = method.apply(source, arguments);
38266         return value === source ? target : value;
38267     };
38268 }
38269
38270 // A per-domain session mutex backed by a cookie and dead man's
38271 // switch. If the session crashes, the mutex will auto-release
38272 // after 5 seconds.
38273
38274 function utilSessionMutex(name) {
38275     var mutex = {},
38276         intervalID;
38277
38278     function renew() {
38279         var expires = new Date();
38280         expires.setSeconds(expires.getSeconds() + 5);
38281         document.cookie = name + '=1; expires=' + expires.toUTCString();
38282     }
38283
38284     mutex.lock = function() {
38285         if (intervalID) return true;
38286         var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
38287         if (cookie) return false;
38288         renew();
38289         intervalID = window.setInterval(renew, 4000);
38290         return true;
38291     };
38292
38293     mutex.unlock = function() {
38294         if (!intervalID) return;
38295         document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT';
38296         clearInterval(intervalID);
38297         intervalID = null;
38298     };
38299
38300     mutex.locked = function() {
38301         return !!intervalID;
38302     };
38303
38304     return mutex;
38305 }
38306
38307 function utilSuggestNames(preset, suggestions) {
38308     preset = preset.id.split('/', 2);
38309     var k = preset[0],
38310         v = preset[1];
38311
38312     return function(value, callback) {
38313         var result = [];
38314         if (value && value.length > 2) {
38315             if (suggestions[k] && suggestions[k][v]) {
38316                 for (var sugg in suggestions[k][v]) {
38317                     var dist = utilEditDistance(value, sugg.substring(0, value.length));
38318                     if (dist < 3) {
38319                         result.push({
38320                             title: sugg,
38321                             value: sugg,
38322                             dist: dist
38323                         });
38324                     }
38325                 }
38326             }
38327             result.sort(function(a, b) {
38328                 return a.dist - b.dist;
38329             });
38330         }
38331         result = result.slice(0,3);
38332         callback(result);
38333     };
38334 }
38335
38336 function utilTriggerEvent(target, type) {
38337     target.each(function() {
38338         var evt = document.createEvent('HTMLEvents');
38339         evt.initEvent(type, true, true);
38340         this.dispatchEvent(evt);
38341     });
38342 }
38343
38344 function validationDeprecatedTag() {
38345
38346     var validation = function(changes) {
38347         var warnings = [];
38348         for (var i = 0; i < changes.created.length; i++) {
38349             var change = changes.created[i],
38350                 deprecatedTags = change.deprecatedTags();
38351
38352             if (!lodash.isEmpty(deprecatedTags)) {
38353                 var tags = utilTagText({ tags: deprecatedTags });
38354                 warnings.push({
38355                     id: 'deprecated_tags',
38356                     message: t('validations.deprecated_tags', { tags: tags }),
38357                     entity: change
38358                 });
38359             }
38360         }
38361
38362         return warnings;
38363     };
38364
38365
38366     return validation;
38367 }
38368
38369 function validationDisconnectedHighway() {
38370
38371
38372     function isDisconnectedHighway(entity, graph) {
38373         if (!entity.tags.highway) return false;
38374         if (entity.geometry(graph) !== 'line') return false;
38375
38376         return graph.childNodes(entity)
38377             .every(function(vertex) {
38378                 var parents = graph.parentWays(vertex);
38379                 if (parents.length === 1) {  // standalone vertex
38380                     return true;
38381                 } else {                     // shared vertex
38382                     return !vertex.tags.entrance &&
38383                         parents.filter(function(parent) {
38384                             return parent.tags.highway && parent !== entity;
38385                         }).length === 0;
38386                 }
38387             });
38388     }
38389
38390
38391     var validation = function(changes, graph) {
38392         var warnings = [];
38393         for (var i = 0; i < changes.created.length; i++) {
38394             var entity = changes.created[i];
38395
38396             if (isDisconnectedHighway(entity, graph)) {
38397                 warnings.push({
38398                     id: 'disconnected_highway',
38399                     message: t('validations.disconnected_highway'),
38400                     tooltip: t('validations.disconnected_highway_tooltip'),
38401                     entity: entity
38402                 });
38403             }
38404         }
38405
38406         return warnings;
38407     };
38408
38409
38410     return validation;
38411 }
38412
38413 function validationManyDeletions() {
38414     var threshold = 100;
38415
38416     var validation = function(changes) {
38417         var warnings = [];
38418         if (changes.deleted.length > threshold) {
38419             warnings.push({
38420                 id: 'many_deletions',
38421                 message: t('validations.many_deletions', { n: changes.deleted.length })
38422             });
38423         }
38424
38425         return warnings;
38426     };
38427
38428
38429     return validation;
38430 }
38431
38432 function validationMissingTag() {
38433
38434     // Slightly stricter check than Entity#isUsed (#3091)
38435     function hasTags(entity, graph) {
38436         return lodash.without(Object.keys(entity.tags), 'area', 'name').length > 0 ||
38437             graph.parentRelations(entity).length > 0;
38438     }
38439
38440     var validation = function(changes, graph) {
38441         var types = ['point', 'line', 'area', 'relation'],
38442             warnings = [];
38443
38444         for (var i = 0; i < changes.created.length; i++) {
38445             var change = changes.created[i],
38446                 geometry = change.geometry(graph);
38447
38448             if (types.indexOf(geometry) !== -1 && !hasTags(change, graph)) {
38449                 warnings.push({
38450                     id: 'missing_tag',
38451                     message: t('validations.untagged_' + geometry),
38452                     tooltip: t('validations.untagged_' + geometry + '_tooltip'),
38453                     entity: change
38454                 });
38455             }
38456         }
38457
38458         return warnings;
38459     };
38460
38461
38462     return validation;
38463 }
38464
38465 function validationOldMultipolygon() {
38466
38467
38468     return function validation(changes, graph) {
38469         var warnings = [];
38470         for (var i = 0; i < changes.created.length; i++) {
38471             var entity = changes.created[i];
38472             var parent = osmIsSimpleMultipolygonOuterMember(entity, graph);
38473             if (parent) {
38474                 warnings.push({
38475                     id: 'old_multipolygon',
38476                     message: t('validations.old_multipolygon'),
38477                     tooltip: t('validations.old_multipolygon_tooltip'),
38478                     entity: parent
38479                 });
38480             }
38481         }
38482         return warnings;
38483     };
38484 }
38485
38486 // https://github.com/openstreetmap/josm/blob/mirror/src/org/
38487 // openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
38488 function validationTagSuggestsArea() {
38489
38490     function tagSuggestsArea(tags) {
38491         if (lodash.isEmpty(tags)) return false;
38492
38493         var presence = ['landuse', 'amenities', 'tourism', 'shop'];
38494         for (var i = 0; i < presence.length; i++) {
38495             if (tags[presence[i]] !== undefined) {
38496                 return presence[i] + '=' + tags[presence[i]];
38497             }
38498         }
38499
38500         if (tags.building && tags.building === 'yes') return 'building=yes';
38501     }
38502
38503
38504     var validation = function(changes, graph) {
38505         var warnings = [];
38506         for (var i = 0; i < changes.created.length; i++) {
38507             var change = changes.created[i],
38508                 geometry = change.geometry(graph),
38509                 suggestion = (geometry === 'line' ? tagSuggestsArea(change.tags) : undefined);
38510
38511             if (suggestion) {
38512                 warnings.push({
38513                     id: 'tag_suggests_area',
38514                     message: t('validations.tag_suggests_area', { tag: suggestion }),
38515                     entity: change
38516                 });
38517             }
38518         }
38519
38520         return warnings;
38521     };
38522
38523
38524     return validation;
38525 }
38526
38527
38528
38529 var Validations = Object.freeze({
38530         validationDeprecatedTag: validationDeprecatedTag,
38531         validationDisconnectedHighway: validationDisconnectedHighway,
38532         validationManyDeletions: validationManyDeletions,
38533         validationMissingTag: validationMissingTag,
38534         validationOldMultipolygon: validationOldMultipolygon,
38535         validationTagSuggestsArea: validationTagSuggestsArea
38536 });
38537
38538 /*
38539     iD.Difference represents the difference between two graphs.
38540     It knows how to calculate the set of entities that were
38541     created, modified, or deleted, and also contains the logic
38542     for recursively extending a difference to the complete set
38543     of entities that will require a redraw, taking into account
38544     child and parent relationships.
38545  */
38546 function coreDifference(base, head) {
38547     var changes = {},
38548         difference = {},
38549         length = 0;
38550
38551
38552     function changed(h, b) {
38553         return h !== b && !lodash.isEqual(lodash.omit(h, 'v'), lodash.omit(b, 'v'));
38554     }
38555
38556
38557     lodash.each(head.entities, function(h, id) {
38558         var b = base.entities[id];
38559         if (changed(h, b)) {
38560             changes[id] = {base: b, head: h};
38561             length++;
38562         }
38563     });
38564
38565
38566     lodash.each(base.entities, function(b, id) {
38567         var h = head.entities[id];
38568         if (!changes[id] && changed(h, b)) {
38569             changes[id] = {base: b, head: h};
38570             length++;
38571         }
38572     });
38573
38574
38575     function addParents(parents, result) {
38576         for (var i = 0; i < parents.length; i++) {
38577             var parent = parents[i];
38578
38579             if (parent.id in result)
38580                 continue;
38581
38582             result[parent.id] = parent;
38583             addParents(head.parentRelations(parent), result);
38584         }
38585     }
38586
38587
38588     difference.length = function() {
38589         return length;
38590     };
38591
38592
38593     difference.changes = function() {
38594         return changes;
38595     };
38596
38597
38598     difference.extantIDs = function() {
38599         var result = [];
38600         lodash.each(changes, function(change, id) {
38601             if (change.head) result.push(id);
38602         });
38603         return result;
38604     };
38605
38606
38607     difference.modified = function() {
38608         var result = [];
38609         lodash.each(changes, function(change) {
38610             if (change.base && change.head) result.push(change.head);
38611         });
38612         return result;
38613     };
38614
38615
38616     difference.created = function() {
38617         var result = [];
38618         lodash.each(changes, function(change) {
38619             if (!change.base && change.head) result.push(change.head);
38620         });
38621         return result;
38622     };
38623
38624
38625     difference.deleted = function() {
38626         var result = [];
38627         lodash.each(changes, function(change) {
38628             if (change.base && !change.head) result.push(change.base);
38629         });
38630         return result;
38631     };
38632
38633
38634     difference.summary = function() {
38635         var relevant = {};
38636
38637         function addEntity(entity, graph, changeType) {
38638             relevant[entity.id] = {
38639                 entity: entity,
38640                 graph: graph,
38641                 changeType: changeType
38642             };
38643         }
38644
38645         function addParents(entity) {
38646             var parents = head.parentWays(entity);
38647             for (var j = parents.length - 1; j >= 0; j--) {
38648                 var parent = parents[j];
38649                 if (!(parent.id in relevant)) addEntity(parent, head, 'modified');
38650             }
38651         }
38652
38653         lodash.each(changes, function(change) {
38654             if (change.head && change.head.geometry(head) !== 'vertex') {
38655                 addEntity(change.head, head, change.base ? 'modified' : 'created');
38656
38657             } else if (change.base && change.base.geometry(base) !== 'vertex') {
38658                 addEntity(change.base, base, 'deleted');
38659
38660             } else if (change.base && change.head) { // modified vertex
38661                 var moved    = !lodash.isEqual(change.base.loc,  change.head.loc),
38662                     retagged = !lodash.isEqual(change.base.tags, change.head.tags);
38663
38664                 if (moved) {
38665                     addParents(change.head);
38666                 }
38667
38668                 if (retagged || (moved && change.head.hasInterestingTags())) {
38669                     addEntity(change.head, head, 'modified');
38670                 }
38671
38672             } else if (change.head && change.head.hasInterestingTags()) { // created vertex
38673                 addEntity(change.head, head, 'created');
38674
38675             } else if (change.base && change.base.hasInterestingTags()) { // deleted vertex
38676                 addEntity(change.base, base, 'deleted');
38677             }
38678         });
38679
38680         return values(relevant);
38681     };
38682
38683
38684     difference.complete = function(extent$$1) {
38685         var result = {}, id, change;
38686
38687         for (id in changes) {
38688             change = changes[id];
38689
38690             var h = change.head,
38691                 b = change.base,
38692                 entity = h || b;
38693
38694             if (extent$$1 &&
38695                 (!h || !h.intersects(extent$$1, head)) &&
38696                 (!b || !b.intersects(extent$$1, base)))
38697                 continue;
38698
38699             result[id] = h;
38700
38701             if (entity.type === 'way') {
38702                 var nh = h ? h.nodes : [],
38703                     nb = b ? b.nodes : [],
38704                     diff, i;
38705
38706                 diff = lodash.difference(nh, nb);
38707                 for (i = 0; i < diff.length; i++) {
38708                     result[diff[i]] = head.hasEntity(diff[i]);
38709                 }
38710
38711                 diff = lodash.difference(nb, nh);
38712                 for (i = 0; i < diff.length; i++) {
38713                     result[diff[i]] = head.hasEntity(diff[i]);
38714                 }
38715             }
38716
38717             addParents(head.parentWays(entity), result);
38718             addParents(head.parentRelations(entity), result);
38719         }
38720
38721         return result;
38722     };
38723
38724
38725     return difference;
38726 }
38727
38728 function coreGraph$$1(other, mutable) {
38729     if (!(this instanceof coreGraph$$1)) return new coreGraph$$1(other, mutable);
38730
38731     if (other instanceof coreGraph$$1) {
38732         var base = other.base();
38733         this.entities = lodash.assign(Object.create(base.entities), other.entities);
38734         this._parentWays = lodash.assign(Object.create(base.parentWays), other._parentWays);
38735         this._parentRels = lodash.assign(Object.create(base.parentRels), other._parentRels);
38736
38737     } else {
38738         this.entities = Object.create({});
38739         this._parentWays = Object.create({});
38740         this._parentRels = Object.create({});
38741         this.rebase(other || [], [this]);
38742     }
38743
38744     this.transients = {};
38745     this._childNodes = {};
38746     this.frozen = !mutable;
38747 }
38748
38749
38750 coreGraph$$1.prototype = {
38751
38752     hasEntity: function(id) {
38753         return this.entities[id];
38754     },
38755
38756
38757     entity: function(id) {
38758         var entity = this.entities[id];
38759
38760         //https://github.com/openstreetmap/iD/issues/3973#issuecomment-307052376
38761         if (!entity) {
38762             entity = this.entities.__proto__[id];  // eslint-disable-line no-proto
38763         }
38764
38765         if (!entity) {
38766             throw new Error('entity ' + id + ' not found');
38767         }
38768         return entity;
38769     },
38770
38771
38772     transient: function(entity, key, fn) {
38773         var id = entity.id,
38774             transients = this.transients[id] ||
38775             (this.transients[id] = {});
38776
38777         if (transients[key] !== undefined) {
38778             return transients[key];
38779         }
38780
38781         transients[key] = fn.call(entity);
38782
38783         return transients[key];
38784     },
38785
38786
38787     parentWays: function(entity) {
38788         var parents = this._parentWays[entity.id],
38789             result = [];
38790
38791         if (parents) {
38792             for (var i = 0; i < parents.length; i++) {
38793                 result.push(this.entity(parents[i]));
38794             }
38795         }
38796         return result;
38797     },
38798
38799
38800     isPoi: function(entity) {
38801         var parentWays = this._parentWays[entity.id];
38802         return !parentWays || parentWays.length === 0;
38803     },
38804
38805
38806     isShared: function(entity) {
38807         var parentWays = this._parentWays[entity.id];
38808         return parentWays && parentWays.length > 1;
38809     },
38810
38811
38812     parentRelations: function(entity) {
38813         var parents = this._parentRels[entity.id],
38814             result = [];
38815
38816         if (parents) {
38817             for (var i = 0; i < parents.length; i++) {
38818                 result.push(this.entity(parents[i]));
38819             }
38820         }
38821         return result;
38822     },
38823
38824
38825     childNodes: function(entity) {
38826         if (this._childNodes[entity.id]) return this._childNodes[entity.id];
38827         if (!entity.nodes) return [];
38828
38829         var nodes = [];
38830         for (var i = 0; i < entity.nodes.length; i++) {
38831             nodes[i] = this.entity(entity.nodes[i]);
38832         }
38833
38834         if (debug) Object.freeze(nodes);
38835
38836         this._childNodes[entity.id] = nodes;
38837         return this._childNodes[entity.id];
38838     },
38839
38840
38841     base: function() {
38842         return {
38843             'entities': utilGetPrototypeOf(this.entities),
38844             'parentWays': utilGetPrototypeOf(this._parentWays),
38845             'parentRels': utilGetPrototypeOf(this._parentRels)
38846         };
38847     },
38848
38849
38850     // Unlike other graph methods, rebase mutates in place. This is because it
38851     // is used only during the history operation that merges newly downloaded
38852     // data into each state. To external consumers, it should appear as if the
38853     // graph always contained the newly downloaded data.
38854     rebase: function(entities, stack, force) {
38855         var base = this.base(),
38856             i, j, k, id;
38857
38858         for (i = 0; i < entities.length; i++) {
38859             var entity = entities[i];
38860
38861             if (!entity.visible || (!force && base.entities[entity.id]))
38862                 continue;
38863
38864             // Merging data into the base graph
38865             base.entities[entity.id] = entity;
38866             this._updateCalculated(undefined, entity, base.parentWays, base.parentRels);
38867
38868             // Restore provisionally-deleted nodes that are discovered to have an extant parent
38869             if (entity.type === 'way') {
38870                 for (j = 0; j < entity.nodes.length; j++) {
38871                     id = entity.nodes[j];
38872                     for (k = 1; k < stack.length; k++) {
38873                         var ents = stack[k].entities;
38874                         if (ents.hasOwnProperty(id) && ents[id] === undefined) {
38875                             delete ents[id];
38876                         }
38877                     }
38878                 }
38879             }
38880         }
38881
38882         for (i = 0; i < stack.length; i++) {
38883             stack[i]._updateRebased();
38884         }
38885     },
38886
38887
38888     _updateRebased: function() {
38889         var base = this.base(),
38890             i, k, child, id, keys;
38891
38892         keys = Object.keys(this._parentWays);
38893         for (i = 0; i < keys.length; i++) {
38894             child = keys[i];
38895             if (base.parentWays[child]) {
38896                 for (k = 0; k < base.parentWays[child].length; k++) {
38897                     id = base.parentWays[child][k];
38898                     if (!this.entities.hasOwnProperty(id) && !lodash.includes(this._parentWays[child], id)) {
38899                         this._parentWays[child].push(id);
38900                     }
38901                 }
38902             }
38903         }
38904
38905         keys = Object.keys(this._parentRels);
38906         for (i = 0; i < keys.length; i++) {
38907             child = keys[i];
38908             if (base.parentRels[child]) {
38909                 for (k = 0; k < base.parentRels[child].length; k++) {
38910                     id = base.parentRels[child][k];
38911                     if (!this.entities.hasOwnProperty(id) && !lodash.includes(this._parentRels[child], id)) {
38912                         this._parentRels[child].push(id);
38913                     }
38914                 }
38915             }
38916         }
38917
38918         this.transients = {};
38919
38920         // this._childNodes is not updated, under the assumption that
38921         // ways are always downloaded with their child nodes.
38922     },
38923
38924
38925     // Updates calculated properties (parentWays, parentRels) for the specified change
38926     _updateCalculated: function(oldentity, entity, parentWays, parentRels) {
38927
38928         parentWays = parentWays || this._parentWays;
38929         parentRels = parentRels || this._parentRels;
38930
38931         var type = entity && entity.type || oldentity && oldentity.type,
38932             removed, added, ways, rels, i;
38933
38934
38935         if (type === 'way') {
38936
38937             // Update parentWays
38938             if (oldentity && entity) {
38939                 removed = lodash.difference(oldentity.nodes, entity.nodes);
38940                 added = lodash.difference(entity.nodes, oldentity.nodes);
38941             } else if (oldentity) {
38942                 removed = oldentity.nodes;
38943                 added = [];
38944             } else if (entity) {
38945                 removed = [];
38946                 added = entity.nodes;
38947             }
38948             for (i = 0; i < removed.length; i++) {
38949                 parentWays[removed[i]] = lodash.without(parentWays[removed[i]], oldentity.id);
38950             }
38951             for (i = 0; i < added.length; i++) {
38952                 ways = lodash.without(parentWays[added[i]], entity.id);
38953                 ways.push(entity.id);
38954                 parentWays[added[i]] = ways;
38955             }
38956
38957         } else if (type === 'relation') {
38958
38959             // Update parentRels
38960             if (oldentity && entity) {
38961                 removed = lodash.difference(oldentity.members, entity.members);
38962                 added = lodash.difference(entity.members, oldentity);
38963             } else if (oldentity) {
38964                 removed = oldentity.members;
38965                 added = [];
38966             } else if (entity) {
38967                 removed = [];
38968                 added = entity.members;
38969             }
38970             for (i = 0; i < removed.length; i++) {
38971                 parentRels[removed[i].id] = lodash.without(parentRels[removed[i].id], oldentity.id);
38972             }
38973             for (i = 0; i < added.length; i++) {
38974                 rels = lodash.without(parentRels[added[i].id], entity.id);
38975                 rels.push(entity.id);
38976                 parentRels[added[i].id] = rels;
38977             }
38978         }
38979     },
38980
38981
38982     replace: function(entity) {
38983         if (this.entities[entity.id] === entity)
38984             return this;
38985
38986         return this.update(function() {
38987             this._updateCalculated(this.entities[entity.id], entity);
38988             this.entities[entity.id] = entity;
38989         });
38990     },
38991
38992
38993     remove: function(entity) {
38994         return this.update(function() {
38995             this._updateCalculated(entity, undefined);
38996             this.entities[entity.id] = undefined;
38997         });
38998     },
38999
39000
39001     revert: function(id) {
39002         var baseEntity = this.base().entities[id],
39003             headEntity = this.entities[id];
39004
39005         if (headEntity === baseEntity)
39006             return this;
39007
39008         return this.update(function() {
39009             this._updateCalculated(headEntity, baseEntity);
39010             delete this.entities[id];
39011         });
39012     },
39013
39014
39015     update: function() {
39016         var graph = this.frozen ? coreGraph$$1(this, true) : this;
39017
39018         for (var i = 0; i < arguments.length; i++) {
39019             arguments[i].call(graph, graph);
39020         }
39021
39022         if (this.frozen) graph.frozen = true;
39023
39024         return graph;
39025     },
39026
39027
39028     // Obliterates any existing entities
39029     load: function(entities) {
39030         var base = this.base();
39031         this.entities = Object.create(base.entities);
39032
39033         for (var i in entities) {
39034             this.entities[i] = entities[i];
39035             this._updateCalculated(base.entities[i], this.entities[i]);
39036         }
39037
39038         return this;
39039     }
39040 };
39041
39042 var index$10 = partialSort;
39043
39044 // Floyd-Rivest selection algorithm:
39045 // Rearrange items so that all items in the [left, k] range are smaller than all items in (k, right];
39046 // The k-th element will have the (k - left + 1)th smallest value in [left, right]
39047
39048 function partialSort(arr, k, left, right, compare) {
39049     left = left || 0;
39050     right = right || (arr.length - 1);
39051     compare = compare || defaultCompare;
39052
39053     while (right > left) {
39054         if (right - left > 600) {
39055             var n = right - left + 1;
39056             var m = k - left + 1;
39057             var z = Math.log(n);
39058             var s = 0.5 * Math.exp(2 * z / 3);
39059             var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
39060             var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
39061             var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
39062             partialSort(arr, k, newLeft, newRight, compare);
39063         }
39064
39065         var t = arr[k];
39066         var i = left;
39067         var j = right;
39068
39069         swap(arr, left, k);
39070         if (compare(arr[right], t) > 0) swap(arr, left, right);
39071
39072         while (i < j) {
39073             swap(arr, i, j);
39074             i++;
39075             j--;
39076             while (compare(arr[i], t) < 0) i++;
39077             while (compare(arr[j], t) > 0) j--;
39078         }
39079
39080         if (compare(arr[left], t) === 0) swap(arr, left, j);
39081         else {
39082             j++;
39083             swap(arr, j, right);
39084         }
39085
39086         if (j <= k) left = j + 1;
39087         if (k <= j) right = j - 1;
39088     }
39089 }
39090
39091 function swap(arr, i, j) {
39092     var tmp = arr[i];
39093     arr[i] = arr[j];
39094     arr[j] = tmp;
39095 }
39096
39097 function defaultCompare(a, b) {
39098     return a < b ? -1 : a > b ? 1 : 0;
39099 }
39100
39101 var index$9 = rbush;
39102
39103
39104
39105 function rbush(maxEntries, format) {
39106     if (!(this instanceof rbush)) return new rbush(maxEntries, format);
39107
39108     // max entries in a node is 9 by default; min node fill is 40% for best performance
39109     this._maxEntries = Math.max(4, maxEntries || 9);
39110     this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
39111
39112     if (format) {
39113         this._initFormat(format);
39114     }
39115
39116     this.clear();
39117 }
39118
39119 rbush.prototype = {
39120
39121     all: function () {
39122         return this._all(this.data, []);
39123     },
39124
39125     search: function (bbox) {
39126
39127         var node = this.data,
39128             result = [],
39129             toBBox = this.toBBox;
39130
39131         if (!intersects$1(bbox, node)) return result;
39132
39133         var nodesToSearch = [],
39134             i, len, child, childBBox;
39135
39136         while (node) {
39137             for (i = 0, len = node.children.length; i < len; i++) {
39138
39139                 child = node.children[i];
39140                 childBBox = node.leaf ? toBBox(child) : child;
39141
39142                 if (intersects$1(bbox, childBBox)) {
39143                     if (node.leaf) result.push(child);
39144                     else if (contains$2(bbox, childBBox)) this._all(child, result);
39145                     else nodesToSearch.push(child);
39146                 }
39147             }
39148             node = nodesToSearch.pop();
39149         }
39150
39151         return result;
39152     },
39153
39154     collides: function (bbox) {
39155
39156         var node = this.data,
39157             toBBox = this.toBBox;
39158
39159         if (!intersects$1(bbox, node)) return false;
39160
39161         var nodesToSearch = [],
39162             i, len, child, childBBox;
39163
39164         while (node) {
39165             for (i = 0, len = node.children.length; i < len; i++) {
39166
39167                 child = node.children[i];
39168                 childBBox = node.leaf ? toBBox(child) : child;
39169
39170                 if (intersects$1(bbox, childBBox)) {
39171                     if (node.leaf || contains$2(bbox, childBBox)) return true;
39172                     nodesToSearch.push(child);
39173                 }
39174             }
39175             node = nodesToSearch.pop();
39176         }
39177
39178         return false;
39179     },
39180
39181     load: function (data) {
39182         if (!(data && data.length)) return this;
39183
39184         if (data.length < this._minEntries) {
39185             for (var i = 0, len = data.length; i < len; i++) {
39186                 this.insert(data[i]);
39187             }
39188             return this;
39189         }
39190
39191         // recursively build the tree with the given data from stratch using OMT algorithm
39192         var node = this._build(data.slice(), 0, data.length - 1, 0);
39193
39194         if (!this.data.children.length) {
39195             // save as is if tree is empty
39196             this.data = node;
39197
39198         } else if (this.data.height === node.height) {
39199             // split root if trees have the same height
39200             this._splitRoot(this.data, node);
39201
39202         } else {
39203             if (this.data.height < node.height) {
39204                 // swap trees if inserted one is bigger
39205                 var tmpNode = this.data;
39206                 this.data = node;
39207                 node = tmpNode;
39208             }
39209
39210             // insert the small tree into the large tree at appropriate level
39211             this._insert(node, this.data.height - node.height - 1, true);
39212         }
39213
39214         return this;
39215     },
39216
39217     insert: function (item) {
39218         if (item) this._insert(item, this.data.height - 1);
39219         return this;
39220     },
39221
39222     clear: function () {
39223         this.data = createNode([]);
39224         return this;
39225     },
39226
39227     remove: function (item, equalsFn) {
39228         if (!item) return this;
39229
39230         var node = this.data,
39231             bbox = this.toBBox(item),
39232             path = [],
39233             indexes = [],
39234             i, parent, index, goingUp;
39235
39236         // depth-first iterative tree traversal
39237         while (node || path.length) {
39238
39239             if (!node) { // go up
39240                 node = path.pop();
39241                 parent = path[path.length - 1];
39242                 i = indexes.pop();
39243                 goingUp = true;
39244             }
39245
39246             if (node.leaf) { // check current node
39247                 index = findItem(item, node.children, equalsFn);
39248
39249                 if (index !== -1) {
39250                     // item found, remove the item and condense tree upwards
39251                     node.children.splice(index, 1);
39252                     path.push(node);
39253                     this._condense(path);
39254                     return this;
39255                 }
39256             }
39257
39258             if (!goingUp && !node.leaf && contains$2(node, bbox)) { // go down
39259                 path.push(node);
39260                 indexes.push(i);
39261                 i = 0;
39262                 parent = node;
39263                 node = node.children[0];
39264
39265             } else if (parent) { // go right
39266                 i++;
39267                 node = parent.children[i];
39268                 goingUp = false;
39269
39270             } else node = null; // nothing found
39271         }
39272
39273         return this;
39274     },
39275
39276     toBBox: function (item) { return item; },
39277
39278     compareMinX: compareNodeMinX,
39279     compareMinY: compareNodeMinY,
39280
39281     toJSON: function () { return this.data; },
39282
39283     fromJSON: function (data) {
39284         this.data = data;
39285         return this;
39286     },
39287
39288     _all: function (node, result) {
39289         var nodesToSearch = [];
39290         while (node) {
39291             if (node.leaf) result.push.apply(result, node.children);
39292             else nodesToSearch.push.apply(nodesToSearch, node.children);
39293
39294             node = nodesToSearch.pop();
39295         }
39296         return result;
39297     },
39298
39299     _build: function (items, left, right, height) {
39300
39301         var N = right - left + 1,
39302             M = this._maxEntries,
39303             node;
39304
39305         if (N <= M) {
39306             // reached leaf level; return leaf
39307             node = createNode(items.slice(left, right + 1));
39308             calcBBox(node, this.toBBox);
39309             return node;
39310         }
39311
39312         if (!height) {
39313             // target height of the bulk-loaded tree
39314             height = Math.ceil(Math.log(N) / Math.log(M));
39315
39316             // target number of root entries to maximize storage utilization
39317             M = Math.ceil(N / Math.pow(M, height - 1));
39318         }
39319
39320         node = createNode([]);
39321         node.leaf = false;
39322         node.height = height;
39323
39324         // split the items into M mostly square tiles
39325
39326         var N2 = Math.ceil(N / M),
39327             N1 = N2 * Math.ceil(Math.sqrt(M)),
39328             i, j, right2, right3;
39329
39330         multiSelect(items, left, right, N1, this.compareMinX);
39331
39332         for (i = left; i <= right; i += N1) {
39333
39334             right2 = Math.min(i + N1 - 1, right);
39335
39336             multiSelect(items, i, right2, N2, this.compareMinY);
39337
39338             for (j = i; j <= right2; j += N2) {
39339
39340                 right3 = Math.min(j + N2 - 1, right2);
39341
39342                 // pack each entry recursively
39343                 node.children.push(this._build(items, j, right3, height - 1));
39344             }
39345         }
39346
39347         calcBBox(node, this.toBBox);
39348
39349         return node;
39350     },
39351
39352     _chooseSubtree: function (bbox, node, level, path) {
39353
39354         var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
39355
39356         while (true) {
39357             path.push(node);
39358
39359             if (node.leaf || path.length - 1 === level) break;
39360
39361             minArea = minEnlargement = Infinity;
39362
39363             for (i = 0, len = node.children.length; i < len; i++) {
39364                 child = node.children[i];
39365                 area = bboxArea(child);
39366                 enlargement = enlargedArea(bbox, child) - area;
39367
39368                 // choose entry with the least area enlargement
39369                 if (enlargement < minEnlargement) {
39370                     minEnlargement = enlargement;
39371                     minArea = area < minArea ? area : minArea;
39372                     targetNode = child;
39373
39374                 } else if (enlargement === minEnlargement) {
39375                     // otherwise choose one with the smallest area
39376                     if (area < minArea) {
39377                         minArea = area;
39378                         targetNode = child;
39379                     }
39380                 }
39381             }
39382
39383             node = targetNode || node.children[0];
39384         }
39385
39386         return node;
39387     },
39388
39389     _insert: function (item, level, isNode) {
39390
39391         var toBBox = this.toBBox,
39392             bbox = isNode ? item : toBBox(item),
39393             insertPath = [];
39394
39395         // find the best node for accommodating the item, saving all nodes along the path too
39396         var node = this._chooseSubtree(bbox, this.data, level, insertPath);
39397
39398         // put the item into the node
39399         node.children.push(item);
39400         extend$1(node, bbox);
39401
39402         // split on node overflow; propagate upwards if necessary
39403         while (level >= 0) {
39404             if (insertPath[level].children.length > this._maxEntries) {
39405                 this._split(insertPath, level);
39406                 level--;
39407             } else break;
39408         }
39409
39410         // adjust bboxes along the insertion path
39411         this._adjustParentBBoxes(bbox, insertPath, level);
39412     },
39413
39414     // split overflowed node into two
39415     _split: function (insertPath, level) {
39416
39417         var node = insertPath[level],
39418             M = node.children.length,
39419             m = this._minEntries;
39420
39421         this._chooseSplitAxis(node, m, M);
39422
39423         var splitIndex = this._chooseSplitIndex(node, m, M);
39424
39425         var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
39426         newNode.height = node.height;
39427         newNode.leaf = node.leaf;
39428
39429         calcBBox(node, this.toBBox);
39430         calcBBox(newNode, this.toBBox);
39431
39432         if (level) insertPath[level - 1].children.push(newNode);
39433         else this._splitRoot(node, newNode);
39434     },
39435
39436     _splitRoot: function (node, newNode) {
39437         // split root node
39438         this.data = createNode([node, newNode]);
39439         this.data.height = node.height + 1;
39440         this.data.leaf = false;
39441         calcBBox(this.data, this.toBBox);
39442     },
39443
39444     _chooseSplitIndex: function (node, m, M) {
39445
39446         var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
39447
39448         minOverlap = minArea = Infinity;
39449
39450         for (i = m; i <= M - m; i++) {
39451             bbox1 = distBBox(node, 0, i, this.toBBox);
39452             bbox2 = distBBox(node, i, M, this.toBBox);
39453
39454             overlap = intersectionArea(bbox1, bbox2);
39455             area = bboxArea(bbox1) + bboxArea(bbox2);
39456
39457             // choose distribution with minimum overlap
39458             if (overlap < minOverlap) {
39459                 minOverlap = overlap;
39460                 index = i;
39461
39462                 minArea = area < minArea ? area : minArea;
39463
39464             } else if (overlap === minOverlap) {
39465                 // otherwise choose distribution with minimum area
39466                 if (area < minArea) {
39467                     minArea = area;
39468                     index = i;
39469                 }
39470             }
39471         }
39472
39473         return index;
39474     },
39475
39476     // sorts node children by the best axis for split
39477     _chooseSplitAxis: function (node, m, M) {
39478
39479         var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX,
39480             compareMinY = node.leaf ? this.compareMinY : compareNodeMinY,
39481             xMargin = this._allDistMargin(node, m, M, compareMinX),
39482             yMargin = this._allDistMargin(node, m, M, compareMinY);
39483
39484         // if total distributions margin value is minimal for x, sort by minX,
39485         // otherwise it's already sorted by minY
39486         if (xMargin < yMargin) node.children.sort(compareMinX);
39487     },
39488
39489     // total margin of all possible split distributions where each node is at least m full
39490     _allDistMargin: function (node, m, M, compare) {
39491
39492         node.children.sort(compare);
39493
39494         var toBBox = this.toBBox,
39495             leftBBox = distBBox(node, 0, m, toBBox),
39496             rightBBox = distBBox(node, M - m, M, toBBox),
39497             margin = bboxMargin(leftBBox) + bboxMargin(rightBBox),
39498             i, child;
39499
39500         for (i = m; i < M - m; i++) {
39501             child = node.children[i];
39502             extend$1(leftBBox, node.leaf ? toBBox(child) : child);
39503             margin += bboxMargin(leftBBox);
39504         }
39505
39506         for (i = M - m - 1; i >= m; i--) {
39507             child = node.children[i];
39508             extend$1(rightBBox, node.leaf ? toBBox(child) : child);
39509             margin += bboxMargin(rightBBox);
39510         }
39511
39512         return margin;
39513     },
39514
39515     _adjustParentBBoxes: function (bbox, path, level) {
39516         // adjust bboxes along the given tree path
39517         for (var i = level; i >= 0; i--) {
39518             extend$1(path[i], bbox);
39519         }
39520     },
39521
39522     _condense: function (path) {
39523         // go through the path, removing empty nodes and updating bboxes
39524         for (var i = path.length - 1, siblings; i >= 0; i--) {
39525             if (path[i].children.length === 0) {
39526                 if (i > 0) {
39527                     siblings = path[i - 1].children;
39528                     siblings.splice(siblings.indexOf(path[i]), 1);
39529
39530                 } else this.clear();
39531
39532             } else calcBBox(path[i], this.toBBox);
39533         }
39534     },
39535
39536     _initFormat: function (format) {
39537         // data format (minX, minY, maxX, maxY accessors)
39538
39539         // uses eval-type function compilation instead of just accepting a toBBox function
39540         // because the algorithms are very sensitive to sorting functions performance,
39541         // so they should be dead simple and without inner calls
39542
39543         var compareArr = ['return a', ' - b', ';'];
39544
39545         this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
39546         this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
39547
39548         this.toBBox = new Function('a',
39549             'return {minX: a' + format[0] +
39550             ', minY: a' + format[1] +
39551             ', maxX: a' + format[2] +
39552             ', maxY: a' + format[3] + '};');
39553     }
39554 };
39555
39556 function findItem(item, items, equalsFn) {
39557     if (!equalsFn) return items.indexOf(item);
39558
39559     for (var i = 0; i < items.length; i++) {
39560         if (equalsFn(item, items[i])) return i;
39561     }
39562     return -1;
39563 }
39564
39565 // calculate node's bbox from bboxes of its children
39566 function calcBBox(node, toBBox) {
39567     distBBox(node, 0, node.children.length, toBBox, node);
39568 }
39569
39570 // min bounding rectangle of node children from k to p-1
39571 function distBBox(node, k, p, toBBox, destNode) {
39572     if (!destNode) destNode = createNode(null);
39573     destNode.minX = Infinity;
39574     destNode.minY = Infinity;
39575     destNode.maxX = -Infinity;
39576     destNode.maxY = -Infinity;
39577
39578     for (var i = k, child; i < p; i++) {
39579         child = node.children[i];
39580         extend$1(destNode, node.leaf ? toBBox(child) : child);
39581     }
39582
39583     return destNode;
39584 }
39585
39586 function extend$1(a, b) {
39587     a.minX = Math.min(a.minX, b.minX);
39588     a.minY = Math.min(a.minY, b.minY);
39589     a.maxX = Math.max(a.maxX, b.maxX);
39590     a.maxY = Math.max(a.maxY, b.maxY);
39591     return a;
39592 }
39593
39594 function compareNodeMinX(a, b) { return a.minX - b.minX; }
39595 function compareNodeMinY(a, b) { return a.minY - b.minY; }
39596
39597 function bboxArea(a)   { return (a.maxX - a.minX) * (a.maxY - a.minY); }
39598 function bboxMargin(a) { return (a.maxX - a.minX) + (a.maxY - a.minY); }
39599
39600 function enlargedArea(a, b) {
39601     return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) *
39602            (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
39603 }
39604
39605 function intersectionArea(a, b) {
39606     var minX = Math.max(a.minX, b.minX),
39607         minY = Math.max(a.minY, b.minY),
39608         maxX = Math.min(a.maxX, b.maxX),
39609         maxY = Math.min(a.maxY, b.maxY);
39610
39611     return Math.max(0, maxX - minX) *
39612            Math.max(0, maxY - minY);
39613 }
39614
39615 function contains$2(a, b) {
39616     return a.minX <= b.minX &&
39617            a.minY <= b.minY &&
39618            b.maxX <= a.maxX &&
39619            b.maxY <= a.maxY;
39620 }
39621
39622 function intersects$1(a, b) {
39623     return b.minX <= a.maxX &&
39624            b.minY <= a.maxY &&
39625            b.maxX >= a.minX &&
39626            b.maxY >= a.minY;
39627 }
39628
39629 function createNode(children) {
39630     return {
39631         children: children,
39632         height: 1,
39633         leaf: true,
39634         minX: Infinity,
39635         minY: Infinity,
39636         maxX: -Infinity,
39637         maxY: -Infinity
39638     };
39639 }
39640
39641 // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
39642 // combines selection algorithm with binary divide & conquer approach
39643
39644 function multiSelect(arr, left, right, n, compare) {
39645     var stack = [left, right],
39646         mid;
39647
39648     while (stack.length) {
39649         right = stack.pop();
39650         left = stack.pop();
39651
39652         if (right - left <= n) continue;
39653
39654         mid = left + Math.ceil((right - left) / n / 2) * n;
39655         index$10(arr, mid, left, right, compare);
39656
39657         stack.push(left, mid, mid, right);
39658     }
39659 }
39660
39661 function coreTree(head) {
39662     var rtree = index$9(),
39663         bboxes = {},
39664         tree = {};
39665
39666
39667     function entityBBox(entity) {
39668         var bbox = entity.extent(head).bbox();
39669         bbox.id = entity.id;
39670         bboxes[entity.id] = bbox;
39671         return bbox;
39672     }
39673
39674
39675     function updateParents(entity, insertions, memo) {
39676         head.parentWays(entity).forEach(function(way) {
39677             if (bboxes[way.id]) {
39678                 rtree.remove(bboxes[way.id]);
39679                 insertions[way.id] = way;
39680             }
39681             updateParents(way, insertions, memo);
39682         });
39683
39684         head.parentRelations(entity).forEach(function(relation) {
39685             if (memo[entity.id]) return;
39686             memo[entity.id] = true;
39687             if (bboxes[relation.id]) {
39688                 rtree.remove(bboxes[relation.id]);
39689                 insertions[relation.id] = relation;
39690             }
39691             updateParents(relation, insertions, memo);
39692         });
39693     }
39694
39695
39696     tree.rebase = function(entities, force) {
39697         var insertions = {};
39698
39699         for (var i = 0; i < entities.length; i++) {
39700             var entity = entities[i];
39701
39702             if (!entity.visible)
39703                 continue;
39704
39705             if (head.entities.hasOwnProperty(entity.id) || bboxes[entity.id]) {
39706                 if (!force) {
39707                     continue;
39708                 } else if (bboxes[entity.id]) {
39709                     rtree.remove(bboxes[entity.id]);
39710                 }
39711             }
39712
39713             insertions[entity.id] = entity;
39714             updateParents(entity, insertions, {});
39715         }
39716
39717         rtree.load(lodash.map(insertions, entityBBox));
39718
39719         return tree;
39720     };
39721
39722
39723     tree.intersects = function(extent, graph) {
39724         if (graph !== head) {
39725             var diff = coreDifference(head, graph),
39726                 insertions = {};
39727
39728             head = graph;
39729
39730             diff.deleted().forEach(function(entity) {
39731                 rtree.remove(bboxes[entity.id]);
39732                 delete bboxes[entity.id];
39733             });
39734
39735             diff.modified().forEach(function(entity) {
39736                 rtree.remove(bboxes[entity.id]);
39737                 insertions[entity.id] = entity;
39738                 updateParents(entity, insertions, {});
39739             });
39740
39741             diff.created().forEach(function(entity) {
39742                 insertions[entity.id] = entity;
39743             });
39744
39745             rtree.load(lodash.map(insertions, entityBBox));
39746         }
39747
39748         return rtree.search(extent.bbox()).map(function(bbox) {
39749             return head.entity(bbox.id);
39750         });
39751     };
39752
39753
39754     return tree;
39755 }
39756
39757 /*
39758  * This code is licensed under the MIT license.
39759  *
39760  * Copyright © 2013, iD authors.
39761  *
39762  * Portions copyright © 2011, Keith Cirkel
39763  * See https://github.com/keithamus/jwerty
39764  *
39765  */
39766 function d3keybinding(namespace$$1) {
39767     var bindings = [];
39768
39769
39770     function testBindings(isCapturing) {
39771         var didMatch = false,
39772             i, binding;
39773
39774         // Most key shortcuts will accept either lower or uppercase ('h' or 'H'),
39775         // so we don't strictly match on the shift key, but we prioritize
39776         // shifted bindings first, and fallback to unshifted only if no match.
39777         // (This lets us differentiate between '←'/'⇧←' or '⌘Z'/'⌘⇧Z')
39778
39779         // priority match shifted bindings first
39780         for (i = 0; i < bindings.length; i++) {
39781             binding = bindings[i];
39782             if (!binding.event.modifiers.shiftKey) continue;  // no shift
39783             if (!!binding.capture !== isCapturing) continue;
39784             if (matches(binding, true)) {
39785                 binding.callback();
39786                 didMatch = true;
39787             }
39788         }
39789
39790         // then unshifted bindings
39791         if (didMatch) return;
39792         for (i = 0; i < bindings.length; i++) {
39793             binding = bindings[i];
39794             if (binding.event.modifiers.shiftKey) continue;   // shift
39795             if (!!binding.capture !== isCapturing) continue;
39796             if (matches(binding, false)) {
39797                 binding.callback();
39798             }
39799         }
39800
39801
39802         function matches(binding, testShift) {
39803             var event$$1 = event;
39804             if (event$$1.key !== undefined) {
39805                 if (binding.event.key === undefined) {
39806                     return false;
39807                 } else if (lodash.isArray(binding.event.key)) {
39808                     if (binding.event.key.map(function(s) { return s.toLowerCase(); }).indexOf(event$$1.key.toLowerCase()) === -1)
39809                         return false;
39810                 } else {
39811                     if (event$$1.key.toLowerCase() !== binding.event.key.toLowerCase())
39812                         return false;
39813                 }
39814             } else {
39815                 // check keycodes if browser doesn't support KeyboardEvent.key
39816                 if (event$$1.keyCode !== binding.event.keyCode)
39817                     return false;
39818             }
39819
39820             // test modifier keys
39821             if (!(event$$1.ctrlKey && event$$1.altKey)) {  // if both are set, assume AltGr and skip it - #4096
39822                 if (event$$1.ctrlKey !== binding.event.modifiers.ctrlKey) return false;
39823                 if (event$$1.altKey !== binding.event.modifiers.altKey) return false;
39824             }
39825             if (event$$1.metaKey !== binding.event.modifiers.metaKey) return false;
39826             if (testShift && event$$1.shiftKey !== binding.event.modifiers.shiftKey) return false;
39827
39828             return true;
39829         }
39830     }
39831
39832
39833     function capture() {
39834         testBindings(true);
39835     }
39836
39837
39838     function bubble() {
39839         var tagName = select(event.target).node().tagName;
39840         if (tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA') {
39841             return;
39842         }
39843         testBindings(false);
39844     }
39845
39846
39847     function keybinding(selection$$1) {
39848         selection$$1 = selection$$1 || select(document);
39849         selection$$1.on('keydown.capture' + namespace$$1, capture, true);
39850         selection$$1.on('keydown.bubble' + namespace$$1, bubble, false);
39851         return keybinding;
39852     }
39853
39854
39855     keybinding.off = function(selection$$1) {
39856         bindings = [];
39857         selection$$1 = selection$$1 || select(document);
39858         selection$$1.on('keydown.capture' + namespace$$1, null);
39859         selection$$1.on('keydown.bubble' + namespace$$1, null);
39860         return keybinding;
39861     };
39862
39863
39864     keybinding.on = function(codes, callback, capture) {
39865         var arr = [].concat(codes);
39866         for (var i = 0; i < arr.length; i++) {
39867             var code = arr[i];
39868             var binding = {
39869                 event: {
39870                     key: undefined,
39871                     keyCode: 0, // only for browsers that don't support KeyboardEvent.key
39872                     modifiers: {
39873                         shiftKey: false,
39874                         ctrlKey: false,
39875                         altKey: false,
39876                         metaKey: false
39877                     }
39878                 },
39879                 capture: capture,
39880                 callback: callback
39881             };
39882
39883             code = code.toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
39884
39885             for (var j = 0; j < code.length; j++) {
39886                 // Normalise matching errors
39887                 if (code[j] === '++') code[j] = '+';
39888
39889                 if (code[j] in d3keybinding.modifierCodes) {
39890                     binding.event.modifiers[d3keybinding.modifierProperties[d3keybinding.modifierCodes[code[j]]]] = true;
39891                 } else {
39892                     binding.event.key = d3keybinding.keys[code[j]] || code[j];
39893                     if (code[j] in d3keybinding.keyCodes) {
39894                         binding.event.keyCode = d3keybinding.keyCodes[code[j]];
39895                     }
39896                 }
39897             }
39898
39899             bindings.push(binding);
39900         }
39901
39902         return keybinding;
39903     };
39904
39905     return keybinding;
39906 }
39907
39908
39909 d3keybinding.modifierCodes = {
39910     // Shift key, ⇧
39911     '⇧': 16, shift: 16,
39912     // CTRL key, on Mac: ⌃
39913     '⌃': 17, ctrl: 17,
39914     // ALT key, on Mac: ⌥ (Alt)
39915     '⌥': 18, alt: 18, option: 18,
39916     // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
39917     '⌘': 91, meta: 91, cmd: 91, 'super': 91, win: 91
39918 };
39919
39920 d3keybinding.modifierProperties = {
39921     16: 'shiftKey',
39922     17: 'ctrlKey',
39923     18: 'altKey',
39924     91: 'metaKey'
39925 };
39926
39927 d3keybinding.keys = {
39928     // Backspace key, on Mac: ⌫ (Backspace)
39929     '⌫': 'Backspace', backspace: 'Backspace',
39930     // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
39931     '⇥': 'Tab', '⇆': 'Tab', tab: 'Tab',
39932     // Return key, ↩
39933     '↩': 'Enter', 'return': 'Enter', enter: 'Enter', '⌅': 'Enter',
39934     // Pause/Break key
39935     'pause': 'Pause', 'pause-break': 'Pause',
39936     // Caps Lock key, ⇪
39937     '⇪': 'CapsLock', caps: 'CapsLock', 'caps-lock': 'CapsLock',
39938     // Escape key, on Mac: ⎋, on Windows: Esc
39939     '⎋': ['Escape', 'Esc'], escape: ['Escape', 'Esc'], esc: ['Escape', 'Esc'],
39940     // Space key
39941     space: [' ', 'Spacebar'],
39942     // Page-Up key, or pgup, on Mac: ↖
39943     '↖': 'PageUp', pgup: 'PageUp', 'page-up': 'PageUp',
39944     // Page-Down key, or pgdown, on Mac: ↘
39945     '↘': 'PageDown', pgdown: 'PageDown', 'page-down': 'PageDown',
39946     // END key, on Mac: ⇟
39947     '⇟': 'End', end: 'End',
39948     // HOME key, on Mac: ⇞
39949     '⇞': 'Home', home: 'Home',
39950     // Insert key, or ins
39951     ins: 'Insert', insert: 'Insert',
39952     // Delete key, on Mac: ⌦ (Delete)
39953     '⌦': ['Delete', 'Del'], del: ['Delete', 'Del'], 'delete': ['Delete', 'Del'],
39954     // Left Arrow Key, or ←
39955     '←': ['ArrowLeft', 'Left'], left: ['ArrowLeft', 'Left'], 'arrow-left': ['ArrowLeft', 'Left'],
39956     // Up Arrow Key, or ↑
39957     '↑': ['ArrowUp', 'Up'], up: ['ArrowUp', 'Up'], 'arrow-up': ['ArrowUp', 'Up'],
39958     // Right Arrow Key, or →
39959     '→': ['ArrowRight', 'Right'], right: ['ArrowRight', 'Right'], 'arrow-right': ['ArrowRight', 'Right'],
39960     // Up Arrow Key, or ↓
39961     '↓': ['ArrowDown', 'Down'], down: ['ArrowDown', 'Down'], 'arrow-down': ['ArrowDown', 'Down'],
39962     // odities, stuff for backward compatibility (browsers and code):
39963     // Num-Multiply, or *
39964     '*': ['*', 'Multiply'], star: ['*', 'Multiply'], asterisk: ['*', 'Multiply'], multiply: ['*', 'Multiply'],
39965     // Num-Plus or +
39966     '+': ['+', 'Add'], 'plus': ['+', 'Add'],
39967     // Num-Subtract, or -
39968     '-': ['-', 'Subtract'], subtract: ['-', 'Subtract'], 'dash': ['-', 'Subtract'],
39969     // Semicolon
39970     semicolon: ';',
39971     // = or equals
39972     equals: '=',
39973     // Comma, or ,
39974     comma: ',',
39975     // Period, or ., or full-stop
39976     period: '.', 'full-stop': '.',
39977     // Slash, or /, or forward-slash
39978     slash: '/', 'forward-slash': '/',
39979     // Tick, or `, or back-quote
39980     tick: '`', 'back-quote': '`',
39981     // Open bracket, or [
39982     'open-bracket': '[',
39983     // Back slash, or \
39984     'back-slash': '\\',
39985     // Close backet, or ]
39986     'close-bracket': ']',
39987     // Apostrophe, or Quote, or '
39988     quote: '\'', apostrophe: '\'',
39989     // NUMPAD 0-9
39990     'num-0': '0',
39991     'num-1': '1',
39992     'num-2': '2',
39993     'num-3': '3',
39994     'num-4': '4',
39995     'num-5': '5',
39996     'num-6': '6',
39997     'num-7': '7',
39998     'num-8': '8',
39999     'num-9': '9',
40000     // F1-F25
40001     f1: 'F1',
40002     f2: 'F2',
40003     f3: 'F3',
40004     f4: 'F4',
40005     f5: 'F5',
40006     f6: 'F6',
40007     f7: 'F7',
40008     f8: 'F8',
40009     f9: 'F9',
40010     f10: 'F10',
40011     f11: 'F11',
40012     f12: 'F12',
40013     f13: 'F13',
40014     f14: 'F14',
40015     f15: 'F15',
40016     f16: 'F16',
40017     f17: 'F17',
40018     f18: 'F18',
40019     f19: 'F19',
40020     f20: 'F20',
40021     f21: 'F21',
40022     f22: 'F22',
40023     f23: 'F23',
40024     f24: 'F24',
40025     f25: 'F25'
40026 };
40027
40028 d3keybinding.keyCodes = {
40029     // Backspace key, on Mac: ⌫ (Backspace)
40030     '⌫': 8, backspace: 8,
40031     // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
40032     '⇥': 9, '⇆': 9, tab: 9,
40033     // Return key, ↩
40034     '↩': 13, 'return': 13, enter: 13, '⌅': 13,
40035     // Pause/Break key
40036     'pause': 19, 'pause-break': 19,
40037     // Caps Lock key, ⇪
40038     '⇪': 20, caps: 20, 'caps-lock': 20,
40039     // Escape key, on Mac: ⎋, on Windows: Esc
40040     '⎋': 27, escape: 27, esc: 27,
40041     // Space key
40042     space: 32,
40043     // Page-Up key, or pgup, on Mac: ↖
40044     '↖': 33, pgup: 33, 'page-up': 33,
40045     // Page-Down key, or pgdown, on Mac: ↘
40046     '↘': 34, pgdown: 34, 'page-down': 34,
40047     // END key, on Mac: ⇟
40048     '⇟': 35, end: 35,
40049     // HOME key, on Mac: ⇞
40050     '⇞': 36, home: 36,
40051     // Insert key, or ins
40052     ins: 45, insert: 45,
40053     // Delete key, on Mac: ⌦ (Delete)
40054     '⌦': 46, del: 46, 'delete': 46,
40055     // Left Arrow Key, or ←
40056     '←': 37, left: 37, 'arrow-left': 37,
40057     // Up Arrow Key, or ↑
40058     '↑': 38, up: 38, 'arrow-up': 38,
40059     // Right Arrow Key, or →
40060     '→': 39, right: 39, 'arrow-right': 39,
40061     // Up Arrow Key, or ↓
40062     '↓': 40, down: 40, 'arrow-down': 40,
40063     // odities, printing characters that come out wrong:
40064     // Firefox Equals
40065     'ffequals': 61,
40066     // Num-Multiply, or *
40067     '*': 106, star: 106, asterisk: 106, multiply: 106,
40068     // Num-Plus or +
40069     '+': 107, 'plus': 107,
40070     // Num-Subtract, or -
40071     '-': 109, subtract: 109,
40072     // Firefox Plus
40073     'ffplus': 171,
40074     // Firefox Minus
40075     'ffminus': 173,
40076     // Semicolon
40077     ';': 186, semicolon: 186,
40078     // = or equals
40079     '=': 187, 'equals': 187,
40080     // Comma, or ,
40081     ',': 188, comma: 188,
40082     // Dash / Underscore key
40083     'dash': 189,
40084     // Period, or ., or full-stop
40085     '.': 190, period: 190, 'full-stop': 190,
40086     // Slash, or /, or forward-slash
40087     '/': 191, slash: 191, 'forward-slash': 191,
40088     // Tick, or `, or back-quote
40089     '`': 192, tick: 192, 'back-quote': 192,
40090     // Open bracket, or [
40091     '[': 219, 'open-bracket': 219,
40092     // Back slash, or \
40093     '\\': 220, 'back-slash': 220,
40094     // Close backet, or ]
40095     ']': 221, 'close-bracket': 221,
40096     // Apostrophe, or Quote, or '
40097     '\'': 222, quote: 222, apostrophe: 222
40098 };
40099
40100 // NUMPAD 0-9
40101 var i$1 = 95;
40102 var n = 0;
40103 while (++i$1 < 106) {
40104     d3keybinding.keyCodes['num-' + n] = i$1;
40105     ++n;
40106 }
40107
40108 // 0-9
40109 i$1 = 47; n = 0;
40110 while (++i$1 < 58) {
40111     d3keybinding.keyCodes[n] = i$1;
40112     ++n;
40113 }
40114
40115 // F1-F25
40116 i$1 = 111; n = 1;
40117 while (++i$1 < 136) {
40118     d3keybinding.keyCodes['f' + n] = i$1;
40119     ++n;
40120 }
40121
40122 // a-z
40123 i$1 = 64;
40124 while (++i$1 < 91) {
40125     d3keybinding.keyCodes[String.fromCharCode(i$1).toLowerCase()] = i$1;
40126 }
40127
40128 function tooltip() {
40129   var tooltip = function(selection$$1) {
40130       selection$$1.each(setup);
40131     },
40132     animation = utilFunctor(false),
40133     html$$1 = utilFunctor(false),
40134     title = function() {
40135       var title = this.getAttribute('data-original-title');
40136       if (title) {
40137         return title;
40138       } else {
40139         title = this.getAttribute('title');
40140         this.removeAttribute('title');
40141         this.setAttribute('data-original-title', title);
40142       }
40143       return title;
40144     },
40145     over = 'mouseenter.tooltip',
40146     out = 'mouseleave.tooltip',
40147     placement = utilFunctor('top');
40148
40149
40150   tooltip.title = function(_) {
40151     if (arguments.length) {
40152       title = utilFunctor(_);
40153       return tooltip;
40154     } else {
40155       return title;
40156     }
40157   };
40158
40159
40160   tooltip.html = function(_) {
40161     if (arguments.length) {
40162       html$$1 = utilFunctor(_);
40163       return tooltip;
40164     } else {
40165       return html$$1;
40166     }
40167   };
40168
40169
40170   tooltip.placement = function(_) {
40171     if (arguments.length) {
40172       placement = utilFunctor(_);
40173       return tooltip;
40174     } else {
40175       return placement;
40176     }
40177   };
40178
40179
40180   tooltip.show = function(selection$$1) {
40181     selection$$1.each(show);
40182   };
40183
40184
40185   tooltip.hide = function(selection$$1) {
40186     selection$$1.each(hide);
40187   };
40188
40189
40190   tooltip.toggle = function(selection$$1) {
40191     selection$$1.each(toggle);
40192   };
40193
40194
40195   tooltip.destroy = function(selection$$1) {
40196     selection$$1
40197       .on(over, null)
40198       .on(out, null)
40199       .attr('title', function() {
40200         return this.getAttribute('data-original-title') || this.getAttribute('title');
40201       })
40202       .attr('data-original-title', null)
40203       .selectAll('.tooltip')
40204       .remove();
40205   };
40206
40207
40208   function setup() {
40209     var root = select(this),
40210         animate = animation.apply(this, arguments),
40211         tip = root.selectAll('.tooltip').data([0]);
40212
40213     var enter = tip.enter()
40214       .append('div')
40215       .attr('class', 'tooltip');
40216
40217     enter
40218       .append('div')
40219       .attr('class', 'tooltip-arrow');
40220
40221     enter
40222       .append('div')
40223       .attr('class', 'tooltip-inner');
40224
40225     tip = enter
40226       .merge(tip);
40227
40228     if (animate) {
40229       tip.classed('fade', true);
40230     }
40231
40232     var place = placement.apply(this, arguments);
40233     tip.classed(place, true);
40234
40235     root.on(over, show);
40236     root.on(out, hide);
40237   }
40238
40239
40240   function show() {
40241     var root = select(this),
40242       content = title.apply(this, arguments),
40243       tip = root.selectAll('.tooltip')
40244         .classed('in', true),
40245       markup = html$$1.apply(this, arguments);
40246
40247     tip.selectAll('.tooltip-inner')[markup ? 'html' : 'text'](content);
40248     var place = placement.apply(this, arguments),
40249       outer = getPosition(root.node()),
40250       inner = getPosition(tip.node()),
40251       pos;
40252
40253     switch (place) {
40254       case 'top':
40255         pos = {x: outer.x + (outer.w - inner.w) / 2, y: outer.y - inner.h};
40256         break;
40257       case 'right':
40258         pos = {x: outer.x + outer.w, y: outer.y + (outer.h - inner.h) / 2};
40259         break;
40260       case 'left':
40261         pos = {x: outer.x - inner.w, y: outer.y + (outer.h - inner.h) / 2};
40262         break;
40263       case 'bottom':
40264         pos = {x: Math.max(0, outer.x + (outer.w - inner.w) / 2), y: outer.y + outer.h};
40265         break;
40266     }
40267
40268     if (pos) {
40269       tip.style('left', ~~pos.x + 'px').style('top', ~~pos.y + 'px');
40270     } else {
40271       tip.style('left', null).style('top', null);
40272     }
40273
40274     this.tooltipVisible = true;
40275   }
40276
40277
40278   function hide() {
40279     select(this).selectAll('.tooltip')
40280       .classed('in', false);
40281
40282     this.tooltipVisible = false;
40283   }
40284
40285
40286   function toggle() {
40287     if (this.tooltipVisible) {
40288       hide.apply(this, arguments);
40289     } else {
40290       show.apply(this, arguments);
40291     }
40292   }
40293
40294   return tooltip;
40295 }
40296
40297
40298 function getPosition(node) {
40299   var mode = select(node).style('position');
40300   if (mode === 'absolute' || mode === 'static') {
40301     return {
40302       x: node.offsetLeft,
40303       y: node.offsetTop,
40304       w: node.offsetWidth,
40305       h: node.offsetHeight
40306     };
40307   } else {
40308     return {
40309       x: 0,
40310       y: 0,
40311       w: node.offsetWidth,
40312       h: node.offsetHeight
40313     };
40314   }
40315 }
40316
40317 function svgAreas$$1(projection$$1, context) {
40318     // Patterns only work in Firefox when set directly on element.
40319     // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
40320     var patterns = {
40321         beach: 'beach',
40322         cemetery: 'cemetery',
40323         construction: 'construction',
40324         farm: 'farmland',
40325         farmland: 'farmland',
40326         grave_yard: 'cemetery',
40327         meadow: 'meadow',
40328         military: 'construction',
40329         orchard: 'orchard',
40330         sand: 'beach',
40331         scrub: 'scrub',
40332         wetland: 'wetland',
40333     };
40334
40335     var patternKeys = ['landuse', 'natural', 'amenity'];
40336
40337
40338     function setPattern(d) {
40339         for (var i = 0; i < patternKeys.length; i++) {
40340             if (d.tags.building && d.tags.building !== 'no') continue;
40341
40342             if (patterns.hasOwnProperty(d.tags[patternKeys[i]])) {
40343                 this.style.fill = this.style.stroke = 'url("#pattern-' + patterns[d.tags[patternKeys[i]]] + '")';
40344                 return;
40345             }
40346         }
40347         this.style.fill = this.style.stroke = '';
40348     }
40349
40350
40351     return function drawAreas(selection$$1, graph, entities, filter) {
40352         var path$$1 = svgPath(projection$$1, graph, true),
40353             areas = {},
40354             multipolygon;
40355
40356         for (var i = 0; i < entities.length; i++) {
40357             var entity = entities[i];
40358             if (entity.geometry(graph) !== 'area') continue;
40359
40360             multipolygon = osmIsSimpleMultipolygonOuterMember(entity, graph);
40361             if (multipolygon) {
40362                 areas[multipolygon.id] = {
40363                     entity: multipolygon.mergeTags(entity.tags),
40364                     area: Math.abs(entity.area(graph))
40365                 };
40366             } else if (!areas[entity.id]) {
40367                 areas[entity.id] = {
40368                     entity: entity,
40369                     area: Math.abs(entity.area(graph))
40370                 };
40371             }
40372         }
40373
40374         areas = values(areas).filter(function hasPath(a) { return path$$1(a.entity); });
40375         areas.sort(function areaSort(a, b) { return b.area - a.area; });
40376         areas = lodash.map(areas, 'entity');
40377
40378         var strokes = areas.filter(function(area$$1) {
40379             return area$$1.type === 'way';
40380         });
40381
40382         var data = {
40383             clip: areas,
40384             shadow: strokes,
40385             stroke: strokes,
40386             fill: areas
40387         };
40388
40389         var clipPaths = context.surface().selectAll('defs').selectAll('.clipPath')
40390            .filter(filter)
40391            .data(data.clip, osmEntity$$1.key);
40392
40393         clipPaths.exit()
40394            .remove();
40395
40396         var clipPathsEnter = clipPaths.enter()
40397            .append('clipPath')
40398            .attr('class', 'clipPath')
40399            .attr('id', function(entity) { return entity.id + '-clippath'; });
40400
40401         clipPathsEnter
40402            .append('path');
40403
40404         clipPaths.merge(clipPathsEnter)
40405            .selectAll('path')
40406            .attr('d', path$$1);
40407
40408
40409         var layer = selection$$1.selectAll('.layer-areas');
40410
40411         var areagroup = layer
40412             .selectAll('g.areagroup')
40413             .data(['fill', 'shadow', 'stroke']);
40414
40415         areagroup = areagroup.enter()
40416             .append('g')
40417             .attr('class', function(d) { return 'areagroup area-' + d; })
40418             .merge(areagroup);
40419
40420         var paths = areagroup
40421             .selectAll('path')
40422             .filter(filter)
40423             .data(function(layer) { return data[layer]; }, osmEntity$$1.key);
40424
40425         paths.exit()
40426             .remove();
40427
40428         var fills = selection$$1.selectAll('.area-fill path.area').nodes();
40429
40430         var bisect = bisector(function(node) {
40431             return -node.__data__.area(graph);
40432         }).left;
40433
40434         function sortedByArea(entity) {
40435             if (this._parent.__data__ === 'fill') {
40436                 return fills[bisect(fills, -entity.area(graph))];
40437             }
40438         }
40439
40440         paths = paths.enter()
40441             .insert('path', sortedByArea)
40442             .merge(paths)
40443             .each(function(entity) {
40444                 var layer = this.parentNode.__data__;
40445
40446                 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
40447
40448                 if (layer === 'fill') {
40449                     this.setAttribute('clip-path', 'url(#' + entity.id + '-clippath)');
40450                     setPattern.apply(this, arguments);
40451                 }
40452             })
40453             .call(svgTagClasses())
40454             .attr('d', path$$1);
40455     };
40456 }
40457
40458 function svgDebug(projection$$1, context) {
40459
40460     function multipolygons(imagery) {
40461         return imagery.map(function(data$$1) {
40462             return {
40463                 type: 'MultiPolygon',
40464                 coordinates: [ data$$1.polygon ]
40465             };
40466         });
40467     }
40468
40469     function drawDebug(selection$$1) {
40470         var showsTile = context.getDebug('tile'),
40471             showsCollision = context.getDebug('collision'),
40472             showsImagery = context.getDebug('imagery'),
40473             showsImperial = context.getDebug('imperial'),
40474             showsDriveLeft = context.getDebug('driveLeft'),
40475             path$$1 = index$4(projection$$1);
40476
40477
40478         var debugData = [];
40479         if (showsTile) {
40480             debugData.push({ class: 'red', label: 'tile' });
40481         }
40482         if (showsCollision) {
40483             debugData.push({ class: 'yellow', label: 'collision' });
40484         }
40485         if (showsImagery) {
40486             debugData.push({ class: 'orange', label: 'imagery' });
40487         }
40488         if (showsImperial) {
40489             debugData.push({ class: 'cyan', label: 'imperial' });
40490         }
40491         if (showsDriveLeft) {
40492             debugData.push({ class: 'green', label: 'driveLeft' });
40493         }
40494
40495
40496         var legend = select('#content')
40497             .selectAll('.debug-legend')
40498             .data(debugData.length ? [0] : []);
40499
40500         legend.exit()
40501             .remove();
40502
40503         legend = legend.enter()
40504             .append('div')
40505             .attr('class', 'fillD debug-legend')
40506             .merge(legend);
40507
40508
40509         var legendItems = legend.selectAll('.debug-legend-item')
40510             .data(debugData, function(d) { return d.label; });
40511
40512         legendItems.exit()
40513             .remove();
40514
40515         legendItems.enter()
40516             .append('span')
40517             .attr('class', function(d) { return 'debug-legend-item ' + d.class; })
40518             .text(function(d) { return d.label; });
40519
40520
40521         var layer = selection$$1.selectAll('.layer-debug')
40522             .data(showsImagery || showsImperial || showsDriveLeft ? [0] : []);
40523
40524         layer.exit()
40525             .remove();
40526
40527         layer = layer.enter()
40528             .append('g')
40529             .attr('class', 'layer-debug')
40530             .merge(layer);
40531
40532
40533         var extent$$1 = context.map().extent(),
40534             dataImagery = data.imagery || [],
40535             availableImagery = showsImagery && multipolygons(dataImagery.filter(function(source) {
40536                 if (!source.polygon) return false;
40537                 return source.polygon.some(function(polygon) {
40538                     return geoPolygonIntersectsPolygon(polygon, extent$$1, true);
40539                 });
40540             }));
40541
40542         var imagery = layer.selectAll('path.debug-imagery')
40543             .data(showsImagery ? availableImagery : []);
40544
40545         imagery.exit()
40546             .remove();
40547
40548         imagery.enter()
40549             .append('path')
40550             .attr('class', 'debug-imagery debug orange');
40551
40552
40553         var imperial = layer
40554             .selectAll('path.debug-imperial')
40555             .data(showsImperial ? [dataImperial] : []);
40556
40557         imperial.exit()
40558             .remove();
40559
40560         imperial.enter()
40561             .append('path')
40562             .attr('class', 'debug-imperial debug cyan');
40563
40564
40565         var driveLeft = layer
40566             .selectAll('path.debug-drive-left')
40567             .data(showsDriveLeft ? [dataDriveLeft] : []);
40568
40569         driveLeft.exit()
40570             .remove();
40571
40572         driveLeft.enter()
40573             .append('path')
40574             .attr('class', 'debug-drive-left debug green');
40575
40576
40577         // update
40578         layer.selectAll('path')
40579             .attr('d', path$$1);
40580     }
40581
40582
40583     // This looks strange because `enabled` methods on other layers are
40584     // chainable getter/setters, and this one is just a getter.
40585     drawDebug.enabled = function() {
40586         if (!arguments.length) {
40587             return context.getDebug('tile') ||
40588                 context.getDebug('collision') ||
40589                 context.getDebug('imagery') ||
40590                 context.getDebug('imperial') ||
40591                 context.getDebug('driveLeft');
40592         } else {
40593             return this;
40594         }
40595     };
40596
40597
40598     return drawDebug;
40599 }
40600
40601 /*
40602     A standalone SVG element that contains only a `defs` sub-element. To be
40603     used once globally, since defs IDs must be unique within a document.
40604 */
40605 function svgDefs(context) {
40606
40607     function SVGSpriteDefinition(id, href) {
40608         return function(defs) {
40609             request(href)
40610                 .mimeType('image/svg+xml')
40611                 .response(function(xhr) { return xhr.responseXML; })
40612                 .get(function(err, svg) {
40613                     if (err) return;
40614                     defs.node().appendChild(
40615                         select(svg.documentElement).attr('id', id).node()
40616                     );
40617                 });
40618         };
40619     }
40620
40621
40622     return function drawDefs(selection$$1) {
40623         var defs = selection$$1.append('defs');
40624
40625         // marker
40626         defs.append('marker')
40627             .attr('id', 'oneway-marker')
40628             .attr('viewBox', '0 0 10 10')
40629             .attr('refY', 2.5)
40630             .attr('refX', 5)
40631             .attr('markerWidth', 2)
40632             .attr('markerHeight', 2)
40633             .attr('markerUnits', 'strokeWidth')
40634             .attr('orient', 'auto')
40635
40636             .append('path')
40637             .attr('class', 'oneway')
40638             .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')
40639             .attr('stroke', 'none')
40640             .attr('fill', '#000')
40641             .attr('opacity', '0.75');
40642
40643         // patterns
40644         var patterns = defs.selectAll('pattern')
40645             .data([
40646                 // pattern name, pattern image name
40647                 ['wetland', 'wetland'],
40648                 ['construction', 'construction'],
40649                 ['cemetery', 'cemetery'],
40650                 ['orchard', 'orchard'],
40651                 ['farmland', 'farmland'],
40652                 ['beach', 'dots'],
40653                 ['scrub', 'dots'],
40654                 ['meadow', 'dots']
40655             ])
40656             .enter()
40657             .append('pattern')
40658             .attr('id', function (d) {
40659                 return 'pattern-' + d[0];
40660             })
40661             .attr('width', 32)
40662             .attr('height', 32)
40663             .attr('patternUnits', 'userSpaceOnUse');
40664
40665         patterns.append('rect')
40666             .attr('x', 0)
40667             .attr('y', 0)
40668             .attr('width', 32)
40669             .attr('height', 32)
40670             .attr('class', function (d) {
40671                     return 'pattern-color-' + d[0];
40672             });
40673
40674         patterns.append('image')
40675             .attr('x', 0)
40676             .attr('y', 0)
40677             .attr('width', 32)
40678             .attr('height', 32)
40679             .attr('xlink:href', function (d) {
40680                 return context.imagePath('pattern/' + d[1] + '.png');
40681             });
40682
40683         // clip paths
40684         defs.selectAll()
40685             .data([12, 18, 20, 32, 45])
40686             .enter()
40687             .append('clipPath')
40688             .attr('id', function (d) {
40689                 return 'clip-square-' + d;
40690             })
40691             .append('rect')
40692             .attr('x', 0)
40693             .attr('y', 0)
40694             .attr('width', function (d) {
40695                 return d;
40696             })
40697             .attr('height', function (d) {
40698                 return d;
40699             });
40700
40701         defs.call(SVGSpriteDefinition(
40702             'iD-sprite',
40703             context.imagePath('iD-sprite.svg')));
40704
40705         defs.call(SVGSpriteDefinition(
40706             'maki-sprite',
40707             context.imagePath('maki-sprite.svg')));
40708     };
40709 }
40710
40711 //[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]
40712 //[4a]          NameChar           ::=          NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
40713 //[5]           Name       ::=          NameStartChar (NameChar)*
40714 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
40715 var nameChar = new RegExp("[\\-\\.0-9"+nameStartChar.source.slice(1,-1)+"\\u00B7\\u0300-\\u036F\\u203F-\\u2040]");
40716 var tagNamePattern = new RegExp('^'+nameStartChar.source+nameChar.source+'*(?:\:'+nameStartChar.source+nameChar.source+'*)?$');
40717 //var tagNamePattern = /^[a-zA-Z_][\w\-\.]*(?:\:[a-zA-Z_][\w\-\.]*)?$/
40718 //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(',')
40719
40720 //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
40721 //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
40722 var S_TAG = 0;//tag name offerring
40723 var S_ATTR = 1;//attr name offerring 
40724 var S_ATTR_SPACE=2;//attr name end and space offer
40725 var S_EQ = 3;//=space?
40726 var S_ATTR_NOQUOT_VALUE = 4;//attr value(no quot value only)
40727 var S_ATTR_END = 5;//attr value end and no space(quot end)
40728 var S_TAG_SPACE = 6;//(attr value end || tag end ) && (space offer)
40729 var S_TAG_CLOSE = 7;//closed el<el />
40730
40731 function XMLReader(){
40732         
40733 }
40734
40735 XMLReader.prototype = {
40736         parse:function(source,defaultNSMap,entityMap){
40737                 var domBuilder = this.domBuilder;
40738                 domBuilder.startDocument();
40739                 _copy(defaultNSMap ,defaultNSMap = {});
40740                 parse(source,defaultNSMap,entityMap,
40741                                 domBuilder,this.errorHandler);
40742                 domBuilder.endDocument();
40743         }
40744 };
40745 function parse(source,defaultNSMapCopy,entityMap,domBuilder,errorHandler){
40746         function fixedFromCharCode(code) {
40747                 // String.prototype.fromCharCode does not supports
40748                 // > 2 bytes unicode chars directly
40749                 if (code > 0xffff) {
40750                         code -= 0x10000;
40751                         var surrogate1 = 0xd800 + (code >> 10)
40752                                 , surrogate2 = 0xdc00 + (code & 0x3ff);
40753
40754                         return String.fromCharCode(surrogate1, surrogate2);
40755                 } else {
40756                         return String.fromCharCode(code);
40757                 }
40758         }
40759         function entityReplacer(a){
40760                 var k = a.slice(1,-1);
40761                 if(k in entityMap){
40762                         return entityMap[k]; 
40763                 }else if(k.charAt(0) === '#'){
40764                         return fixedFromCharCode(parseInt(k.substr(1).replace('x','0x')))
40765                 }else{
40766                         errorHandler.error('entity not found:'+a);
40767                         return a;
40768                 }
40769         }
40770         function appendText(end){//has some bugs
40771                 if(end>start){
40772                         var xt = source.substring(start,end).replace(/&#?\w+;/g,entityReplacer);
40773                         locator&&position(start);
40774                         domBuilder.characters(xt,0,end-start);
40775                         start = end;
40776                 }
40777         }
40778         function position(p,m){
40779                 while(p>=lineEnd && (m = linePattern.exec(source))){
40780                         lineStart = m.index;
40781                         lineEnd = lineStart + m[0].length;
40782                         locator.lineNumber++;
40783                         //console.log('line++:',locator,startPos,endPos)
40784                 }
40785                 locator.columnNumber = p-lineStart+1;
40786         }
40787         var lineStart = 0;
40788         var lineEnd = 0;
40789         var linePattern = /.*(?:\r\n?|\n)|.*$/g;
40790         var locator = domBuilder.locator;
40791         
40792         var parseStack = [{currentNSMap:defaultNSMapCopy}];
40793         var closeMap = {};
40794         var start = 0;
40795         while(true){
40796                 try{
40797                         var tagStart = source.indexOf('<',start);
40798                         if(tagStart<0){
40799                                 if(!source.substr(start).match(/^\s*$/)){
40800                                         var doc = domBuilder.doc;
40801                                 var text = doc.createTextNode(source.substr(start));
40802                                 doc.appendChild(text);
40803                                 domBuilder.currentElement = text;
40804                                 }
40805                                 return;
40806                         }
40807                         if(tagStart>start){
40808                                 appendText(tagStart);
40809                         }
40810                         switch(source.charAt(tagStart+1)){
40811                         case '/':
40812                                 var end = source.indexOf('>',tagStart+3);
40813                                 var tagName = source.substring(tagStart+2,end);
40814                                 var config = parseStack.pop();
40815                                 if(end<0){
40816                                         
40817                                 tagName = source.substring(tagStart+2).replace(/[\s<].*/,'');
40818                                 //console.error('#@@@@@@'+tagName)
40819                                 errorHandler.error("end tag name: "+tagName+' is not complete:'+config.tagName);
40820                                 end = tagStart+1+tagName.length;
40821                         }else if(tagName.match(/\s</)){
40822                                 tagName = tagName.replace(/[\s<].*/,'');
40823                                 errorHandler.error("end tag name: "+tagName+' maybe not complete');
40824                                 end = tagStart+1+tagName.length;
40825                                 }
40826                                 //console.error(parseStack.length,parseStack)
40827                                 //console.error(config);
40828                                 var localNSMap = config.localNSMap;
40829                                 var endMatch = config.tagName == tagName;
40830                                 var endIgnoreCaseMach = endMatch || config.tagName&&config.tagName.toLowerCase() == tagName.toLowerCase();
40831                         if(endIgnoreCaseMach){
40832                                 domBuilder.endElement(config.uri,config.localName,tagName);
40833                                         if(localNSMap){
40834                                                 for(var prefix in localNSMap){
40835                                                         domBuilder.endPrefixMapping(prefix) ;
40836                                                 }
40837                                         }
40838                                         if(!endMatch){
40839                                 errorHandler.fatalError("end tag name: "+tagName+' is not match the current start tagName:'+config.tagName );
40840                                         }
40841                         }else{
40842                                 parseStack.push(config);
40843                         }
40844                                 
40845                                 end++;
40846                                 break;
40847                                 // end elment
40848                         case '?':// <?...?>
40849                                 locator&&position(tagStart);
40850                                 end = parseInstruction(source,tagStart,domBuilder);
40851                                 break;
40852                         case '!':// <!doctype,<![CDATA,<!--
40853                                 locator&&position(tagStart);
40854                                 end = parseDCC(source,tagStart,domBuilder,errorHandler);
40855                                 break;
40856                         default:
40857                                 locator&&position(tagStart);
40858                                 var el = new ElementAttributes();
40859                                 var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
40860                                 //elStartEnd
40861                                 var end = parseElementStartPart(source,tagStart,el,currentNSMap,entityReplacer,errorHandler);
40862                                 var len = el.length;
40863                                 
40864                                 
40865                                 if(!el.closed && fixSelfClosed(source,end,el.tagName,closeMap)){
40866                                         el.closed = true;
40867                                         if(!entityMap.nbsp){
40868                                                 errorHandler.warning('unclosed xml attribute');
40869                                         }
40870                                 }
40871                                 if(locator && len){
40872                                         var locator2 = copyLocator(locator,{});
40873                                         //try{//attribute position fixed
40874                                         for(var i = 0;i<len;i++){
40875                                                 var a = el[i];
40876                                                 position(a.offset);
40877                                                 a.locator = copyLocator(locator,{});
40878                                         }
40879                                         //}catch(e){console.error('@@@@@'+e)}
40880                                         domBuilder.locator = locator2;
40881                                         if(appendElement(el,domBuilder,currentNSMap)){
40882                                                 parseStack.push(el);
40883                                         }
40884                                         domBuilder.locator = locator;
40885                                 }else{
40886                                         if(appendElement(el,domBuilder,currentNSMap)){
40887                                                 parseStack.push(el);
40888                                         }
40889                                 }
40890                                 
40891                                 
40892                                 
40893                                 if(el.uri === 'http://www.w3.org/1999/xhtml' && !el.closed){
40894                                         end = parseHtmlSpecialContent(source,end,el.tagName,entityReplacer,domBuilder);
40895                                 }else{
40896                                         end++;
40897                                 }
40898                         }
40899                 }catch(e){
40900                         errorHandler.error('element parse error: '+e);
40901                         //errorHandler.error('element parse error: '+e);
40902                         end = -1;
40903                         //throw e;
40904                 }
40905                 if(end>start){
40906                         start = end;
40907                 }else{
40908                         //TODO: 这里有可能sax回退,有位置错误风险
40909                         appendText(Math.max(tagStart,start)+1);
40910                 }
40911         }
40912 }
40913 function copyLocator(f,t){
40914         t.lineNumber = f.lineNumber;
40915         t.columnNumber = f.columnNumber;
40916         return t;
40917 }
40918
40919 /**
40920  * @see #appendElement(source,elStartEnd,el,selfClosed,entityReplacer,domBuilder,parseStack);
40921  * @return end of the elementStartPart(end of elementEndPart for selfClosed el)
40922  */
40923 function parseElementStartPart(source,start,el,currentNSMap,entityReplacer,errorHandler){
40924         var attrName;
40925         var value;
40926         var p = ++start;
40927         var s = S_TAG;//status
40928         while(true){
40929                 var c = source.charAt(p);
40930                 switch(c){
40931                 case '=':
40932                         if(s === S_ATTR){//attrName
40933                                 attrName = source.slice(start,p);
40934                                 s = S_EQ;
40935                         }else if(s === S_ATTR_SPACE){
40936                                 s = S_EQ;
40937                         }else{
40938                                 //fatalError: equal must after attrName or space after attrName
40939                                 throw new Error('attribute equal must after attrName');
40940                         }
40941                         break;
40942                 case '\'':
40943                 case '"':
40944                         if(s === S_EQ || s === S_ATTR //|| s == S_ATTR_SPACE
40945                                 ){//equal
40946                                 if(s === S_ATTR){
40947                                         errorHandler.warning('attribute value must after "="');
40948                                         attrName = source.slice(start,p);
40949                                 }
40950                                 start = p+1;
40951                                 p = source.indexOf(c,start);
40952                                 if(p>0){
40953                                         value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
40954                                         el.add(attrName,value,start-1);
40955                                         s = S_ATTR_END;
40956                                 }else{
40957                                         //fatalError: no end quot match
40958                                         throw new Error('attribute value no end \''+c+'\' match');
40959                                 }
40960                         }else if(s == S_ATTR_NOQUOT_VALUE){
40961                                 value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
40962                                 //console.log(attrName,value,start,p)
40963                                 el.add(attrName,value,start);
40964                                 //console.dir(el)
40965                                 errorHandler.warning('attribute "'+attrName+'" missed start quot('+c+')!!');
40966                                 start = p+1;
40967                                 s = S_ATTR_END;
40968                         }else{
40969                                 //fatalError: no equal before
40970                                 throw new Error('attribute value must after "="');
40971                         }
40972                         break;
40973                 case '/':
40974                         switch(s){
40975                         case S_TAG:
40976                                 el.setTagName(source.slice(start,p));
40977                         case S_ATTR_END:
40978                         case S_TAG_SPACE:
40979                         case S_TAG_CLOSE:
40980                                 s =S_TAG_CLOSE;
40981                                 el.closed = true;
40982                         case S_ATTR_NOQUOT_VALUE:
40983                         case S_ATTR:
40984                         case S_ATTR_SPACE:
40985                                 break;
40986                         //case S_EQ:
40987                         default:
40988                                 throw new Error("attribute invalid close char('/')")
40989                         }
40990                         break;
40991                 case ''://end document
40992                         //throw new Error('unexpected end of input')
40993                         errorHandler.error('unexpected end of input');
40994                         if(s == S_TAG){
40995                                 el.setTagName(source.slice(start,p));
40996                         }
40997                         return p;
40998                 case '>':
40999                         switch(s){
41000                         case S_TAG:
41001                                 el.setTagName(source.slice(start,p));
41002                         case S_ATTR_END:
41003                         case S_TAG_SPACE:
41004                         case S_TAG_CLOSE:
41005                                 break;//normal
41006                         case S_ATTR_NOQUOT_VALUE://Compatible state
41007                         case S_ATTR:
41008                                 value = source.slice(start,p);
41009                                 if(value.slice(-1) === '/'){
41010                                         el.closed  = true;
41011                                         value = value.slice(0,-1);
41012                                 }
41013                         case S_ATTR_SPACE:
41014                                 if(s === S_ATTR_SPACE){
41015                                         value = attrName;
41016                                 }
41017                                 if(s == S_ATTR_NOQUOT_VALUE){
41018                                         errorHandler.warning('attribute "'+value+'" missed quot(")!!');
41019                                         el.add(attrName,value.replace(/&#?\w+;/g,entityReplacer),start);
41020                                 }else{
41021                                         if(currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !value.match(/^(?:disabled|checked|selected)$/i)){
41022                                                 errorHandler.warning('attribute "'+value+'" missed value!! "'+value+'" instead!!');
41023                                         }
41024                                         el.add(value,value,start);
41025                                 }
41026                                 break;
41027                         case S_EQ:
41028                                 throw new Error('attribute value missed!!');
41029                         }
41030 //                      console.log(tagName,tagNamePattern,tagNamePattern.test(tagName))
41031                         return p;
41032                 /*xml space '\x20' | #x9 | #xD | #xA; */
41033                 case '\u0080':
41034                         c = ' ';
41035                 default:
41036                         if(c<= ' '){//space
41037                                 switch(s){
41038                                 case S_TAG:
41039                                         el.setTagName(source.slice(start,p));//tagName
41040                                         s = S_TAG_SPACE;
41041                                         break;
41042                                 case S_ATTR:
41043                                         attrName = source.slice(start,p);
41044                                         s = S_ATTR_SPACE;
41045                                         break;
41046                                 case S_ATTR_NOQUOT_VALUE:
41047                                         var value = source.slice(start,p).replace(/&#?\w+;/g,entityReplacer);
41048                                         errorHandler.warning('attribute "'+value+'" missed quot(")!!');
41049                                         el.add(attrName,value,start);
41050                                 case S_ATTR_END:
41051                                         s = S_TAG_SPACE;
41052                                         break;
41053                                 //case S_TAG_SPACE:
41054                                 //case S_EQ:
41055                                 //case S_ATTR_SPACE:
41056                                 //      void();break;
41057                                 //case S_TAG_CLOSE:
41058                                         //ignore warning
41059                                 }
41060                         }else{//not space
41061 //S_TAG,        S_ATTR, S_EQ,   S_ATTR_NOQUOT_VALUE
41062 //S_ATTR_SPACE, S_ATTR_END,     S_TAG_SPACE, S_TAG_CLOSE
41063                                 switch(s){
41064                                 //case S_TAG:void();break;
41065                                 //case S_ATTR:void();break;
41066                                 //case S_ATTR_NOQUOT_VALUE:void();break;
41067                                 case S_ATTR_SPACE:
41068                                         var tagName =  el.tagName;
41069                                         if(currentNSMap[''] !== 'http://www.w3.org/1999/xhtml' || !attrName.match(/^(?:disabled|checked|selected)$/i)){
41070                                                 errorHandler.warning('attribute "'+attrName+'" missed value!! "'+attrName+'" instead2!!');
41071                                         }
41072                                         el.add(attrName,attrName,start);
41073                                         start = p;
41074                                         s = S_ATTR;
41075                                         break;
41076                                 case S_ATTR_END:
41077                                         errorHandler.warning('attribute space is required"'+attrName+'"!!');
41078                                 case S_TAG_SPACE:
41079                                         s = S_ATTR;
41080                                         start = p;
41081                                         break;
41082                                 case S_EQ:
41083                                         s = S_ATTR_NOQUOT_VALUE;
41084                                         start = p;
41085                                         break;
41086                                 case S_TAG_CLOSE:
41087                                         throw new Error("elements closed character '/' and '>' must be connected to");
41088                                 }
41089                         }
41090                 }//end outer switch
41091                 //console.log('p++',p)
41092                 p++;
41093         }
41094 }
41095 /**
41096  * @return true if has new namespace define
41097  */
41098 function appendElement(el,domBuilder,currentNSMap){
41099         var tagName = el.tagName;
41100         var localNSMap = null;
41101         //var currentNSMap = parseStack[parseStack.length-1].currentNSMap;
41102         var i = el.length;
41103         while(i--){
41104                 var a = el[i];
41105                 var qName = a.qName;
41106                 var value = a.value;
41107                 var nsp = qName.indexOf(':');
41108                 if(nsp>0){
41109                         var prefix = a.prefix = qName.slice(0,nsp);
41110                         var localName = qName.slice(nsp+1);
41111                         var nsPrefix = prefix === 'xmlns' && localName;
41112                 }else{
41113                         localName = qName;
41114                         prefix = null;
41115                         nsPrefix = qName === 'xmlns' && '';
41116                 }
41117                 //can not set prefix,because prefix !== ''
41118                 a.localName = localName ;
41119                 //prefix == null for no ns prefix attribute 
41120                 if(nsPrefix !== false){//hack!!
41121                         if(localNSMap == null){
41122                                 localNSMap = {};
41123                                 //console.log(currentNSMap,0)
41124                                 _copy(currentNSMap,currentNSMap={});
41125                                 //console.log(currentNSMap,1)
41126                         }
41127                         currentNSMap[nsPrefix] = localNSMap[nsPrefix] = value;
41128                         a.uri = 'http://www.w3.org/2000/xmlns/';
41129                         domBuilder.startPrefixMapping(nsPrefix, value); 
41130                 }
41131         }
41132         var i = el.length;
41133         while(i--){
41134                 a = el[i];
41135                 var prefix = a.prefix;
41136                 if(prefix){//no prefix attribute has no namespace
41137                         if(prefix === 'xml'){
41138                                 a.uri = 'http://www.w3.org/XML/1998/namespace';
41139                         }if(prefix !== 'xmlns'){
41140                                 a.uri = currentNSMap[prefix || ''];
41141                                 
41142                                 //{console.log('###'+a.qName,domBuilder.locator.systemId+'',currentNSMap,a.uri)}
41143                         }
41144                 }
41145         }
41146         var nsp = tagName.indexOf(':');
41147         if(nsp>0){
41148                 prefix = el.prefix = tagName.slice(0,nsp);
41149                 localName = el.localName = tagName.slice(nsp+1);
41150         }else{
41151                 prefix = null;//important!!
41152                 localName = el.localName = tagName;
41153         }
41154         //no prefix element has default namespace
41155         var ns = el.uri = currentNSMap[prefix || ''];
41156         domBuilder.startElement(ns,localName,tagName,el);
41157         //endPrefixMapping and startPrefixMapping have not any help for dom builder
41158         //localNSMap = null
41159         if(el.closed){
41160                 domBuilder.endElement(ns,localName,tagName);
41161                 if(localNSMap){
41162                         for(prefix in localNSMap){
41163                                 domBuilder.endPrefixMapping(prefix); 
41164                         }
41165                 }
41166         }else{
41167                 el.currentNSMap = currentNSMap;
41168                 el.localNSMap = localNSMap;
41169                 //parseStack.push(el);
41170                 return true;
41171         }
41172 }
41173 function parseHtmlSpecialContent(source,elStartEnd,tagName,entityReplacer,domBuilder){
41174         if(/^(?:script|textarea)$/i.test(tagName)){
41175                 var elEndStart =  source.indexOf('</'+tagName+'>',elStartEnd);
41176                 var text = source.substring(elStartEnd+1,elEndStart);
41177                 if(/[&<]/.test(text)){
41178                         if(/^script$/i.test(tagName)){
41179                                 //if(!/\]\]>/.test(text)){
41180                                         //lexHandler.startCDATA();
41181                                         domBuilder.characters(text,0,text.length);
41182                                         //lexHandler.endCDATA();
41183                                         return elEndStart;
41184                                 //}
41185                         }//}else{//text area
41186                                 text = text.replace(/&#?\w+;/g,entityReplacer);
41187                                 domBuilder.characters(text,0,text.length);
41188                                 return elEndStart;
41189                         //}
41190                         
41191                 }
41192         }
41193         return elStartEnd+1;
41194 }
41195 function fixSelfClosed(source,elStartEnd,tagName,closeMap){
41196         //if(tagName in closeMap){
41197         var pos = closeMap[tagName];
41198         if(pos == null){
41199                 //console.log(tagName)
41200                 pos =  source.lastIndexOf('</'+tagName+'>');
41201                 if(pos<elStartEnd){//忘记闭合
41202                         pos = source.lastIndexOf('</'+tagName);
41203                 }
41204                 closeMap[tagName] =pos;
41205         }
41206         return pos<elStartEnd;
41207         //} 
41208 }
41209 function _copy(source,target){
41210         for(var n in source){target[n] = source[n];}
41211 }
41212 function parseDCC(source,start,domBuilder,errorHandler){//sure start with '<!'
41213         var next= source.charAt(start+2);
41214         switch(next){
41215         case '-':
41216                 if(source.charAt(start + 3) === '-'){
41217                         var end = source.indexOf('-->',start+4);
41218                         //append comment source.substring(4,end)//<!--
41219                         if(end>start){
41220                                 domBuilder.comment(source,start+4,end-start-4);
41221                                 return end+3;
41222                         }else{
41223                                 errorHandler.error("Unclosed comment");
41224                                 return -1;
41225                         }
41226                 }else{
41227                         //error
41228                         return -1;
41229                 }
41230         default:
41231                 if(source.substr(start+3,6) == 'CDATA['){
41232                         var end = source.indexOf(']]>',start+9);
41233                         domBuilder.startCDATA();
41234                         domBuilder.characters(source,start+9,end-start-9);
41235                         domBuilder.endCDATA(); 
41236                         return end+3;
41237                 }
41238                 //<!DOCTYPE
41239                 //startDTD(java.lang.String name, java.lang.String publicId, java.lang.String systemId) 
41240                 var matchs = split(source,start);
41241                 var len = matchs.length;
41242                 if(len>1 && /!doctype/i.test(matchs[0][0])){
41243                         var name = matchs[1][0];
41244                         var pubid = len>3 && /^public$/i.test(matchs[2][0]) && matchs[3][0];
41245                         var sysid = len>4 && matchs[4][0];
41246                         var lastMatch = matchs[len-1];
41247                         domBuilder.startDTD(name,pubid && pubid.replace(/^(['"])(.*?)\1$/,'$2'),
41248                                         sysid && sysid.replace(/^(['"])(.*?)\1$/,'$2'));
41249                         domBuilder.endDTD();
41250                         
41251                         return lastMatch.index+lastMatch[0].length
41252                 }
41253         }
41254         return -1;
41255 }
41256
41257
41258
41259 function parseInstruction(source,start,domBuilder){
41260         var end = source.indexOf('?>',start);
41261         if(end){
41262                 var match = source.substring(start,end).match(/^<\?(\S*)\s*([\s\S]*?)\s*$/);
41263                 if(match){
41264                         var len = match[0].length;
41265                         domBuilder.processingInstruction(match[1], match[2]) ;
41266                         return end+2;
41267                 }else{//error
41268                         return -1;
41269                 }
41270         }
41271         return -1;
41272 }
41273
41274 /**
41275  * @param source
41276  */
41277 function ElementAttributes(source){
41278         
41279 }
41280 ElementAttributes.prototype = {
41281         setTagName:function(tagName){
41282                 if(!tagNamePattern.test(tagName)){
41283                         throw new Error('invalid tagName:'+tagName)
41284                 }
41285                 this.tagName = tagName;
41286         },
41287         add:function(qName,value,offset){
41288                 if(!tagNamePattern.test(qName)){
41289                         throw new Error('invalid attribute:'+qName)
41290                 }
41291                 this[this.length++] = {qName:qName,value:value,offset:offset};
41292         },
41293         length:0,
41294         getLocalName:function(i){return this[i].localName},
41295         getLocator:function(i){return this[i].locator},
41296         getQName:function(i){return this[i].qName},
41297         getURI:function(i){return this[i].uri},
41298         getValue:function(i){return this[i].value}
41299 //      ,getIndex:function(uri, localName)){
41300 //              if(localName){
41301 //                      
41302 //              }else{
41303 //                      var qName = uri
41304 //              }
41305 //      },
41306 //      getValue:function(){return this.getValue(this.getIndex.apply(this,arguments))},
41307 //      getType:function(uri,localName){}
41308 //      getType:function(i){},
41309 };
41310
41311
41312
41313
41314 function _set_proto_(thiz,parent){
41315         thiz.__proto__ = parent;
41316         return thiz;
41317 }
41318 if(!(_set_proto_({},_set_proto_.prototype) instanceof _set_proto_)){
41319         _set_proto_ = function(thiz,parent){
41320                 function p(){}
41321                 p.prototype = parent;
41322                 p = new p();
41323                 for(parent in thiz){
41324                         p[parent] = thiz[parent];
41325                 }
41326                 return p;
41327         };
41328 }
41329
41330 function split(source,start){
41331         var match;
41332         var buf = [];
41333         var reg = /'[^']+'|"[^"]+"|[^\s<>\/=]+=?|(\/?\s*>|<)/g;
41334         reg.lastIndex = start;
41335         reg.exec(source);//skip <
41336         while(match = reg.exec(source)){
41337                 buf.push(match);
41338                 if(match[1])return buf;
41339         }
41340 }
41341
41342 var XMLReader_1 = XMLReader;
41343
41344 var sax = {
41345         XMLReader: XMLReader_1
41346 };
41347
41348 /*
41349  * DOM Level 2
41350  * Object DOMException
41351  * @see http://www.w3.org/TR/REC-DOM-Level-1/ecma-script-language-binding.html
41352  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/ecma-script-binding.html
41353  */
41354
41355 function copy$1(src,dest){
41356         for(var p in src){
41357                 dest[p] = src[p];
41358         }
41359 }
41360 /**
41361 ^\w+\.prototype\.([_\w]+)\s*=\s*((?:.*\{\s*?[\r\n][\s\S]*?^})|\S.*?(?=[;\r\n]));?
41362 ^\w+\.prototype\.([_\w]+)\s*=\s*(\S.*?(?=[;\r\n]));?
41363  */
41364 function _extends(Class,Super){
41365         var pt = Class.prototype;
41366         if(Object.create){
41367                 var ppt = Object.create(Super.prototype);
41368                 pt.__proto__ = ppt;
41369         }
41370         if(!(pt instanceof Super)){
41371                 function t(){}
41372                 t.prototype = Super.prototype;
41373                 t = new t();
41374                 copy$1(pt,t);
41375                 Class.prototype = pt = t;
41376         }
41377         if(pt.constructor != Class){
41378                 if(typeof Class != 'function'){
41379                         console.error("unknow Class:"+Class);
41380                 }
41381                 pt.constructor = Class;
41382         }
41383 }
41384 var htmlns = 'http://www.w3.org/1999/xhtml';
41385 // Node Types
41386 var NodeType = {};
41387 var ELEMENT_NODE                = NodeType.ELEMENT_NODE                = 1;
41388 var ATTRIBUTE_NODE              = NodeType.ATTRIBUTE_NODE              = 2;
41389 var TEXT_NODE                   = NodeType.TEXT_NODE                   = 3;
41390 var CDATA_SECTION_NODE          = NodeType.CDATA_SECTION_NODE          = 4;
41391 var ENTITY_REFERENCE_NODE       = NodeType.ENTITY_REFERENCE_NODE       = 5;
41392 var ENTITY_NODE                 = NodeType.ENTITY_NODE                 = 6;
41393 var PROCESSING_INSTRUCTION_NODE = NodeType.PROCESSING_INSTRUCTION_NODE = 7;
41394 var COMMENT_NODE                = NodeType.COMMENT_NODE                = 8;
41395 var DOCUMENT_NODE               = NodeType.DOCUMENT_NODE               = 9;
41396 var DOCUMENT_TYPE_NODE          = NodeType.DOCUMENT_TYPE_NODE          = 10;
41397 var DOCUMENT_FRAGMENT_NODE      = NodeType.DOCUMENT_FRAGMENT_NODE      = 11;
41398 var NOTATION_NODE               = NodeType.NOTATION_NODE               = 12;
41399
41400 // ExceptionCode
41401 var ExceptionCode = {};
41402 var ExceptionMessage = {};
41403 var INDEX_SIZE_ERR              = ExceptionCode.INDEX_SIZE_ERR              = ((ExceptionMessage[1]="Index size error"),1);
41404 var DOMSTRING_SIZE_ERR          = ExceptionCode.DOMSTRING_SIZE_ERR          = ((ExceptionMessage[2]="DOMString size error"),2);
41405 var HIERARCHY_REQUEST_ERR       = ExceptionCode.HIERARCHY_REQUEST_ERR       = ((ExceptionMessage[3]="Hierarchy request error"),3);
41406 var WRONG_DOCUMENT_ERR          = ExceptionCode.WRONG_DOCUMENT_ERR          = ((ExceptionMessage[4]="Wrong document"),4);
41407 var INVALID_CHARACTER_ERR       = ExceptionCode.INVALID_CHARACTER_ERR       = ((ExceptionMessage[5]="Invalid character"),5);
41408 var NO_DATA_ALLOWED_ERR         = ExceptionCode.NO_DATA_ALLOWED_ERR         = ((ExceptionMessage[6]="No data allowed"),6);
41409 var NO_MODIFICATION_ALLOWED_ERR = ExceptionCode.NO_MODIFICATION_ALLOWED_ERR = ((ExceptionMessage[7]="No modification allowed"),7);
41410 var NOT_FOUND_ERR               = ExceptionCode.NOT_FOUND_ERR               = ((ExceptionMessage[8]="Not found"),8);
41411 var NOT_SUPPORTED_ERR           = ExceptionCode.NOT_SUPPORTED_ERR           = ((ExceptionMessage[9]="Not supported"),9);
41412 var INUSE_ATTRIBUTE_ERR         = ExceptionCode.INUSE_ATTRIBUTE_ERR         = ((ExceptionMessage[10]="Attribute in use"),10);
41413 //level2
41414 var INVALID_STATE_ERR           = ExceptionCode.INVALID_STATE_ERR               = ((ExceptionMessage[11]="Invalid state"),11);
41415 var SYNTAX_ERR                  = ExceptionCode.SYNTAX_ERR                      = ((ExceptionMessage[12]="Syntax error"),12);
41416 var INVALID_MODIFICATION_ERR    = ExceptionCode.INVALID_MODIFICATION_ERR        = ((ExceptionMessage[13]="Invalid modification"),13);
41417 var NAMESPACE_ERR               = ExceptionCode.NAMESPACE_ERR                   = ((ExceptionMessage[14]="Invalid namespace"),14);
41418 var INVALID_ACCESS_ERR          = ExceptionCode.INVALID_ACCESS_ERR              = ((ExceptionMessage[15]="Invalid access"),15);
41419
41420
41421 function DOMException(code, message) {
41422         if(message instanceof Error){
41423                 var error = message;
41424         }else{
41425                 error = this;
41426                 Error.call(this, ExceptionMessage[code]);
41427                 this.message = ExceptionMessage[code];
41428                 if(Error.captureStackTrace) Error.captureStackTrace(this, DOMException);
41429         }
41430         error.code = code;
41431         if(message) this.message = this.message + ": " + message;
41432         return error;
41433 }
41434 DOMException.prototype = Error.prototype;
41435 copy$1(ExceptionCode,DOMException);
41436 /**
41437  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-536297177
41438  * 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.
41439  * The items in the NodeList are accessible via an integral index, starting from 0.
41440  */
41441 function NodeList() {
41442 }
41443 NodeList.prototype = {
41444         /**
41445          * The number of nodes in the list. The range of valid child node indices is 0 to length-1 inclusive.
41446          * @standard level1
41447          */
41448         length:0, 
41449         /**
41450          * 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.
41451          * @standard level1
41452          * @param index  unsigned long 
41453          *   Index into the collection.
41454          * @return Node
41455          *      The node at the indexth position in the NodeList, or null if that is not a valid index. 
41456          */
41457         item: function(index) {
41458                 return this[index] || null;
41459         },
41460         toString:function(isHTML,nodeFilter){
41461                 for(var buf = [], i = 0;i<this.length;i++){
41462                         serializeToString(this[i],buf,isHTML,nodeFilter);
41463                 }
41464                 return buf.join('');
41465         }
41466 };
41467 function LiveNodeList(node,refresh){
41468         this._node = node;
41469         this._refresh = refresh;
41470         _updateLiveList(this);
41471 }
41472 function _updateLiveList(list){
41473         var inc = list._node._inc || list._node.ownerDocument._inc;
41474         if(list._inc != inc){
41475                 var ls = list._refresh(list._node);
41476                 //console.log(ls.length)
41477                 __set__(list,'length',ls.length);
41478                 copy$1(ls,list);
41479                 list._inc = inc;
41480         }
41481 }
41482 LiveNodeList.prototype.item = function(i){
41483         _updateLiveList(this);
41484         return this[i];
41485 };
41486
41487 _extends(LiveNodeList,NodeList);
41488 /**
41489  * 
41490  * 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.
41491  * NamedNodeMap objects in the DOM are live.
41492  * used for attributes or DocumentType entities 
41493  */
41494 function NamedNodeMap() {
41495 }
41496
41497 function _findNodeIndex(list,node){
41498         var i = list.length;
41499         while(i--){
41500                 if(list[i] === node){return i}
41501         }
41502 }
41503
41504 function _addNamedNode(el,list,newAttr,oldAttr){
41505         if(oldAttr){
41506                 list[_findNodeIndex(list,oldAttr)] = newAttr;
41507         }else{
41508                 list[list.length++] = newAttr;
41509         }
41510         if(el){
41511                 newAttr.ownerElement = el;
41512                 var doc = el.ownerDocument;
41513                 if(doc){
41514                         oldAttr && _onRemoveAttribute(doc,el,oldAttr);
41515                         _onAddAttribute(doc,el,newAttr);
41516                 }
41517         }
41518 }
41519 function _removeNamedNode(el,list,attr){
41520         //console.log('remove attr:'+attr)
41521         var i = _findNodeIndex(list,attr);
41522         if(i>=0){
41523                 var lastIndex = list.length-1;
41524                 while(i<lastIndex){
41525                         list[i] = list[++i];
41526                 }
41527                 list.length = lastIndex;
41528                 if(el){
41529                         var doc = el.ownerDocument;
41530                         if(doc){
41531                                 _onRemoveAttribute(doc,el,attr);
41532                                 attr.ownerElement = null;
41533                         }
41534                 }
41535         }else{
41536                 throw DOMException(NOT_FOUND_ERR,new Error(el.tagName+'@'+attr))
41537         }
41538 }
41539 NamedNodeMap.prototype = {
41540         length:0,
41541         item:NodeList.prototype.item,
41542         getNamedItem: function(key) {
41543 //              if(key.indexOf(':')>0 || key == 'xmlns'){
41544 //                      return null;
41545 //              }
41546                 //console.log()
41547                 var i = this.length;
41548                 while(i--){
41549                         var attr = this[i];
41550                         //console.log(attr.nodeName,key)
41551                         if(attr.nodeName == key){
41552                                 return attr;
41553                         }
41554                 }
41555         },
41556         setNamedItem: function(attr) {
41557                 var el = attr.ownerElement;
41558                 if(el && el!=this._ownerElement){
41559                         throw new DOMException(INUSE_ATTRIBUTE_ERR);
41560                 }
41561                 var oldAttr = this.getNamedItem(attr.nodeName);
41562                 _addNamedNode(this._ownerElement,this,attr,oldAttr);
41563                 return oldAttr;
41564         },
41565         /* returns Node */
41566         setNamedItemNS: function(attr) {// raises: WRONG_DOCUMENT_ERR,NO_MODIFICATION_ALLOWED_ERR,INUSE_ATTRIBUTE_ERR
41567                 var el = attr.ownerElement, oldAttr;
41568                 if(el && el!=this._ownerElement){
41569                         throw new DOMException(INUSE_ATTRIBUTE_ERR);
41570                 }
41571                 oldAttr = this.getNamedItemNS(attr.namespaceURI,attr.localName);
41572                 _addNamedNode(this._ownerElement,this,attr,oldAttr);
41573                 return oldAttr;
41574         },
41575
41576         /* returns Node */
41577         removeNamedItem: function(key) {
41578                 var attr = this.getNamedItem(key);
41579                 _removeNamedNode(this._ownerElement,this,attr);
41580                 return attr;
41581                 
41582                 
41583         },// raises: NOT_FOUND_ERR,NO_MODIFICATION_ALLOWED_ERR
41584         
41585         //for level2
41586         removeNamedItemNS:function(namespaceURI,localName){
41587                 var attr = this.getNamedItemNS(namespaceURI,localName);
41588                 _removeNamedNode(this._ownerElement,this,attr);
41589                 return attr;
41590         },
41591         getNamedItemNS: function(namespaceURI, localName) {
41592                 var i = this.length;
41593                 while(i--){
41594                         var node = this[i];
41595                         if(node.localName == localName && node.namespaceURI == namespaceURI){
41596                                 return node;
41597                         }
41598                 }
41599                 return null;
41600         }
41601 };
41602 /**
41603  * @see http://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-102161490
41604  */
41605 function DOMImplementation(/* Object */ features) {
41606         this._features = {};
41607         if (features) {
41608                 for (var feature in features) {
41609                          this._features = features[feature];
41610                 }
41611         }
41612 }
41613
41614 DOMImplementation.prototype = {
41615         hasFeature: function(/* string */ feature, /* string */ version) {
41616                 var versions = this._features[feature.toLowerCase()];
41617                 if (versions && (!version || version in versions)) {
41618                         return true;
41619                 } else {
41620                         return false;
41621                 }
41622         },
41623         // Introduced in DOM Level 2:
41624         createDocument:function(namespaceURI,  qualifiedName, doctype){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR,WRONG_DOCUMENT_ERR
41625                 var doc = new Document();
41626                 doc.implementation = this;
41627                 doc.childNodes = new NodeList();
41628                 doc.doctype = doctype;
41629                 if(doctype){
41630                         doc.appendChild(doctype);
41631                 }
41632                 if(qualifiedName){
41633                         var root = doc.createElementNS(namespaceURI,qualifiedName);
41634                         doc.appendChild(root);
41635                 }
41636                 return doc;
41637         },
41638         // Introduced in DOM Level 2:
41639         createDocumentType:function(qualifiedName, publicId, systemId){// raises:INVALID_CHARACTER_ERR,NAMESPACE_ERR
41640                 var node = new DocumentType();
41641                 node.name = qualifiedName;
41642                 node.nodeName = qualifiedName;
41643                 node.publicId = publicId;
41644                 node.systemId = systemId;
41645                 // Introduced in DOM Level 2:
41646                 //readonly attribute DOMString        internalSubset;
41647                 
41648                 //TODO:..
41649                 //  readonly attribute NamedNodeMap     entities;
41650                 //  readonly attribute NamedNodeMap     notations;
41651                 return node;
41652         }
41653 };
41654
41655
41656 /**
41657  * @see http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html#ID-1950641247
41658  */
41659
41660 function Node$3() {
41661 }
41662
41663 Node$3.prototype = {
41664         firstChild : null,
41665         lastChild : null,
41666         previousSibling : null,
41667         nextSibling : null,
41668         attributes : null,
41669         parentNode : null,
41670         childNodes : null,
41671         ownerDocument : null,
41672         nodeValue : null,
41673         namespaceURI : null,
41674         prefix : null,
41675         localName : null,
41676         // Modified in DOM Level 2:
41677         insertBefore:function(newChild, refChild){//raises 
41678                 return _insertBefore(this,newChild,refChild);
41679         },
41680         replaceChild:function(newChild, oldChild){//raises 
41681                 this.insertBefore(newChild,oldChild);
41682                 if(oldChild){
41683                         this.removeChild(oldChild);
41684                 }
41685         },
41686         removeChild:function(oldChild){
41687                 return _removeChild(this,oldChild);
41688         },
41689         appendChild:function(newChild){
41690                 return this.insertBefore(newChild,null);
41691         },
41692         hasChildNodes:function(){
41693                 return this.firstChild != null;
41694         },
41695         cloneNode:function(deep){
41696                 return cloneNode(this.ownerDocument||this,this,deep);
41697         },
41698         // Modified in DOM Level 2:
41699         normalize:function(){
41700                 var child = this.firstChild;
41701                 while(child){
41702                         var next = child.nextSibling;
41703                         if(next && next.nodeType == TEXT_NODE && child.nodeType == TEXT_NODE){
41704                                 this.removeChild(next);
41705                                 child.appendData(next.data);
41706                         }else{
41707                                 child.normalize();
41708                                 child = next;
41709                         }
41710                 }
41711         },
41712         // Introduced in DOM Level 2:
41713         isSupported:function(feature, version){
41714                 return this.ownerDocument.implementation.hasFeature(feature,version);
41715         },
41716     // Introduced in DOM Level 2:
41717     hasAttributes:function(){
41718         return this.attributes.length>0;
41719     },
41720     lookupPrefix:function(namespaceURI){
41721         var el = this;
41722         while(el){
41723                 var map = el._nsMap;
41724                 //console.dir(map)
41725                 if(map){
41726                         for(var n in map){
41727                                 if(map[n] == namespaceURI){
41728                                         return n;
41729                                 }
41730                         }
41731                 }
41732                 el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;
41733         }
41734         return null;
41735     },
41736     // Introduced in DOM Level 3:
41737     lookupNamespaceURI:function(prefix){
41738         var el = this;
41739         while(el){
41740                 var map = el._nsMap;
41741                 //console.dir(map)
41742                 if(map){
41743                         if(prefix in map){
41744                                 return map[prefix] ;
41745                         }
41746                 }
41747                 el = el.nodeType == ATTRIBUTE_NODE?el.ownerDocument : el.parentNode;
41748         }
41749         return null;
41750     },
41751     // Introduced in DOM Level 3:
41752     isDefaultNamespace:function(namespaceURI){
41753         var prefix = this.lookupPrefix(namespaceURI);
41754         return prefix == null;
41755     }
41756 };
41757
41758
41759 function _xmlEncoder(c){
41760         return c == '<' && '&lt;' ||
41761          c == '>' && '&gt;' ||
41762          c == '&' && '&amp;' ||
41763          c == '"' && '&quot;' ||
41764          '&#'+c.charCodeAt()+';'
41765 }
41766
41767
41768 copy$1(NodeType,Node$3);
41769 copy$1(NodeType,Node$3.prototype);
41770
41771 /**
41772  * @param callback return true for continue,false for break
41773  * @return boolean true: break visit;
41774  */
41775 function _visitNode(node,callback){
41776         if(callback(node)){
41777                 return true;
41778         }
41779         if(node = node.firstChild){
41780                 do{
41781                         if(_visitNode(node,callback)){return true}
41782         }while(node=node.nextSibling)
41783     }
41784 }
41785
41786
41787
41788 function Document(){
41789 }
41790 function _onAddAttribute(doc,el,newAttr){
41791         doc && doc._inc++;
41792         var ns = newAttr.namespaceURI;
41793         if(ns == 'http://www.w3.org/2000/xmlns/'){
41794                 //update namespace
41795                 el._nsMap[newAttr.prefix?newAttr.localName:''] = newAttr.value;
41796         }
41797 }
41798 function _onRemoveAttribute(doc,el,newAttr,remove){
41799         doc && doc._inc++;
41800         var ns = newAttr.namespaceURI;
41801         if(ns == 'http://www.w3.org/2000/xmlns/'){
41802                 //update namespace
41803                 delete el._nsMap[newAttr.prefix?newAttr.localName:''];
41804         }
41805 }
41806 function _onUpdateChild(doc,el,newChild){
41807         if(doc && doc._inc){
41808                 doc._inc++;
41809                 //update childNodes
41810                 var cs = el.childNodes;
41811                 if(newChild){
41812                         cs[cs.length++] = newChild;
41813                 }else{
41814                         //console.log(1)
41815                         var child = el.firstChild;
41816                         var i = 0;
41817                         while(child){
41818                                 cs[i++] = child;
41819                                 child =child.nextSibling;
41820                         }
41821                         cs.length = i;
41822                 }
41823         }
41824 }
41825
41826 /**
41827  * attributes;
41828  * children;
41829  * 
41830  * writeable properties:
41831  * nodeValue,Attr:value,CharacterData:data
41832  * prefix
41833  */
41834 function _removeChild(parentNode,child){
41835         var previous = child.previousSibling;
41836         var next = child.nextSibling;
41837         if(previous){
41838                 previous.nextSibling = next;
41839         }else{
41840                 parentNode.firstChild = next;
41841         }
41842         if(next){
41843                 next.previousSibling = previous;
41844         }else{
41845                 parentNode.lastChild = previous;
41846         }
41847         _onUpdateChild(parentNode.ownerDocument,parentNode);
41848         return child;
41849 }
41850 /**
41851  * preformance key(refChild == null)
41852  */
41853 function _insertBefore(parentNode,newChild,nextChild){
41854         var cp = newChild.parentNode;
41855         if(cp){
41856                 cp.removeChild(newChild);//remove and update
41857         }
41858         if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
41859                 var newFirst = newChild.firstChild;
41860                 if (newFirst == null) {
41861                         return newChild;
41862                 }
41863                 var newLast = newChild.lastChild;
41864         }else{
41865                 newFirst = newLast = newChild;
41866         }
41867         var pre = nextChild ? nextChild.previousSibling : parentNode.lastChild;
41868
41869         newFirst.previousSibling = pre;
41870         newLast.nextSibling = nextChild;
41871         
41872         
41873         if(pre){
41874                 pre.nextSibling = newFirst;
41875         }else{
41876                 parentNode.firstChild = newFirst;
41877         }
41878         if(nextChild == null){
41879                 parentNode.lastChild = newLast;
41880         }else{
41881                 nextChild.previousSibling = newLast;
41882         }
41883         do{
41884                 newFirst.parentNode = parentNode;
41885         }while(newFirst !== newLast && (newFirst= newFirst.nextSibling))
41886         _onUpdateChild(parentNode.ownerDocument||parentNode,parentNode);
41887         //console.log(parentNode.lastChild.nextSibling == null)
41888         if (newChild.nodeType == DOCUMENT_FRAGMENT_NODE) {
41889                 newChild.firstChild = newChild.lastChild = null;
41890         }
41891         return newChild;
41892 }
41893 function _appendSingleChild(parentNode,newChild){
41894         var cp = newChild.parentNode;
41895         if(cp){
41896                 var pre = parentNode.lastChild;
41897                 cp.removeChild(newChild);//remove and update
41898                 var pre = parentNode.lastChild;
41899         }
41900         var pre = parentNode.lastChild;
41901         newChild.parentNode = parentNode;
41902         newChild.previousSibling = pre;
41903         newChild.nextSibling = null;
41904         if(pre){
41905                 pre.nextSibling = newChild;
41906         }else{
41907                 parentNode.firstChild = newChild;
41908         }
41909         parentNode.lastChild = newChild;
41910         _onUpdateChild(parentNode.ownerDocument,parentNode,newChild);
41911         return newChild;
41912         //console.log("__aa",parentNode.lastChild.nextSibling == null)
41913 }
41914 Document.prototype = {
41915         //implementation : null,
41916         nodeName :  '#document',
41917         nodeType :  DOCUMENT_NODE,
41918         doctype :  null,
41919         documentElement :  null,
41920         _inc : 1,
41921         
41922         insertBefore :  function(newChild, refChild){//raises 
41923                 if(newChild.nodeType == DOCUMENT_FRAGMENT_NODE){
41924                         var child = newChild.firstChild;
41925                         while(child){
41926                                 var next = child.nextSibling;
41927                                 this.insertBefore(child,refChild);
41928                                 child = next;
41929                         }
41930                         return newChild;
41931                 }
41932                 if(this.documentElement == null && newChild.nodeType == ELEMENT_NODE){
41933                         this.documentElement = newChild;
41934                 }
41935                 
41936                 return _insertBefore(this,newChild,refChild),(newChild.ownerDocument = this),newChild;
41937         },
41938         removeChild :  function(oldChild){
41939                 if(this.documentElement == oldChild){
41940                         this.documentElement = null;
41941                 }
41942                 return _removeChild(this,oldChild);
41943         },
41944         // Introduced in DOM Level 2:
41945         importNode : function(importedNode,deep){
41946                 return importNode(this,importedNode,deep);
41947         },
41948         // Introduced in DOM Level 2:
41949         getElementById :        function(id){
41950                 var rtv = null;
41951                 _visitNode(this.documentElement,function(node){
41952                         if(node.nodeType == ELEMENT_NODE){
41953                                 if(node.getAttribute('id') == id){
41954                                         rtv = node;
41955                                         return true;
41956                                 }
41957                         }
41958                 });
41959                 return rtv;
41960         },
41961         
41962         //document factory method:
41963         createElement : function(tagName){
41964                 var node = new Element();
41965                 node.ownerDocument = this;
41966                 node.nodeName = tagName;
41967                 node.tagName = tagName;
41968                 node.childNodes = new NodeList();
41969                 var attrs       = node.attributes = new NamedNodeMap();
41970                 attrs._ownerElement = node;
41971                 return node;
41972         },
41973         createDocumentFragment :        function(){
41974                 var node = new DocumentFragment();
41975                 node.ownerDocument = this;
41976                 node.childNodes = new NodeList();
41977                 return node;
41978         },
41979         createTextNode :        function(data){
41980                 var node = new Text();
41981                 node.ownerDocument = this;
41982                 node.appendData(data);
41983                 return node;
41984         },
41985         createComment : function(data){
41986                 var node = new Comment();
41987                 node.ownerDocument = this;
41988                 node.appendData(data);
41989                 return node;
41990         },
41991         createCDATASection :    function(data){
41992                 var node = new CDATASection();
41993                 node.ownerDocument = this;
41994                 node.appendData(data);
41995                 return node;
41996         },
41997         createProcessingInstruction :   function(target,data){
41998                 var node = new ProcessingInstruction();
41999                 node.ownerDocument = this;
42000                 node.tagName = node.target = target;
42001                 node.nodeValue= node.data = data;
42002                 return node;
42003         },
42004         createAttribute :       function(name){
42005                 var node = new Attr();
42006                 node.ownerDocument      = this;
42007                 node.name = name;
42008                 node.nodeName   = name;
42009                 node.localName = name;
42010                 node.specified = true;
42011                 return node;
42012         },
42013         createEntityReference : function(name){
42014                 var node = new EntityReference();
42015                 node.ownerDocument      = this;
42016                 node.nodeName   = name;
42017                 return node;
42018         },
42019         // Introduced in DOM Level 2:
42020         createElementNS :       function(namespaceURI,qualifiedName){
42021                 var node = new Element();
42022                 var pl = qualifiedName.split(':');
42023                 var attrs       = node.attributes = new NamedNodeMap();
42024                 node.childNodes = new NodeList();
42025                 node.ownerDocument = this;
42026                 node.nodeName = qualifiedName;
42027                 node.tagName = qualifiedName;
42028                 node.namespaceURI = namespaceURI;
42029                 if(pl.length == 2){
42030                         node.prefix = pl[0];
42031                         node.localName = pl[1];
42032                 }else{
42033                         //el.prefix = null;
42034                         node.localName = qualifiedName;
42035                 }
42036                 attrs._ownerElement = node;
42037                 return node;
42038         },
42039         // Introduced in DOM Level 2:
42040         createAttributeNS :     function(namespaceURI,qualifiedName){
42041                 var node = new Attr();
42042                 var pl = qualifiedName.split(':');
42043                 node.ownerDocument = this;
42044                 node.nodeName = qualifiedName;
42045                 node.name = qualifiedName;
42046                 node.namespaceURI = namespaceURI;
42047                 node.specified = true;
42048                 if(pl.length == 2){
42049                         node.prefix = pl[0];
42050                         node.localName = pl[1];
42051                 }else{
42052                         //el.prefix = null;
42053                         node.localName = qualifiedName;
42054                 }
42055                 return node;
42056         }
42057 };
42058 _extends(Document,Node$3);
42059
42060
42061 function Element() {
42062         this._nsMap = {};
42063 }
42064 Element.prototype = {
42065         nodeType : ELEMENT_NODE,
42066         hasAttribute : function(name){
42067                 return this.getAttributeNode(name)!=null;
42068         },
42069         getAttribute : function(name){
42070                 var attr = this.getAttributeNode(name);
42071                 return attr && attr.value || '';
42072         },
42073         getAttributeNode : function(name){
42074                 return this.attributes.getNamedItem(name);
42075         },
42076         setAttribute : function(name, value){
42077                 var attr = this.ownerDocument.createAttribute(name);
42078                 attr.value = attr.nodeValue = "" + value;
42079                 this.setAttributeNode(attr);
42080         },
42081         removeAttribute : function(name){
42082                 var attr = this.getAttributeNode(name);
42083                 attr && this.removeAttributeNode(attr);
42084         },
42085         
42086         //four real opeartion method
42087         appendChild:function(newChild){
42088                 if(newChild.nodeType === DOCUMENT_FRAGMENT_NODE){
42089                         return this.insertBefore(newChild,null);
42090                 }else{
42091                         return _appendSingleChild(this,newChild);
42092                 }
42093         },
42094         setAttributeNode : function(newAttr){
42095                 return this.attributes.setNamedItem(newAttr);
42096         },
42097         setAttributeNodeNS : function(newAttr){
42098                 return this.attributes.setNamedItemNS(newAttr);
42099         },
42100         removeAttributeNode : function(oldAttr){
42101                 //console.log(this == oldAttr.ownerElement)
42102                 return this.attributes.removeNamedItem(oldAttr.nodeName);
42103         },
42104         //get real attribute name,and remove it by removeAttributeNode
42105         removeAttributeNS : function(namespaceURI, localName){
42106                 var old = this.getAttributeNodeNS(namespaceURI, localName);
42107                 old && this.removeAttributeNode(old);
42108         },
42109         
42110         hasAttributeNS : function(namespaceURI, localName){
42111                 return this.getAttributeNodeNS(namespaceURI, localName)!=null;
42112         },
42113         getAttributeNS : function(namespaceURI, localName){
42114                 var attr = this.getAttributeNodeNS(namespaceURI, localName);
42115                 return attr && attr.value || '';
42116         },
42117         setAttributeNS : function(namespaceURI, qualifiedName, value){
42118                 var attr = this.ownerDocument.createAttributeNS(namespaceURI, qualifiedName);
42119                 attr.value = attr.nodeValue = "" + value;
42120                 this.setAttributeNode(attr);
42121         },
42122         getAttributeNodeNS : function(namespaceURI, localName){
42123                 return this.attributes.getNamedItemNS(namespaceURI, localName);
42124         },
42125         
42126         getElementsByTagName : function(tagName){
42127                 return new LiveNodeList(this,function(base){
42128                         var ls = [];
42129                         _visitNode(base,function(node){
42130                                 if(node !== base && node.nodeType == ELEMENT_NODE && (tagName === '*' || node.tagName == tagName)){
42131                                         ls.push(node);
42132                                 }
42133                         });
42134                         return ls;
42135                 });
42136         },
42137         getElementsByTagNameNS : function(namespaceURI, localName){
42138                 return new LiveNodeList(this,function(base){
42139                         var ls = [];
42140                         _visitNode(base,function(node){
42141                                 if(node !== base && node.nodeType === ELEMENT_NODE && (namespaceURI === '*' || node.namespaceURI === namespaceURI) && (localName === '*' || node.localName == localName)){
42142                                         ls.push(node);
42143                                 }
42144                         });
42145                         return ls;
42146                         
42147                 });
42148         }
42149 };
42150 Document.prototype.getElementsByTagName = Element.prototype.getElementsByTagName;
42151 Document.prototype.getElementsByTagNameNS = Element.prototype.getElementsByTagNameNS;
42152
42153
42154 _extends(Element,Node$3);
42155 function Attr() {
42156 }
42157 Attr.prototype.nodeType = ATTRIBUTE_NODE;
42158 _extends(Attr,Node$3);
42159
42160
42161 function CharacterData() {
42162 }
42163 CharacterData.prototype = {
42164         data : '',
42165         substringData : function(offset, count) {
42166                 return this.data.substring(offset, offset+count);
42167         },
42168         appendData: function(text) {
42169                 text = this.data+text;
42170                 this.nodeValue = this.data = text;
42171                 this.length = text.length;
42172         },
42173         insertData: function(offset,text) {
42174                 this.replaceData(offset,0,text);
42175         
42176         },
42177         appendChild:function(newChild){
42178                 throw new Error(ExceptionMessage[HIERARCHY_REQUEST_ERR])
42179         },
42180         deleteData: function(offset, count) {
42181                 this.replaceData(offset,count,"");
42182         },
42183         replaceData: function(offset, count, text) {
42184                 var start = this.data.substring(0,offset);
42185                 var end = this.data.substring(offset+count);
42186                 text = start + text + end;
42187                 this.nodeValue = this.data = text;
42188                 this.length = text.length;
42189         }
42190 };
42191 _extends(CharacterData,Node$3);
42192 function Text() {
42193 }
42194 Text.prototype = {
42195         nodeName : "#text",
42196         nodeType : TEXT_NODE,
42197         splitText : function(offset) {
42198                 var text = this.data;
42199                 var newText = text.substring(offset);
42200                 text = text.substring(0, offset);
42201                 this.data = this.nodeValue = text;
42202                 this.length = text.length;
42203                 var newNode = this.ownerDocument.createTextNode(newText);
42204                 if(this.parentNode){
42205                         this.parentNode.insertBefore(newNode, this.nextSibling);
42206                 }
42207                 return newNode;
42208         }
42209 };
42210 _extends(Text,CharacterData);
42211 function Comment() {
42212 }
42213 Comment.prototype = {
42214         nodeName : "#comment",
42215         nodeType : COMMENT_NODE
42216 };
42217 _extends(Comment,CharacterData);
42218
42219 function CDATASection() {
42220 }
42221 CDATASection.prototype = {
42222         nodeName : "#cdata-section",
42223         nodeType : CDATA_SECTION_NODE
42224 };
42225 _extends(CDATASection,CharacterData);
42226
42227
42228 function DocumentType() {
42229 }
42230 DocumentType.prototype.nodeType = DOCUMENT_TYPE_NODE;
42231 _extends(DocumentType,Node$3);
42232
42233 function Notation() {
42234 }
42235 Notation.prototype.nodeType = NOTATION_NODE;
42236 _extends(Notation,Node$3);
42237
42238 function Entity() {
42239 }
42240 Entity.prototype.nodeType = ENTITY_NODE;
42241 _extends(Entity,Node$3);
42242
42243 function EntityReference() {
42244 }
42245 EntityReference.prototype.nodeType = ENTITY_REFERENCE_NODE;
42246 _extends(EntityReference,Node$3);
42247
42248 function DocumentFragment() {
42249 }
42250 DocumentFragment.prototype.nodeName =   "#document-fragment";
42251 DocumentFragment.prototype.nodeType =   DOCUMENT_FRAGMENT_NODE;
42252 _extends(DocumentFragment,Node$3);
42253
42254
42255 function ProcessingInstruction() {
42256 }
42257 ProcessingInstruction.prototype.nodeType = PROCESSING_INSTRUCTION_NODE;
42258 _extends(ProcessingInstruction,Node$3);
42259 function XMLSerializer$1(){}
42260 XMLSerializer$1.prototype.serializeToString = function(node,isHtml,nodeFilter){
42261         return nodeSerializeToString.call(node,isHtml,nodeFilter);
42262 };
42263 Node$3.prototype.toString = nodeSerializeToString;
42264 function nodeSerializeToString(isHtml,nodeFilter){
42265         var buf = [];
42266         var refNode = this.nodeType == 9?this.documentElement:this;
42267         var prefix = refNode.prefix;
42268         var uri = refNode.namespaceURI;
42269         
42270         if(uri && prefix == null){
42271                 //console.log(prefix)
42272                 var prefix = refNode.lookupPrefix(uri);
42273                 if(prefix == null){
42274                         //isHTML = true;
42275                         var visibleNamespaces=[
42276                         {namespace:uri,prefix:null}
42277                         //{namespace:uri,prefix:''}
42278                         ];
42279                 }
42280         }
42281         serializeToString(this,buf,isHtml,nodeFilter,visibleNamespaces);
42282         //console.log('###',this.nodeType,uri,prefix,buf.join(''))
42283         return buf.join('');
42284 }
42285 function needNamespaceDefine(node,isHTML, visibleNamespaces) {
42286         var prefix = node.prefix||'';
42287         var uri = node.namespaceURI;
42288         if (!prefix && !uri){
42289                 return false;
42290         }
42291         if (prefix === "xml" && uri === "http://www.w3.org/XML/1998/namespace" 
42292                 || uri == 'http://www.w3.org/2000/xmlns/'){
42293                 return false;
42294         }
42295         
42296         var i = visibleNamespaces.length; 
42297         //console.log('@@@@',node.tagName,prefix,uri,visibleNamespaces)
42298         while (i--) {
42299                 var ns = visibleNamespaces[i];
42300                 // get namespace prefix
42301                 //console.log(node.nodeType,node.tagName,ns.prefix,prefix)
42302                 if (ns.prefix == prefix){
42303                         return ns.namespace != uri;
42304                 }
42305         }
42306         //console.log(isHTML,uri,prefix=='')
42307         //if(isHTML && prefix ==null && uri == 'http://www.w3.org/1999/xhtml'){
42308         //      return false;
42309         //}
42310         //node.flag = '11111'
42311         //console.error(3,true,node.flag,node.prefix,node.namespaceURI)
42312         return true;
42313 }
42314 function serializeToString(node,buf,isHTML,nodeFilter,visibleNamespaces){
42315         if(nodeFilter){
42316                 node = nodeFilter(node);
42317                 if(node){
42318                         if(typeof node == 'string'){
42319                                 buf.push(node);
42320                                 return;
42321                         }
42322                 }else{
42323                         return;
42324                 }
42325                 //buf.sort.apply(attrs, attributeSorter);
42326         }
42327         switch(node.nodeType){
42328         case ELEMENT_NODE:
42329                 if (!visibleNamespaces) visibleNamespaces = [];
42330                 var startVisibleNamespaces = visibleNamespaces.length;
42331                 var attrs = node.attributes;
42332                 var len = attrs.length;
42333                 var child = node.firstChild;
42334                 var nodeName = node.tagName;
42335                 
42336                 isHTML =  (htmlns === node.namespaceURI) ||isHTML; 
42337                 buf.push('<',nodeName);
42338                 
42339                 
42340                 
42341                 for(var i=0;i<len;i++){
42342                         // add namespaces for attributes
42343                         var attr = attrs.item(i);
42344                         if (attr.prefix == 'xmlns') {
42345                                 visibleNamespaces.push({ prefix: attr.localName, namespace: attr.value });
42346                         }else if(attr.nodeName == 'xmlns'){
42347                                 visibleNamespaces.push({ prefix: '', namespace: attr.value });
42348                         }
42349                 }
42350                 for(var i=0;i<len;i++){
42351                         var attr = attrs.item(i);
42352                         if (needNamespaceDefine(attr,isHTML, visibleNamespaces)) {
42353                                 var prefix = attr.prefix||'';
42354                                 var uri = attr.namespaceURI;
42355                                 var ns = prefix ? ' xmlns:' + prefix : " xmlns";
42356                                 buf.push(ns, '="' , uri , '"');
42357                                 visibleNamespaces.push({ prefix: prefix, namespace:uri });
42358                         }
42359                         serializeToString(attr,buf,isHTML,nodeFilter,visibleNamespaces);
42360                 }
42361                 // add namespace for current node               
42362                 if (needNamespaceDefine(node,isHTML, visibleNamespaces)) {
42363                         var prefix = node.prefix||'';
42364                         var uri = node.namespaceURI;
42365                         var ns = prefix ? ' xmlns:' + prefix : " xmlns";
42366                         buf.push(ns, '="' , uri , '"');
42367                         visibleNamespaces.push({ prefix: prefix, namespace:uri });
42368                 }
42369                 
42370                 if(child || isHTML && !/^(?:meta|link|img|br|hr|input)$/i.test(nodeName)){
42371                         buf.push('>');
42372                         //if is cdata child node
42373                         if(isHTML && /^script$/i.test(nodeName)){
42374                                 while(child){
42375                                         if(child.data){
42376                                                 buf.push(child.data);
42377                                         }else{
42378                                                 serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces);
42379                                         }
42380                                         child = child.nextSibling;
42381                                 }
42382                         }else
42383                         {
42384                                 while(child){
42385                                         serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces);
42386                                         child = child.nextSibling;
42387                                 }
42388                         }
42389                         buf.push('</',nodeName,'>');
42390                 }else{
42391                         buf.push('/>');
42392                 }
42393                 // remove added visible namespaces
42394                 //visibleNamespaces.length = startVisibleNamespaces;
42395                 return;
42396         case DOCUMENT_NODE:
42397         case DOCUMENT_FRAGMENT_NODE:
42398                 var child = node.firstChild;
42399                 while(child){
42400                         serializeToString(child,buf,isHTML,nodeFilter,visibleNamespaces);
42401                         child = child.nextSibling;
42402                 }
42403                 return;
42404         case ATTRIBUTE_NODE:
42405                 return buf.push(' ',node.name,'="',node.value.replace(/[<&"]/g,_xmlEncoder),'"');
42406         case TEXT_NODE:
42407                 return buf.push(node.data.replace(/[<&]/g,_xmlEncoder));
42408         case CDATA_SECTION_NODE:
42409                 return buf.push( '<![CDATA[',node.data,']]>');
42410         case COMMENT_NODE:
42411                 return buf.push( "<!--",node.data,"-->");
42412         case DOCUMENT_TYPE_NODE:
42413                 var pubid = node.publicId;
42414                 var sysid = node.systemId;
42415                 buf.push('<!DOCTYPE ',node.name);
42416                 if(pubid){
42417                         buf.push(' PUBLIC "',pubid);
42418                         if (sysid && sysid!='.') {
42419                                 buf.push( '" "',sysid);
42420                         }
42421                         buf.push('">');
42422                 }else if(sysid && sysid!='.'){
42423                         buf.push(' SYSTEM "',sysid,'">');
42424                 }else{
42425                         var sub = node.internalSubset;
42426                         if(sub){
42427                                 buf.push(" [",sub,"]");
42428                         }
42429                         buf.push(">");
42430                 }
42431                 return;
42432         case PROCESSING_INSTRUCTION_NODE:
42433                 return buf.push( "<?",node.target," ",node.data,"?>");
42434         case ENTITY_REFERENCE_NODE:
42435                 return buf.push( '&',node.nodeName,';');
42436         //case ENTITY_NODE:
42437         //case NOTATION_NODE:
42438         default:
42439                 buf.push('??',node.nodeName);
42440         }
42441 }
42442 function importNode(doc,node,deep){
42443         var node2;
42444         switch (node.nodeType) {
42445         case ELEMENT_NODE:
42446                 node2 = node.cloneNode(false);
42447                 node2.ownerDocument = doc;
42448                 //var attrs = node2.attributes;
42449                 //var len = attrs.length;
42450                 //for(var i=0;i<len;i++){
42451                         //node2.setAttributeNodeNS(importNode(doc,attrs.item(i),deep));
42452                 //}
42453         case DOCUMENT_FRAGMENT_NODE:
42454                 break;
42455         case ATTRIBUTE_NODE:
42456                 deep = true;
42457                 break;
42458         //case ENTITY_REFERENCE_NODE:
42459         //case PROCESSING_INSTRUCTION_NODE:
42460         ////case TEXT_NODE:
42461         //case CDATA_SECTION_NODE:
42462         //case COMMENT_NODE:
42463         //      deep = false;
42464         //      break;
42465         //case DOCUMENT_NODE:
42466         //case DOCUMENT_TYPE_NODE:
42467         //cannot be imported.
42468         //case ENTITY_NODE:
42469         //case NOTATION_NODE:
42470         //can not hit in level3
42471         //default:throw e;
42472         }
42473         if(!node2){
42474                 node2 = node.cloneNode(false);//false
42475         }
42476         node2.ownerDocument = doc;
42477         node2.parentNode = null;
42478         if(deep){
42479                 var child = node.firstChild;
42480                 while(child){
42481                         node2.appendChild(importNode(doc,child,deep));
42482                         child = child.nextSibling;
42483                 }
42484         }
42485         return node2;
42486 }
42487 //
42488 //var _relationMap = {firstChild:1,lastChild:1,previousSibling:1,nextSibling:1,
42489 //                                      attributes:1,childNodes:1,parentNode:1,documentElement:1,doctype,};
42490 function cloneNode(doc,node,deep){
42491         var node2 = new node.constructor();
42492         for(var n in node){
42493                 var v = node[n];
42494                 if(typeof v != 'object' ){
42495                         if(v != node2[n]){
42496                                 node2[n] = v;
42497                         }
42498                 }
42499         }
42500         if(node.childNodes){
42501                 node2.childNodes = new NodeList();
42502         }
42503         node2.ownerDocument = doc;
42504         switch (node2.nodeType) {
42505         case ELEMENT_NODE:
42506                 var attrs       = node.attributes;
42507                 var attrs2      = node2.attributes = new NamedNodeMap();
42508                 var len = attrs.length;
42509                 attrs2._ownerElement = node2;
42510                 for(var i=0;i<len;i++){
42511                         node2.setAttributeNode(cloneNode(doc,attrs.item(i),true));
42512                 }
42513                 break;;
42514         case ATTRIBUTE_NODE:
42515                 deep = true;
42516         }
42517         if(deep){
42518                 var child = node.firstChild;
42519                 while(child){
42520                         node2.appendChild(cloneNode(doc,child,deep));
42521                         child = child.nextSibling;
42522                 }
42523         }
42524         return node2;
42525 }
42526
42527 function __set__(object,key,value){
42528         object[key] = value;
42529 }
42530 //do dynamic
42531 try{
42532         if(Object.defineProperty){
42533                 Object.defineProperty(LiveNodeList.prototype,'length',{
42534                         get:function(){
42535                                 _updateLiveList(this);
42536                                 return this.$$length;
42537                         }
42538                 });
42539                 Object.defineProperty(Node$3.prototype,'textContent',{
42540                         get:function(){
42541                                 return getTextContent(this);
42542                         },
42543                         set:function(data){
42544                                 switch(this.nodeType){
42545                                 case ELEMENT_NODE:
42546                                 case DOCUMENT_FRAGMENT_NODE:
42547                                         while(this.firstChild){
42548                                                 this.removeChild(this.firstChild);
42549                                         }
42550                                         if(data || String(data)){
42551                                                 this.appendChild(this.ownerDocument.createTextNode(data));
42552                                         }
42553                                         break;
42554                                 default:
42555                                         //TODO:
42556                                         this.data = data;
42557                                         this.value = data;
42558                                         this.nodeValue = data;
42559                                 }
42560                         }
42561                 });
42562                 
42563                 function getTextContent(node){
42564                         switch(node.nodeType){
42565                         case ELEMENT_NODE:
42566                         case DOCUMENT_FRAGMENT_NODE:
42567                                 var buf = [];
42568                                 node = node.firstChild;
42569                                 while(node){
42570                                         if(node.nodeType!==7 && node.nodeType !==8){
42571                                                 buf.push(getTextContent(node));
42572                                         }
42573                                         node = node.nextSibling;
42574                                 }
42575                                 return buf.join('');
42576                         default:
42577                                 return node.nodeValue;
42578                         }
42579                 }
42580                 __set__ = function(object,key,value){
42581                         //console.log(value)
42582                         object['$$'+key] = value;
42583                 };
42584         }
42585 }catch(e){//ie8
42586 }
42587
42588 //if(typeof require == 'function'){
42589         var DOMImplementation_1 = DOMImplementation;
42590         var XMLSerializer_1 = XMLSerializer$1;
42591 //}
42592
42593 var dom = {
42594         DOMImplementation: DOMImplementation_1,
42595         XMLSerializer: XMLSerializer_1
42596 };
42597
42598 var domParser = createCommonjsModule(function (module, exports) {
42599 function DOMParser(options){
42600         this.options = options ||{locator:{}};
42601         
42602 }
42603 DOMParser.prototype.parseFromString = function(source,mimeType){
42604         var options = this.options;
42605         var sax$$1 =  new XMLReader();
42606         var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler
42607         var errorHandler = options.errorHandler;
42608         var locator = options.locator;
42609         var defaultNSMap = options.xmlns||{};
42610         var entityMap = {'lt':'<','gt':'>','amp':'&','quot':'"','apos':"'"};
42611         if(locator){
42612                 domBuilder.setDocumentLocator(locator);
42613         }
42614         
42615         sax$$1.errorHandler = buildErrorHandler(errorHandler,domBuilder,locator);
42616         sax$$1.domBuilder = options.domBuilder || domBuilder;
42617         if(/\/x?html?$/.test(mimeType)){
42618                 entityMap.nbsp = '\xa0';
42619                 entityMap.copy = '\xa9';
42620                 defaultNSMap['']= 'http://www.w3.org/1999/xhtml';
42621         }
42622         defaultNSMap.xml = defaultNSMap.xml || 'http://www.w3.org/XML/1998/namespace';
42623         if(source){
42624                 sax$$1.parse(source,defaultNSMap,entityMap);
42625         }else{
42626                 sax$$1.errorHandler.error("invalid doc source");
42627         }
42628         return domBuilder.doc;
42629 };
42630 function buildErrorHandler(errorImpl,domBuilder,locator){
42631         if(!errorImpl){
42632                 if(domBuilder instanceof DOMHandler){
42633                         return domBuilder;
42634                 }
42635                 errorImpl = domBuilder ;
42636         }
42637         var errorHandler = {};
42638         var isCallback = errorImpl instanceof Function;
42639         locator = locator||{};
42640         function build(key){
42641                 var fn = errorImpl[key];
42642                 if(!fn && isCallback){
42643                         fn = errorImpl.length == 2?function(msg){errorImpl(key,msg);}:errorImpl;
42644                 }
42645                 errorHandler[key] = fn && function(msg){
42646                         fn('[xmldom '+key+']\t'+msg+_locator(locator));
42647                 }||function(){};
42648         }
42649         build('warning');
42650         build('error');
42651         build('fatalError');
42652         return errorHandler;
42653 }
42654
42655 //console.log('#\n\n\n\n\n\n\n####')
42656 /**
42657  * +ContentHandler+ErrorHandler
42658  * +LexicalHandler+EntityResolver2
42659  * -DeclHandler-DTDHandler 
42660  * 
42661  * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
42662  * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
42663  * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
42664  */
42665 function DOMHandler() {
42666     this.cdata = false;
42667 }
42668 function position(locator,node){
42669         node.lineNumber = locator.lineNumber;
42670         node.columnNumber = locator.columnNumber;
42671 }
42672 /**
42673  * @see org.xml.sax.ContentHandler#startDocument
42674  * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
42675  */ 
42676 DOMHandler.prototype = {
42677         startDocument : function() {
42678         this.doc = new DOMImplementation().createDocument(null, null, null);
42679         if (this.locator) {
42680                 this.doc.documentURI = this.locator.systemId;
42681         }
42682         },
42683         startElement:function(namespaceURI, localName, qName, attrs) {
42684                 var doc = this.doc;
42685             var el = doc.createElementNS(namespaceURI, qName||localName);
42686             var len = attrs.length;
42687             appendElement(this, el);
42688             this.currentElement = el;
42689             
42690                 this.locator && position(this.locator,el);
42691             for (var i = 0 ; i < len; i++) {
42692                 var namespaceURI = attrs.getURI(i);
42693                 var value = attrs.getValue(i);
42694                 var qName = attrs.getQName(i);
42695                         var attr = doc.createAttributeNS(namespaceURI, qName);
42696                         this.locator &&position(attrs.getLocator(i),attr);
42697                         attr.value = attr.nodeValue = value;
42698                         el.setAttributeNode(attr);
42699             }
42700         },
42701         endElement:function(namespaceURI, localName, qName) {
42702                 var current = this.currentElement;
42703                 var tagName = current.tagName;
42704                 this.currentElement = current.parentNode;
42705         },
42706         startPrefixMapping:function(prefix, uri) {
42707         },
42708         endPrefixMapping:function(prefix) {
42709         },
42710         processingInstruction:function(target, data) {
42711             var ins = this.doc.createProcessingInstruction(target, data);
42712             this.locator && position(this.locator,ins);
42713             appendElement(this, ins);
42714         },
42715         ignorableWhitespace:function(ch, start, length) {
42716         },
42717         characters:function(chars, start, length) {
42718                 chars = _toString.apply(this,arguments);
42719                 //console.log(chars)
42720                 if(chars){
42721                         if (this.cdata) {
42722                                 var charNode = this.doc.createCDATASection(chars);
42723                         } else {
42724                                 var charNode = this.doc.createTextNode(chars);
42725                         }
42726                         if(this.currentElement){
42727                                 this.currentElement.appendChild(charNode);
42728                         }else if(/^\s*$/.test(chars)){
42729                                 this.doc.appendChild(charNode);
42730                                 //process xml
42731                         }
42732                         this.locator && position(this.locator,charNode);
42733                 }
42734         },
42735         skippedEntity:function(name) {
42736         },
42737         endDocument:function() {
42738                 this.doc.normalize();
42739         },
42740         setDocumentLocator:function (locator) {
42741             if(this.locator = locator){// && !('lineNumber' in locator)){
42742                 locator.lineNumber = 0;
42743             }
42744         },
42745         //LexicalHandler
42746         comment:function(chars, start, length) {
42747                 chars = _toString.apply(this,arguments);
42748             var comm = this.doc.createComment(chars);
42749             this.locator && position(this.locator,comm);
42750             appendElement(this, comm);
42751         },
42752         
42753         startCDATA:function() {
42754             //used in characters() methods
42755             this.cdata = true;
42756         },
42757         endCDATA:function() {
42758             this.cdata = false;
42759         },
42760         
42761         startDTD:function(name, publicId, systemId) {
42762                 var impl = this.doc.implementation;
42763             if (impl && impl.createDocumentType) {
42764                 var dt = impl.createDocumentType(name, publicId, systemId);
42765                 this.locator && position(this.locator,dt);
42766                 appendElement(this, dt);
42767             }
42768         },
42769         /**
42770          * @see org.xml.sax.ErrorHandler
42771          * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
42772          */
42773         warning:function(error) {
42774                 console.warn('[xmldom warning]\t'+error,_locator(this.locator));
42775         },
42776         error:function(error) {
42777                 console.error('[xmldom error]\t'+error,_locator(this.locator));
42778         },
42779         fatalError:function(error) {
42780                 console.error('[xmldom fatalError]\t'+error,_locator(this.locator));
42781             throw error;
42782         }
42783 };
42784 function _locator(l){
42785         if(l){
42786                 return '\n@'+(l.systemId ||'')+'#[line:'+l.lineNumber+',col:'+l.columnNumber+']'
42787         }
42788 }
42789 function _toString(chars,start,length){
42790         if(typeof chars == 'string'){
42791                 return chars.substr(start,length)
42792         }else{//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
42793                 if(chars.length >= start+length || start){
42794                         return new java.lang.String(chars,start,length)+'';
42795                 }
42796                 return chars;
42797         }
42798 }
42799
42800 /*
42801  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
42802  * used method of org.xml.sax.ext.LexicalHandler:
42803  *  #comment(chars, start, length)
42804  *  #startCDATA()
42805  *  #endCDATA()
42806  *  #startDTD(name, publicId, systemId)
42807  *
42808  *
42809  * IGNORED method of org.xml.sax.ext.LexicalHandler:
42810  *  #endDTD()
42811  *  #startEntity(name)
42812  *  #endEntity(name)
42813  *
42814  *
42815  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
42816  * IGNORED method of org.xml.sax.ext.DeclHandler
42817  *      #attributeDecl(eName, aName, type, mode, value)
42818  *  #elementDecl(name, model)
42819  *  #externalEntityDecl(name, publicId, systemId)
42820  *  #internalEntityDecl(name, value)
42821  * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
42822  * IGNORED method of org.xml.sax.EntityResolver2
42823  *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
42824  *  #resolveEntity(publicId, systemId)
42825  *  #getExternalSubset(name, baseURI)
42826  * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
42827  * IGNORED method of org.xml.sax.DTDHandler
42828  *  #notationDecl(name, publicId, systemId) {};
42829  *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
42830  */
42831 "endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key){
42832         DOMHandler.prototype[key] = function(){return null};
42833 });
42834
42835 /* 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 */
42836 function appendElement (hander,node) {
42837     if (!hander.currentElement) {
42838         hander.doc.appendChild(node);
42839     } else {
42840         hander.currentElement.appendChild(node);
42841     }
42842 }//appendChild and setAttributeNS are preformance key
42843
42844 //if(typeof require == 'function'){
42845         var XMLReader = sax.XMLReader;
42846         var DOMImplementation = exports.DOMImplementation = dom.DOMImplementation;
42847         exports.XMLSerializer = dom.XMLSerializer ;
42848         exports.DOMParser = DOMParser;
42849 //}
42850 });
42851
42852 var togeojson = createCommonjsModule(function (module, exports) {
42853 var toGeoJSON = (function() {
42854     'use strict';
42855
42856     var removeSpace = /\s*/g,
42857         trimSpace = /^\s*|\s*$/g,
42858         splitSpace = /\s+/;
42859     // generate a short, numeric hash of a string
42860     function okhash(x) {
42861         if (!x || !x.length) return 0;
42862         for (var i = 0, h = 0; i < x.length; i++) {
42863             h = ((h << 5) - h) + x.charCodeAt(i) | 0;
42864         } return h;
42865     }
42866     // all Y children of X
42867     function get(x, y) { return x.getElementsByTagName(y); }
42868     function attr(x, y) { return x.getAttribute(y); }
42869     function attrf(x, y) { return parseFloat(attr(x, y)); }
42870     // one Y child of X, if any, otherwise null
42871     function get1(x, y) { var n = get(x, y); return n.length ? n[0] : null; }
42872     // https://developer.mozilla.org/en-US/docs/Web/API/Node.normalize
42873     function norm(el) { if (el.normalize) { el.normalize(); } return el; }
42874     // cast array x into numbers
42875     function numarray(x) {
42876         for (var j = 0, o = []; j < x.length; j++) { o[j] = parseFloat(x[j]); }
42877         return o;
42878     }
42879     // get the content of a text node, if any
42880     function nodeVal(x) {
42881         if (x) { norm(x); }
42882         return (x && x.textContent) || '';
42883     }
42884     // get the contents of multiple text nodes, if present
42885     function getMulti(x, ys) {
42886         var o = {}, n, k;
42887         for (k = 0; k < ys.length; k++) {
42888             n = get1(x, ys[k]);
42889             if (n) o[ys[k]] = nodeVal(n);
42890         }
42891         return o;
42892     }
42893     // add properties of Y to X, overwriting if present in both
42894     function extend(x, y) { for (var k in y) x[k] = y[k]; }
42895     // get one coordinate from a coordinate array, if any
42896     function coord1(v) { return numarray(v.replace(removeSpace, '').split(',')); }
42897     // get all coordinates from a coordinate array as [[],[]]
42898     function coord(v) {
42899         var coords = v.replace(trimSpace, '').split(splitSpace),
42900             o = [];
42901         for (var i = 0; i < coords.length; i++) {
42902             o.push(coord1(coords[i]));
42903         }
42904         return o;
42905     }
42906     function coordPair(x) {
42907         var ll = [attrf(x, 'lon'), attrf(x, 'lat')],
42908             ele = get1(x, 'ele'),
42909             // handle namespaced attribute in browser
42910             heartRate = get1(x, 'gpxtpx:hr') || get1(x, 'hr'),
42911             time = get1(x, 'time'),
42912             e;
42913         if (ele) {
42914             e = parseFloat(nodeVal(ele));
42915             if (!isNaN(e)) {
42916                 ll.push(e);
42917             }
42918         }
42919         return {
42920             coordinates: ll,
42921             time: time ? nodeVal(time) : null,
42922             heartRate: heartRate ? parseFloat(nodeVal(heartRate)) : null
42923         };
42924     }
42925
42926     // create a new feature collection parent object
42927     function fc() {
42928         return {
42929             type: 'FeatureCollection',
42930             features: []
42931         };
42932     }
42933
42934     var serializer;
42935     if (typeof XMLSerializer !== 'undefined') {
42936         /* istanbul ignore next */
42937         serializer = new XMLSerializer();
42938     // only require xmldom in a node environment
42939     } else if ('object' === 'object' && typeof process === 'object' && !process.browser) {
42940         serializer = new (domParser.XMLSerializer)();
42941     }
42942     function xml2str(str) {
42943         // IE9 will create a new XMLSerializer but it'll crash immediately.
42944         // This line is ignored because we don't run coverage tests in IE9
42945         /* istanbul ignore next */
42946         if (str.xml !== undefined) return str.xml;
42947         return serializer.serializeToString(str);
42948     }
42949
42950     var t = {
42951         kml: function(doc) {
42952
42953             var gj = fc(),
42954                 // styleindex keeps track of hashed styles in order to match features
42955                 styleIndex = {}, styleByHash = {},
42956                 // stylemapindex keeps track of style maps to expose in properties
42957                 styleMapIndex = {},
42958                 // atomic geospatial types supported by KML - MultiGeometry is
42959                 // handled separately
42960                 geotypes = ['Polygon', 'LineString', 'Point', 'Track', 'gx:Track'],
42961                 // all root placemarks in the file
42962                 placemarks = get(doc, 'Placemark'),
42963                 styles = get(doc, 'Style'),
42964                 styleMaps = get(doc, 'StyleMap');
42965
42966             for (var k = 0; k < styles.length; k++) {
42967                 var hash = okhash(xml2str(styles[k])).toString(16);
42968                 styleIndex['#' + attr(styles[k], 'id')] = hash;
42969                 styleByHash[hash] = styles[k];
42970             }
42971             for (var l = 0; l < styleMaps.length; l++) {
42972                 styleIndex['#' + attr(styleMaps[l], 'id')] = okhash(xml2str(styleMaps[l])).toString(16);
42973                 var pairs = get(styleMaps[l], 'Pair');
42974                 var pairsMap = {};
42975                 for (var m = 0; m < pairs.length; m++) {
42976                     pairsMap[nodeVal(get1(pairs[m], 'key'))] = nodeVal(get1(pairs[m], 'styleUrl'));
42977                 }
42978                 styleMapIndex['#' + attr(styleMaps[l], 'id')] = pairsMap;
42979
42980             }
42981             for (var j = 0; j < placemarks.length; j++) {
42982                 gj.features = gj.features.concat(getPlacemark(placemarks[j]));
42983             }
42984             function kmlColor(v) {
42985                 var color, opacity;
42986                 v = v || '';
42987                 if (v.substr(0, 1) === '#') { v = v.substr(1); }
42988                 if (v.length === 6 || v.length === 3) { color = v; }
42989                 if (v.length === 8) {
42990                     opacity = parseInt(v.substr(0, 2), 16) / 255;
42991                     color = '#' + v.substr(6, 2) +
42992                         v.substr(4, 2) +
42993                         v.substr(2, 2);
42994                 }
42995                 return [color, isNaN(opacity) ? undefined : opacity];
42996             }
42997             function gxCoord(v) { return numarray(v.split(' ')); }
42998             function gxCoords(root) {
42999                 var elems = get(root, 'coord', 'gx'), coords = [], times = [];
43000                 if (elems.length === 0) elems = get(root, 'gx:coord');
43001                 for (var i = 0; i < elems.length; i++) coords.push(gxCoord(nodeVal(elems[i])));
43002                 var timeElems = get(root, 'when');
43003                 for (var j = 0; j < timeElems.length; j++) times.push(nodeVal(timeElems[j]));
43004                 return {
43005                     coords: coords,
43006                     times: times
43007                 };
43008             }
43009             function getGeometry(root) {
43010                 var geomNode, geomNodes, i, j, k, geoms = [], coordTimes = [];
43011                 if (get1(root, 'MultiGeometry')) { return getGeometry(get1(root, 'MultiGeometry')); }
43012                 if (get1(root, 'MultiTrack')) { return getGeometry(get1(root, 'MultiTrack')); }
43013                 if (get1(root, 'gx:MultiTrack')) { return getGeometry(get1(root, 'gx:MultiTrack')); }
43014                 for (i = 0; i < geotypes.length; i++) {
43015                     geomNodes = get(root, geotypes[i]);
43016                     if (geomNodes) {
43017                         for (j = 0; j < geomNodes.length; j++) {
43018                             geomNode = geomNodes[j];
43019                             if (geotypes[i] === 'Point') {
43020                                 geoms.push({
43021                                     type: 'Point',
43022                                     coordinates: coord1(nodeVal(get1(geomNode, 'coordinates')))
43023                                 });
43024                             } else if (geotypes[i] === 'LineString') {
43025                                 geoms.push({
43026                                     type: 'LineString',
43027                                     coordinates: coord(nodeVal(get1(geomNode, 'coordinates')))
43028                                 });
43029                             } else if (geotypes[i] === 'Polygon') {
43030                                 var rings = get(geomNode, 'LinearRing'),
43031                                     coords = [];
43032                                 for (k = 0; k < rings.length; k++) {
43033                                     coords.push(coord(nodeVal(get1(rings[k], 'coordinates'))));
43034                                 }
43035                                 geoms.push({
43036                                     type: 'Polygon',
43037                                     coordinates: coords
43038                                 });
43039                             } else if (geotypes[i] === 'Track' ||
43040                                 geotypes[i] === 'gx:Track') {
43041                                 var track = gxCoords(geomNode);
43042                                 geoms.push({
43043                                     type: 'LineString',
43044                                     coordinates: track.coords
43045                                 });
43046                                 if (track.times.length) coordTimes.push(track.times);
43047                             }
43048                         }
43049                     }
43050                 }
43051                 return {
43052                     geoms: geoms,
43053                     coordTimes: coordTimes
43054                 };
43055             }
43056             function getPlacemark(root) {
43057                 var geomsAndTimes = getGeometry(root), i, properties = {},
43058                     name = nodeVal(get1(root, 'name')),
43059                     address = nodeVal(get1(root, 'address')),
43060                     styleUrl = nodeVal(get1(root, 'styleUrl')),
43061                     description = nodeVal(get1(root, 'description')),
43062                     timeSpan = get1(root, 'TimeSpan'),
43063                     timeStamp = get1(root, 'TimeStamp'),
43064                     extendedData = get1(root, 'ExtendedData'),
43065                     lineStyle = get1(root, 'LineStyle'),
43066                     polyStyle = get1(root, 'PolyStyle'),
43067                     visibility = get1(root, 'visibility');
43068
43069                 if (!geomsAndTimes.geoms.length) return [];
43070                 if (name) properties.name = name;
43071                 if (address) properties.address = address;
43072                 if (styleUrl) {
43073                     if (styleUrl[0] !== '#') {
43074                         styleUrl = '#' + styleUrl;
43075                     }
43076
43077                     properties.styleUrl = styleUrl;
43078                     if (styleIndex[styleUrl]) {
43079                         properties.styleHash = styleIndex[styleUrl];
43080                     }
43081                     if (styleMapIndex[styleUrl]) {
43082                         properties.styleMapHash = styleMapIndex[styleUrl];
43083                         properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal];
43084                     }
43085                     // Try to populate the lineStyle or polyStyle since we got the style hash
43086                     var style = styleByHash[properties.styleHash];
43087                     if (style) {
43088                         if (!lineStyle) lineStyle = get1(style, 'LineStyle');
43089                         if (!polyStyle) polyStyle = get1(style, 'PolyStyle');
43090                     }
43091                 }
43092                 if (description) properties.description = description;
43093                 if (timeSpan) {
43094                     var begin = nodeVal(get1(timeSpan, 'begin'));
43095                     var end = nodeVal(get1(timeSpan, 'end'));
43096                     properties.timespan = { begin: begin, end: end };
43097                 }
43098                 if (timeStamp) {
43099                     properties.timestamp = nodeVal(get1(timeStamp, 'when'));
43100                 }
43101                 if (lineStyle) {
43102                     var linestyles = kmlColor(nodeVal(get1(lineStyle, 'color'))),
43103                         color = linestyles[0],
43104                         opacity = linestyles[1],
43105                         width = parseFloat(nodeVal(get1(lineStyle, 'width')));
43106                     if (color) properties.stroke = color;
43107                     if (!isNaN(opacity)) properties['stroke-opacity'] = opacity;
43108                     if (!isNaN(width)) properties['stroke-width'] = width;
43109                 }
43110                 if (polyStyle) {
43111                     var polystyles = kmlColor(nodeVal(get1(polyStyle, 'color'))),
43112                         pcolor = polystyles[0],
43113                         popacity = polystyles[1],
43114                         fill = nodeVal(get1(polyStyle, 'fill')),
43115                         outline = nodeVal(get1(polyStyle, 'outline'));
43116                     if (pcolor) properties.fill = pcolor;
43117                     if (!isNaN(popacity)) properties['fill-opacity'] = popacity;
43118                     if (fill) properties['fill-opacity'] = fill === '1' ? properties['fill-opacity'] || 1 : 0;
43119                     if (outline) properties['stroke-opacity'] = outline === '1' ? properties['stroke-opacity'] || 1 : 0;
43120                 }
43121                 if (extendedData) {
43122                     var datas = get(extendedData, 'Data'),
43123                         simpleDatas = get(extendedData, 'SimpleData');
43124
43125                     for (i = 0; i < datas.length; i++) {
43126                         properties[datas[i].getAttribute('name')] = nodeVal(get1(datas[i], 'value'));
43127                     }
43128                     for (i = 0; i < simpleDatas.length; i++) {
43129                         properties[simpleDatas[i].getAttribute('name')] = nodeVal(simpleDatas[i]);
43130                     }
43131                 }
43132                 if (visibility) {
43133                     properties.visibility = nodeVal(visibility);
43134                 }
43135                 if (geomsAndTimes.coordTimes.length) {
43136                     properties.coordTimes = (geomsAndTimes.coordTimes.length === 1) ?
43137                         geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes;
43138                 }
43139                 var feature = {
43140                     type: 'Feature',
43141                     geometry: (geomsAndTimes.geoms.length === 1) ? geomsAndTimes.geoms[0] : {
43142                         type: 'GeometryCollection',
43143                         geometries: geomsAndTimes.geoms
43144                     },
43145                     properties: properties
43146                 };
43147                 if (attr(root, 'id')) feature.id = attr(root, 'id');
43148                 return [feature];
43149             }
43150             return gj;
43151         },
43152         gpx: function(doc) {
43153             var i,
43154                 tracks = get(doc, 'trk'),
43155                 routes = get(doc, 'rte'),
43156                 waypoints = get(doc, 'wpt'),
43157                 // a feature collection
43158                 gj = fc(),
43159                 feature;
43160             for (i = 0; i < tracks.length; i++) {
43161                 feature = getTrack(tracks[i]);
43162                 if (feature) gj.features.push(feature);
43163             }
43164             for (i = 0; i < routes.length; i++) {
43165                 feature = getRoute(routes[i]);
43166                 if (feature) gj.features.push(feature);
43167             }
43168             for (i = 0; i < waypoints.length; i++) {
43169                 gj.features.push(getPoint(waypoints[i]));
43170             }
43171             function getPoints(node, pointname) {
43172                 var pts = get(node, pointname),
43173                     line = [],
43174                     times = [],
43175                     heartRates = [],
43176                     l = pts.length;
43177                 if (l < 2) return {};  // Invalid line in GeoJSON
43178                 for (var i = 0; i < l; i++) {
43179                     var c = coordPair(pts[i]);
43180                     line.push(c.coordinates);
43181                     if (c.time) times.push(c.time);
43182                     if (c.heartRate) heartRates.push(c.heartRate);
43183                 }
43184                 return {
43185                     line: line,
43186                     times: times,
43187                     heartRates: heartRates
43188                 };
43189             }
43190             function getTrack(node) {
43191                 var segments = get(node, 'trkseg'),
43192                     track = [],
43193                     times = [],
43194                     heartRates = [],
43195                     line;
43196                 for (var i = 0; i < segments.length; i++) {
43197                     line = getPoints(segments[i], 'trkpt');
43198                     if (line) {
43199                         if (line.line) track.push(line.line);
43200                         if (line.times && line.times.length) times.push(line.times);
43201                         if (line.heartRates && line.heartRates.length) heartRates.push(line.heartRates);
43202                     }
43203                 }
43204                 if (track.length === 0) return;
43205                 var properties = getProperties(node);
43206                 extend(properties, getLineStyle(get1(node, 'extensions')));
43207                 if (times.length) properties.coordTimes = track.length === 1 ? times[0] : times;
43208                 if (heartRates.length) properties.heartRates = track.length === 1 ? heartRates[0] : heartRates;
43209                 return {
43210                     type: 'Feature',
43211                     properties: properties,
43212                     geometry: {
43213                         type: track.length === 1 ? 'LineString' : 'MultiLineString',
43214                         coordinates: track.length === 1 ? track[0] : track
43215                     }
43216                 };
43217             }
43218             function getRoute(node) {
43219                 var line = getPoints(node, 'rtept');
43220                 if (!line.line) return;
43221                 var prop = getProperties(node);
43222                 extend(prop, getLineStyle(get1(node, 'extensions')));
43223                 var routeObj = {
43224                     type: 'Feature',
43225                     properties: prop,
43226                     geometry: {
43227                         type: 'LineString',
43228                         coordinates: line.line
43229                     }
43230                 };
43231                 return routeObj;
43232             }
43233             function getPoint(node) {
43234                 var prop = getProperties(node);
43235                 extend(prop, getMulti(node, ['sym']));
43236                 return {
43237                     type: 'Feature',
43238                     properties: prop,
43239                     geometry: {
43240                         type: 'Point',
43241                         coordinates: coordPair(node).coordinates
43242                     }
43243                 };
43244             }
43245             function getLineStyle(extensions) {
43246                 var style = {};
43247                 if (extensions) {
43248                     var lineStyle = get1(extensions, 'line');
43249                     if (lineStyle) {
43250                         var color = nodeVal(get1(lineStyle, 'color')),
43251                             opacity = parseFloat(nodeVal(get1(lineStyle, 'opacity'))),
43252                             width = parseFloat(nodeVal(get1(lineStyle, 'width')));
43253                         if (color) style.stroke = color;
43254                         if (!isNaN(opacity)) style['stroke-opacity'] = opacity;
43255                         // GPX width is in mm, convert to px with 96 px per inch
43256                         if (!isNaN(width)) style['stroke-width'] = width * 96 / 25.4;
43257                     }
43258                 }
43259                 return style;
43260             }
43261             function getProperties(node) {
43262                 var prop = getMulti(node, ['name', 'cmt', 'desc', 'type', 'time', 'keywords']),
43263                     links = get(node, 'link');
43264                 if (links.length) prop.links = [];
43265                 for (var i = 0, link; i < links.length; i++) {
43266                     link = { href: attr(links[i], 'href') };
43267                     extend(link, getMulti(links[i], ['text', 'type']));
43268                     prop.links.push(link);
43269                 }
43270                 return prop;
43271             }
43272             return gj;
43273         }
43274     };
43275     return t;
43276 })();
43277
43278 module.exports = toGeoJSON;
43279 });
43280
43281 function svgGpx(projection$$1, context, dispatch$$1) {
43282     var showLabels = true,
43283         detected = utilDetect(),
43284         layer;
43285
43286
43287     function init() {
43288         if (svgGpx.initialized) return;  // run once
43289
43290         svgGpx.geojson = {};
43291         svgGpx.enabled = true;
43292
43293         function over() {
43294             event.stopPropagation();
43295             event.preventDefault();
43296             event.dataTransfer.dropEffect = 'copy';
43297         }
43298
43299         select('body')
43300             .attr('dropzone', 'copy')
43301             .on('drop.localgpx', function() {
43302                 event.stopPropagation();
43303                 event.preventDefault();
43304                 if (!detected.filedrop) return;
43305                 drawGpx.files(event.dataTransfer.files);
43306             })
43307             .on('dragenter.localgpx', over)
43308             .on('dragexit.localgpx', over)
43309             .on('dragover.localgpx', over);
43310
43311         svgGpx.initialized = true;
43312     }
43313
43314
43315     function drawGpx(selection$$1) {
43316         var geojson = svgGpx.geojson,
43317             enabled = svgGpx.enabled;
43318
43319         layer = selection$$1.selectAll('.layer-gpx')
43320             .data(enabled ? [0] : []);
43321
43322         layer.exit()
43323             .remove();
43324
43325         layer = layer.enter()
43326             .append('g')
43327             .attr('class', 'layer-gpx')
43328             .merge(layer);
43329
43330
43331         var paths = layer
43332             .selectAll('path')
43333             .data([geojson]);
43334
43335         paths.exit()
43336             .remove();
43337
43338         paths = paths.enter()
43339             .append('path')
43340             .attr('class', 'gpx')
43341             .merge(paths);
43342
43343
43344         var path$$1 = index$4(projection$$1);
43345
43346         paths
43347             .attr('d', path$$1);
43348
43349
43350         var labels = layer.selectAll('text')
43351             .data(showLabels && geojson.features ? geojson.features : []);
43352
43353         labels.exit()
43354             .remove();
43355
43356         labels = labels.enter()
43357             .append('text')
43358             .attr('class', 'gpx')
43359             .merge(labels);
43360
43361         labels
43362             .text(function(d) {
43363                 return d.properties.desc || d.properties.name;
43364             })
43365             .attr('x', function(d) {
43366                 var centroid = path$$1.centroid(d);
43367                 return centroid[0] + 7;
43368             })
43369             .attr('y', function(d) {
43370                 var centroid = path$$1.centroid(d);
43371                 return centroid[1];
43372             });
43373
43374     }
43375
43376
43377     function toDom(x) {
43378         return (new DOMParser()).parseFromString(x, 'text/xml');
43379     }
43380
43381
43382     function getExtension(fileName) {
43383         if (lodash.isUndefined(fileName)) {
43384             return '';
43385         }
43386
43387         var lastDotIndex = fileName.lastIndexOf('.');
43388         if (lastDotIndex < 0) {
43389             return '';
43390         }
43391
43392         return fileName.substr(lastDotIndex);
43393     }
43394
43395
43396     function parseSaveAndZoom(extension, data) {
43397         switch (extension) {
43398             default:
43399                 drawGpx.geojson(togeojson.gpx(toDom(data))).fitZoom();
43400                 break;
43401             case '.kml':
43402                 drawGpx.geojson(togeojson.kml(toDom(data))).fitZoom();
43403                 break;
43404             case '.geojson':
43405             case '.json':
43406                 drawGpx.geojson(JSON.parse(data)).fitZoom();
43407                 break;
43408         }
43409     }
43410
43411
43412     drawGpx.showLabels = function(_) {
43413         if (!arguments.length) return showLabels;
43414         showLabels = _;
43415         return this;
43416     };
43417
43418
43419     drawGpx.enabled = function(_) {
43420         if (!arguments.length) return svgGpx.enabled;
43421         svgGpx.enabled = _;
43422         dispatch$$1.call('change');
43423         return this;
43424     };
43425
43426
43427     drawGpx.hasGpx = function() {
43428         var geojson = svgGpx.geojson;
43429         return (!(lodash.isEmpty(geojson) || lodash.isEmpty(geojson.features)));
43430     };
43431
43432
43433     drawGpx.geojson = function(gj) {
43434         if (!arguments.length) return svgGpx.geojson;
43435         if (lodash.isEmpty(gj) || lodash.isEmpty(gj.features)) return this;
43436         svgGpx.geojson = gj;
43437         dispatch$$1.call('change');
43438         return this;
43439     };
43440
43441
43442     drawGpx.url = function(url) {
43443         text(url, function(err, data) {
43444             if (!err) {
43445                 var extension = getExtension(url);
43446                 parseSaveAndZoom(extension, data);
43447             }
43448         });
43449         return this;
43450     };
43451
43452
43453     drawGpx.files = function(fileList) {
43454         if (!fileList.length) return this;
43455         var f = fileList[0],
43456             reader = new FileReader();
43457
43458         reader.onload = (function(file) {
43459             var extension = getExtension(file.name);
43460
43461             return function (e) {
43462                 parseSaveAndZoom(extension, e.target.result);
43463             };
43464         })(f);
43465
43466         reader.readAsText(f);
43467         return this;
43468     };
43469
43470
43471     drawGpx.fitZoom = function() {
43472         if (!this.hasGpx()) return this;
43473         var geojson = svgGpx.geojson;
43474
43475         var map = context.map(),
43476             viewport = map.trimmedExtent().polygon(),
43477             coords = lodash.reduce(geojson.features, function(coords, feature) {
43478                 var c = feature.geometry.coordinates;
43479
43480                 /* eslint-disable no-fallthrough */
43481                 switch (feature.geometry.type) {
43482                     case 'Point':
43483                         c = [c];
43484                     case 'MultiPoint':
43485                     case 'LineString':
43486                         break;
43487
43488                     case 'MultiPolygon':
43489                         c = lodash.flatten(c);
43490                     case 'Polygon':
43491                     case 'MultiLineString':
43492                         c = lodash.flatten(c);
43493                         break;
43494                 }
43495                 /* eslint-enable no-fallthrough */
43496
43497                 return lodash.union(coords, c);
43498             }, []);
43499
43500         if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
43501             var extent$$1 = geoExtent$$1(bounds({ type: 'LineString', coordinates: coords }));
43502             map.centerZoom(extent$$1.center(), map.trimmedExtentZoom(extent$$1));
43503         }
43504
43505         return this;
43506     };
43507
43508
43509     init();
43510     return drawGpx;
43511 }
43512
43513 function svgIcon(name, svgklass, useklass) {
43514     return function drawIcon(selection) {
43515         selection.selectAll('svg')
43516             .data([0])
43517             .enter()
43518             .append('svg')
43519             .attr('class', 'icon ' + (svgklass || ''))
43520             .append('use')
43521             .attr('xlink:href', name)
43522             .attr('class', useklass);
43523     };
43524 }
43525
43526 function svgLabels(projection$$1, context) {
43527     var path$$1 = index$4(projection$$1),
43528         detected = utilDetect(),
43529         baselineHack = (detected.ie || detected.browser.toLowerCase() === 'edge'),
43530         rdrawn = index$9(),
43531         rskipped = index$9(),
43532         textWidthCache = {},
43533         entitybboxes = {};
43534
43535     // Listed from highest to lowest priority
43536     var labelStack = [
43537         ['line', 'aeroway', '*', 12],
43538         ['line', 'highway', 'motorway', 12],
43539         ['line', 'highway', 'trunk', 12],
43540         ['line', 'highway', 'primary', 12],
43541         ['line', 'highway', 'secondary', 12],
43542         ['line', 'highway', 'tertiary', 12],
43543         ['line', 'highway', '*', 12],
43544         ['line', 'railway', '*', 12],
43545         ['line', 'waterway', '*', 12],
43546         ['area', 'aeroway', '*', 12],
43547         ['area', 'amenity', '*', 12],
43548         ['area', 'building', '*', 12],
43549         ['area', 'historic', '*', 12],
43550         ['area', 'leisure', '*', 12],
43551         ['area', 'man_made', '*', 12],
43552         ['area', 'natural', '*', 12],
43553         ['area', 'shop', '*', 12],
43554         ['area', 'tourism', '*', 12],
43555         ['area', 'camp_site', '*', 12],
43556         ['point', 'aeroway', '*', 10],
43557         ['point', 'amenity', '*', 10],
43558         ['point', 'building', '*', 10],
43559         ['point', 'historic', '*', 10],
43560         ['point', 'leisure', '*', 10],
43561         ['point', 'man_made', '*', 10],
43562         ['point', 'natural', '*', 10],
43563         ['point', 'shop', '*', 10],
43564         ['point', 'tourism', '*', 10],
43565         ['point', 'camp_site', '*', 10],
43566         ['line', 'name', '*', 12],
43567         ['area', 'name', '*', 12],
43568         ['point', 'name', '*', 10]
43569     ];
43570
43571
43572     function blacklisted(preset) {
43573         var noIcons = ['building', 'landuse', 'natural'];
43574         return lodash.some(noIcons, function(s) {
43575             return preset.id.indexOf(s) >= 0;
43576         });
43577     }
43578
43579
43580     function get(array, prop) {
43581         return function(d, i) { return array[i][prop]; };
43582     }
43583
43584
43585     function textWidth(text$$1, size, elem) {
43586         var c = textWidthCache[size];
43587         if (!c) c = textWidthCache[size] = {};
43588
43589         if (c[text$$1]) {
43590             return c[text$$1];
43591
43592         } else if (elem) {
43593             c[text$$1] = elem.getComputedTextLength();
43594             return c[text$$1];
43595
43596         } else {
43597             var str = encodeURIComponent(text$$1).match(/%[CDEFcdef]/g);
43598             if (str === null) {
43599                 return size / 3 * 2 * text$$1.length;
43600             } else {
43601                 return size / 3 * (2 * text$$1.length + str.length);
43602             }
43603         }
43604     }
43605
43606
43607     function drawLinePaths(selection$$1, entities, filter, classes, labels) {
43608         var paths = selection$$1.selectAll('path')
43609             .filter(filter)
43610             .data(entities, osmEntity$$1.key);
43611
43612         paths.exit()
43613             .remove();
43614
43615         paths.enter()
43616             .append('path')
43617             .style('stroke-width', get(labels, 'font-size'))
43618             .attr('id', function(d) { return 'labelpath-' + d.id; })
43619             .attr('class', classes)
43620             .merge(paths)
43621             .attr('d', get(labels, 'lineString'));
43622     }
43623
43624
43625     function drawLineLabels(selection$$1, entities, filter, classes, labels) {
43626         var texts = selection$$1.selectAll('text.' + classes)
43627             .filter(filter)
43628             .data(entities, osmEntity$$1.key);
43629
43630         texts.exit()
43631             .remove();
43632
43633         texts.enter()
43634             .append('text')
43635             .attr('class', function(d, i) { return classes + ' ' + labels[i].classes + ' ' + d.id; })
43636             .attr('dy', baselineHack ? '0.35em' : null)
43637             .append('textPath')
43638             .attr('class', 'textpath');
43639
43640         texts = selection$$1.selectAll('text.' + classes);
43641
43642         texts.selectAll('.textpath')
43643             .filter(filter)
43644             .data(entities, osmEntity$$1.key)
43645             .attr('startOffset', '50%')
43646             .attr('xlink:href', function(d) { return '#labelpath-' + d.id; })
43647             .text(utilDisplayNameForPath);
43648     }
43649
43650
43651     function drawPointLabels(selection$$1, entities, filter, classes, labels) {
43652         var texts = selection$$1.selectAll('text.' + classes)
43653             .filter(filter)
43654             .data(entities, osmEntity$$1.key);
43655
43656         texts.exit()
43657             .remove();
43658
43659         texts = texts.enter()
43660             .append('text')
43661             .attr('class', function(d, i) {
43662                 return classes + ' ' + labels[i].classes + ' ' + d.id;
43663             })
43664             .merge(texts);
43665
43666         texts
43667             .attr('x', get(labels, 'x'))
43668             .attr('y', get(labels, 'y'))
43669             .style('text-anchor', get(labels, 'textAnchor'))
43670             .text(utilDisplayName)
43671             .each(function(d, i) {
43672                 textWidth(utilDisplayName(d), labels[i].height, this);
43673             });
43674     }
43675
43676
43677     function drawAreaLabels(selection$$1, entities, filter, classes, labels) {
43678         entities = entities.filter(hasText);
43679         labels = labels.filter(hasText);
43680         drawPointLabels(selection$$1, entities, filter, classes, labels);
43681
43682         function hasText(d, i) {
43683             return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
43684         }
43685     }
43686
43687
43688     function drawAreaIcons(selection$$1, entities, filter, classes, labels) {
43689         var icons = selection$$1.selectAll('use.' + classes)
43690             .filter(filter)
43691             .data(entities, osmEntity$$1.key);
43692
43693         icons.exit()
43694             .remove();
43695
43696         icons = icons.enter()
43697             .append('use')
43698             .attr('class', 'icon ' + classes)
43699             .attr('width', '17px')
43700             .attr('height', '17px')
43701             .merge(icons);
43702
43703         icons
43704             .attr('transform', get(labels, 'transform'))
43705             .attr('xlink:href', function(d) {
43706                 var preset = context.presets().match(d, context.graph()),
43707                     picon = preset && preset.icon;
43708
43709                 if (!picon)
43710                     return '';
43711                 else {
43712                     var isMaki = dataFeatureIcons.indexOf(picon) !== -1;
43713                     return '#' + picon + (isMaki ? '-15' : '');
43714                 }
43715             });
43716     }
43717
43718
43719     function drawCollisionBoxes(selection$$1, rtree, which) {
43720         var showDebug = context.getDebug('collision'),
43721             classes = 'debug ' + which + ' ' +
43722                 (which === 'debug-skipped' ? 'orange' : 'yellow');
43723
43724         var debug = selection$$1.selectAll('.layer-label-debug')
43725                 .data(showDebug ? [true] : []);
43726
43727         debug.exit()
43728             .remove();
43729
43730         debug = debug.enter()
43731             .append('g')
43732             .attr('class', 'layer-label-debug')
43733             .merge(debug);
43734
43735         if (showDebug) {
43736             var gj = rtree.all().map(function(d) {
43737                 return { type: 'Polygon', coordinates: [[
43738                     [d.minX, d.minY],
43739                     [d.maxX, d.minY],
43740                     [d.maxX, d.maxY],
43741                     [d.minX, d.maxY],
43742                     [d.minX, d.minY]
43743                 ]]};
43744             });
43745
43746             var debugboxes = debug.selectAll('.' + which)
43747                 .data(gj);
43748
43749             debugboxes.exit()
43750                 .remove();
43751
43752             debugboxes = debugboxes.enter()
43753                 .append('path')
43754                 .attr('class', classes)
43755                 .merge(debugboxes);
43756
43757             debugboxes
43758                 .attr('d', index$4());
43759         }
43760     }
43761
43762
43763     function drawLabels(selection$$1, graph, entities, filter, dimensions, fullRedraw) {
43764         var lowZoom = context.surface().classed('low-zoom');
43765
43766         var labelable = [], i, j, k, entity, geometry;
43767         for (i = 0; i < labelStack.length; i++) {
43768             labelable.push([]);
43769         }
43770
43771         if (fullRedraw) {
43772             rdrawn.clear();
43773             rskipped.clear();
43774             entitybboxes = {};
43775         } else {
43776             for (i = 0; i < entities.length; i++) {
43777                 entity = entities[i];
43778                 var toRemove = []
43779                     .concat(entitybboxes[entity.id] || [])
43780                     .concat(entitybboxes[entity.id + 'I'] || []);
43781
43782                 for (j = 0; j < toRemove.length; j++) {
43783                     rdrawn.remove(toRemove[j]);
43784                     rskipped.remove(toRemove[j]);
43785                 }
43786             }
43787         }
43788
43789         // Split entities into groups specified by labelStack
43790         for (i = 0; i < entities.length; i++) {
43791             entity = entities[i];
43792             geometry = entity.geometry(graph);
43793             if (geometry === 'vertex') { geometry = 'point'; }  // treat vertex like point
43794
43795             var preset = geometry === 'area' && context.presets().match(entity, graph),
43796                 icon = preset && !blacklisted(preset) && preset.icon;
43797
43798             if (!icon && !utilDisplayName(entity))
43799                 continue;
43800
43801             for (k = 0; k < labelStack.length; k++) {
43802                 var matchGeom = labelStack[k][0],
43803                     matchKey = labelStack[k][1],
43804                     matchVal = labelStack[k][2],
43805                     hasVal = entity.tags[matchKey];
43806
43807                 if (geometry === matchGeom && hasVal && (matchVal === '*' || matchVal === hasVal)) {
43808                     labelable[k].push(entity);
43809                     break;
43810                 }
43811             }
43812         }
43813
43814         var positions = {
43815             point: [],
43816             line: [],
43817             area: []
43818         };
43819
43820         var labelled = {
43821             point: [],
43822             line: [],
43823             area: []
43824         };
43825
43826         // Try and find a valid label for labellable entities
43827         for (k = 0; k < labelable.length; k++) {
43828             var fontSize = labelStack[k][3];
43829             for (i = 0; i < labelable[k].length; i++) {
43830                 entity = labelable[k][i];
43831                 geometry = entity.geometry(graph);
43832
43833                 var getName = (geometry === 'line') ? utilDisplayNameForPath : utilDisplayName,
43834                     name = getName(entity),
43835                     width = name && textWidth(name, fontSize),
43836                     p;
43837
43838                 if (geometry === 'point') {
43839                     p = getPointLabel(entity, width, fontSize, geometry);
43840                 } else if (geometry === 'vertex' && !lowZoom) {
43841                     // don't label vertices at low zoom because they don't have icons
43842                     p = getPointLabel(entity, width, fontSize, geometry);
43843                 } else if (geometry === 'line') {
43844                     p = getLineLabel(entity, width, fontSize);
43845                 } else if (geometry === 'area') {
43846                     p = getAreaLabel(entity, width, fontSize);
43847                 }
43848
43849                 if (p) {
43850                     if (geometry === 'vertex') { geometry = 'point'; }  // treat vertex like point
43851                     p.classes = geometry + ' tag-' + labelStack[k][1];
43852                     positions[geometry].push(p);
43853                     labelled[geometry].push(entity);
43854                 }
43855             }
43856         }
43857
43858
43859         function getPointLabel(entity, width, height, geometry) {
43860             var y = (geometry === 'point' ? -12 : 0),
43861                 pointOffsets = {
43862                     ltr: [15, y, 'start'],
43863                     rtl: [-15, y, 'end']
43864                 };
43865
43866             var coord = projection$$1(entity.loc),
43867                 margin = 2,
43868                 offset = pointOffsets[textDirection],
43869                 p = {
43870                     height: height,
43871                     width: width,
43872                     x: coord[0] + offset[0],
43873                     y: coord[1] + offset[1],
43874                     textAnchor: offset[2]
43875                 },
43876                 bbox;
43877
43878             if (textDirection === 'rtl') {
43879                 bbox = {
43880                     minX: p.x - width - margin,
43881                     minY: p.y - (height / 2) - margin,
43882                     maxX: p.x + margin,
43883                     maxY: p.y + (height / 2) + margin
43884                 };
43885             } else {
43886                 bbox = {
43887                     minX: p.x - margin,
43888                     minY: p.y - (height / 2) - margin,
43889                     maxX: p.x + width + margin,
43890                     maxY: p.y + (height / 2) + margin
43891                 };
43892             }
43893
43894             if (tryInsert([bbox], entity.id, true)) {
43895                 return p;
43896             }
43897         }
43898
43899
43900         function getLineLabel(entity, width, height) {
43901             var viewport = geoExtent$$1(context.projection.clipExtent()).polygon(),
43902                 nodes = lodash.map(graph.childNodes(entity), 'loc').map(projection$$1),
43903                 length = geoPathLength(nodes);
43904
43905             if (length < width + 20) return;
43906
43907             // % along the line to attempt to place the label
43908             var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70,
43909                                25, 75, 20, 80, 15, 95, 10, 90, 5, 95];
43910             var margin = 3;
43911
43912             for (var i = 0; i < lineOffsets.length; i++) {
43913                 var offset = lineOffsets[i],
43914                     middle = offset / 100 * length,
43915                     start = middle - width / 2;
43916
43917                 if (start < 0 || start + width > length) continue;
43918
43919                 // generate subpath and ignore paths that are invalid or don't cross viewport.
43920                 var sub = subpath(nodes, start, start + width);
43921                 if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
43922                     continue;
43923                 }
43924
43925                 var isReverse = reverse$$1(sub);
43926                 if (isReverse) {
43927                     sub = sub.reverse();
43928                 }
43929
43930                 var bboxes = [],
43931                     boxsize = (height + 2) / 2;
43932
43933                 for (var j = 0; j < sub.length - 1; j++) {
43934                     var a = sub[j];
43935                     var b = sub[j + 1];
43936                     var num = Math.max(1, Math.floor(geoEuclideanDistance(a, b) / boxsize / 2));
43937
43938                     for (var box = 0; box < num; box++) {
43939                         var p = geoInterp(a, b, box / num);
43940                         var x0 = p[0] - boxsize - margin;
43941                         var y0 = p[1] - boxsize - margin;
43942                         var x1 = p[0] + boxsize + margin;
43943                         var y1 = p[1] + boxsize + margin;
43944
43945                         bboxes.push({
43946                             minX: Math.min(x0, x1),
43947                             minY: Math.min(y0, y1),
43948                             maxX: Math.max(x0, x1),
43949                             maxY: Math.max(y0, y1)
43950                         });
43951                     }
43952                 }
43953
43954                 if (tryInsert(bboxes, entity.id, false)) {
43955                     return {
43956                         'font-size': height + 2,
43957                         lineString: lineString(sub),
43958                         startOffset: offset + '%'
43959                     };
43960                 }
43961             }
43962
43963             function reverse$$1(p) {
43964                 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
43965                 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI/2 && angle > -Math.PI/2);
43966             }
43967
43968             function lineString(nodes) {
43969                 return 'M' + nodes.join('L');
43970             }
43971
43972             function subpath(nodes, from, to) {
43973                 var sofar = 0,
43974                     start, end, i0, i1;
43975
43976                 for (var i = 0; i < nodes.length - 1; i++) {
43977                     var a = nodes[i],
43978                         b = nodes[i + 1];
43979                     var current = geoEuclideanDistance(a, b);
43980                     var portion;
43981                     if (!start && sofar + current >= from) {
43982                         portion = (from - sofar) / current;
43983                         start = [
43984                             a[0] + portion * (b[0] - a[0]),
43985                             a[1] + portion * (b[1] - a[1])
43986                         ];
43987                         i0 = i + 1;
43988                     }
43989                     if (!end && sofar + current >= to) {
43990                         portion = (to - sofar) / current;
43991                         end = [
43992                             a[0] + portion * (b[0] - a[0]),
43993                             a[1] + portion * (b[1] - a[1])
43994                         ];
43995                         i1 = i + 1;
43996                     }
43997                     sofar += current;
43998                 }
43999
44000                 var ret = nodes.slice(i0, i1);
44001                 ret.unshift(start);
44002                 ret.push(end);
44003                 return ret;
44004             }
44005         }
44006
44007
44008         function getAreaLabel(entity, width, height) {
44009             var centroid = path$$1.centroid(entity.asGeoJSON(graph, true)),
44010                 extent$$1 = entity.extent(graph),
44011                 entitywidth = projection$$1(extent$$1[1])[0] - projection$$1(extent$$1[0])[0];
44012
44013             if (isNaN(centroid[0]) || entitywidth < 20) return;
44014
44015             var iconSize = 20,
44016                 iconX = centroid[0] - (iconSize / 2),
44017                 iconY = centroid[1] - (iconSize / 2),
44018                 margin = 2,
44019                 textOffset = iconSize + margin,
44020                 p = { transform: 'translate(' + iconX + ',' + iconY + ')' };
44021
44022             var bbox = {
44023                 minX: iconX,
44024                 minY: iconY,
44025                 maxX: iconX + iconSize,
44026                 maxY: iconY + iconSize
44027             };
44028
44029             // try to add icon
44030             if (tryInsert([bbox], entity.id + 'I', true)) {
44031                 if (width && entitywidth >= width + 20) {
44032                     var labelX = centroid[0],
44033                         labelY = centroid[1] + textOffset;
44034
44035                     bbox = {
44036                         minX: labelX - (width / 2) - margin,
44037                         minY: labelY - (height / 2) - margin,
44038                         maxX: labelX + (width / 2) + margin,
44039                         maxY: labelY + (height / 2) + margin
44040                     };
44041
44042                     // try to add label
44043                     if (tryInsert([bbox], entity.id, true)) {
44044                         p.x = labelX;
44045                         p.y = labelY;
44046                         p.textAnchor = 'middle';
44047                         p.height = height;
44048                     }
44049                 }
44050
44051                 return p;
44052             }
44053         }
44054
44055
44056         function tryInsert(bboxes, id, saveSkipped) {
44057             var skipped = false,
44058                 bbox;
44059
44060             for (var i = 0; i < bboxes.length; i++) {
44061                 bbox = bboxes[i];
44062                 bbox.id = id;
44063
44064                 // Check that label is visible
44065                 if (bbox.minX < 0 || bbox.minY < 0 || bbox.maxX > dimensions[0] || bbox.maxY > dimensions[1]) {
44066                     skipped = true;
44067                     break;
44068                 }
44069                 if (rdrawn.collides(bbox)) {
44070                     skipped = true;
44071                     break;
44072                 }
44073             }
44074
44075             entitybboxes[id] = bboxes;
44076
44077             if (skipped) {
44078                 if (saveSkipped) {
44079                     rskipped.load(bboxes);
44080                 }
44081             } else {
44082                 rdrawn.load(bboxes);
44083             }
44084
44085             return !skipped;
44086         }
44087
44088
44089         var label = selection$$1.selectAll('.layer-label'),
44090             halo = selection$$1.selectAll('.layer-halo');
44091
44092         // points
44093         drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
44094         drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point);
44095
44096         // lines
44097         drawLinePaths(halo, labelled.line, filter, '', positions.line);
44098         drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
44099         drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line);
44100
44101         // areas
44102         drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
44103         drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
44104         drawAreaIcons(label, labelled.area, filter, 'areaicon', positions.area);
44105         drawAreaIcons(halo, labelled.area, filter, 'areaicon-halo', positions.area);
44106
44107         // debug
44108         drawCollisionBoxes(label, rskipped, 'debug-skipped');
44109         drawCollisionBoxes(label, rdrawn, 'debug-drawn');
44110
44111         selection$$1.call(filterLabels);
44112     }
44113
44114
44115     function filterLabels(selection$$1) {
44116         var layers = selection$$1
44117             .selectAll('.layer-label, .layer-halo');
44118
44119         layers.selectAll('.proximate')
44120             .classed('proximate', false);
44121
44122         var mouse$$1 = context.mouse(),
44123             graph = context.graph(),
44124             selectedIDs = context.selectedIDs(),
44125             ids = [],
44126             pad, bbox;
44127
44128         // hide labels near the mouse
44129         if (mouse$$1) {
44130             pad = 20;
44131             bbox = { minX: mouse$$1[0] - pad, minY: mouse$$1[1] - pad, maxX: mouse$$1[0] + pad, maxY: mouse$$1[1] + pad };
44132             ids.push.apply(ids, lodash.map(rdrawn.search(bbox), 'id'));
44133         }
44134
44135         // hide labels along selected ways, or near selected vertices
44136         for (var i = 0; i < selectedIDs.length; i++) {
44137             var entity = graph.hasEntity(selectedIDs[i]);
44138             if (!entity) continue;
44139             var geometry = entity.geometry(graph);
44140
44141             if (geometry === 'line') {
44142                 ids.push(selectedIDs[i]);
44143             } else if (geometry === 'vertex') {
44144                 var point = context.projection(entity.loc);
44145                 pad = 10;
44146                 bbox = { minX: point[0] - pad, minY: point[1] - pad, maxX: point[0] + pad, maxY: point[1] + pad };
44147                 ids.push.apply(ids, lodash.map(rdrawn.search(bbox), 'id'));
44148             }
44149         }
44150
44151         layers.selectAll(utilEntitySelector(ids))
44152             .classed('proximate', true);
44153     }
44154
44155
44156     var throttleFilterLabels = lodash.throttle(filterLabels, 100);
44157
44158
44159     drawLabels.observe = function(selection$$1) {
44160         var listener = function() { throttleFilterLabels(selection$$1); };
44161         selection$$1.on('mousemove.hidelabels', listener);
44162         context.on('enter.hidelabels', listener);
44163     };
44164
44165
44166     drawLabels.off = function(selection$$1) {
44167         throttleFilterLabels.cancel();
44168         selection$$1.on('mousemove.hidelabels', null);
44169         context.on('enter.hidelabels', null);
44170     };
44171
44172
44173     return drawLabels;
44174 }
44175
44176 function refresh(selection, node) {
44177     var cr = node.getBoundingClientRect();
44178     var prop = [cr.width, cr.height];
44179     selection.property('__dimensions__', prop);
44180     return prop;
44181 }
44182
44183 function utilGetDimensions(selection, force) {
44184     if (!selection || selection.empty()) {
44185         return [0, 0];
44186     }
44187     var node = selection.node(),
44188         cached = selection.property('__dimensions__');
44189     return (!cached || force) ? refresh(selection, node) : cached;
44190 }
44191
44192
44193 function utilSetDimensions(selection, dimensions) {
44194     if (!selection || selection.empty()) {
44195         return selection;
44196     }
44197     var node = selection.node();
44198     if (dimensions === null) {
44199         refresh(selection, node);
44200         return selection;
44201     }
44202     return selection
44203         .property('__dimensions__', [dimensions[0], dimensions[1]])
44204         .attr('width', dimensions[0])
44205         .attr('height', dimensions[1]);
44206 }
44207
44208 function svgPointTransform(projection) {
44209     return function(entity) {
44210         // http://jsperf.com/short-array-join
44211         var pt = projection(entity.loc);
44212         return 'translate(' + pt[0] + ',' + pt[1] + ')';
44213     };
44214 }
44215
44216 function d3geoTile() {
44217   var size = [960, 500],
44218       scale = 256,
44219       scaleExtent = [0, 20],
44220       translate = [size[0] / 2, size[1] / 2],
44221       zoomDelta = 0;
44222
44223   function bound(_) {
44224       return Math.min(scaleExtent[1], Math.max(scaleExtent[0], _));
44225   }
44226
44227   function tile() {
44228     var z = Math.max(Math.log(scale) / Math.LN2 - 8, 0),
44229         z0 = bound(Math.round(z + zoomDelta)),
44230         k = Math.pow(2, z - z0 + 8),
44231         origin = [(translate[0] - scale / 2) / k, (translate[1] - scale / 2) / k],
44232         tiles = [],
44233         cols = sequence(Math.max(0, Math.floor(-origin[0])), Math.max(0, Math.ceil(size[0] / k - origin[0]))),
44234         rows = sequence(Math.max(0, Math.floor(-origin[1])), Math.max(0, Math.ceil(size[1] / k - origin[1])));
44235
44236     rows.forEach(function(y) {
44237       cols.forEach(function(x) {
44238         tiles.push([x, y, z0]);
44239       });
44240     });
44241
44242     tiles.translate = origin;
44243     tiles.scale = k;
44244
44245     return tiles;
44246   }
44247
44248   tile.scaleExtent = function(_) {
44249     if (!arguments.length) return scaleExtent;
44250     scaleExtent = _;
44251     return tile;
44252   };
44253
44254   tile.size = function(_) {
44255     if (!arguments.length) return size;
44256     size = _;
44257     return tile;
44258   };
44259
44260   tile.scale = function(_) {
44261     if (!arguments.length) return scale;
44262     scale = _;
44263     return tile;
44264   };
44265
44266   tile.translate = function(_) {
44267     if (!arguments.length) return translate;
44268     translate = _;
44269     return tile;
44270   };
44271
44272   tile.zoomDelta = function(_) {
44273     if (!arguments.length) return zoomDelta;
44274     zoomDelta = +_;
44275     return tile;
44276   };
44277
44278   return tile;
44279 }
44280
44281 /* global Mapillary:false */
44282 var apibase = 'https://a.mapillary.com/v3/';
44283 var viewercss = 'mapillary-js/mapillary.min.css';
44284 var viewerjs = 'mapillary-js/mapillary.min.js';
44285 var clientId = 'NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1ZWYyMmYwNjdmNDdlNmVi';
44286 var maxResults = 1000;
44287 var tileZoom = 14;
44288 var dispatch$2 = dispatch('loadedImages', 'loadedSigns');
44289 var mapillaryCache;
44290 var mapillaryClicks;
44291 var mapillaryImage;
44292 var mapillarySignDefs;
44293 var mapillarySignSprite;
44294 var mapillaryViewer;
44295
44296
44297 function abortRequest(i) {
44298     i.abort();
44299 }
44300
44301
44302 function nearNullIsland(x, y, z) {
44303     if (z >= 7) {
44304         var center = Math.pow(2, z - 1),
44305             width = Math.pow(2, z - 6),
44306             min$$1 = center - (width / 2),
44307             max$$1 = center + (width / 2) - 1;
44308         return x >= min$$1 && x <= max$$1 && y >= min$$1 && y <= max$$1;
44309     }
44310     return false;
44311 }
44312
44313
44314 function maxPageAtZoom(z) {
44315     if (z < 15)   return 2;
44316     if (z === 15) return 5;
44317     if (z === 16) return 10;
44318     if (z === 17) return 20;
44319     if (z === 18) return 40;
44320     if (z > 18)   return 80;
44321 }
44322
44323
44324 function getTiles(projection$$1) {
44325     var s = projection$$1.scale() * 2 * Math.PI,
44326         z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
44327         ts = 256 * Math.pow(2, z - tileZoom),
44328         origin = [
44329             s / 2 - projection$$1.translate()[0],
44330             s / 2 - projection$$1.translate()[1]];
44331
44332     return d3geoTile()
44333         .scaleExtent([tileZoom, tileZoom])
44334         .scale(s)
44335         .size(projection$$1.clipExtent()[1])
44336         .translate(projection$$1.translate())()
44337         .map(function(tile) {
44338             var x = tile[0] * ts - origin[0],
44339                 y = tile[1] * ts - origin[1];
44340
44341             return {
44342                 id: tile.toString(),
44343                 xyz: tile,
44344                 extent: geoExtent$$1(
44345                     projection$$1.invert([x, y + ts]),
44346                     projection$$1.invert([x + ts, y])
44347                 )
44348             };
44349         });
44350 }
44351
44352
44353 function loadTiles(which, url, projection$$1) {
44354     var s = projection$$1.scale() * 2 * Math.PI,
44355         currZoom = Math.floor(Math.max(Math.log(s) / Math.log(2) - 8, 0));
44356
44357     var tiles = getTiles(projection$$1).filter(function(t) {
44358             return !nearNullIsland(t.xyz[0], t.xyz[1], t.xyz[2]);
44359         });
44360
44361     lodash.filter(which.inflight, function(v, k) {
44362         var wanted = lodash.find(tiles, function(tile) { return k === (tile.id + ',0'); });
44363         if (!wanted) delete which.inflight[k];
44364         return !wanted;
44365     }).map(abortRequest);
44366
44367     tiles.forEach(function(tile) {
44368         loadNextTilePage(which, currZoom, url, tile);
44369     });
44370 }
44371
44372
44373 function loadNextTilePage(which, currZoom, url, tile) {
44374     var cache = mapillaryCache[which],
44375         rect = tile.extent.rectangle(),
44376         maxPages = maxPageAtZoom(currZoom),
44377         nextPage = cache.nextPage[tile.id] || 0,
44378         nextURL = cache.nextURL[tile.id] || url +
44379             utilQsString({
44380                 per_page: maxResults,
44381                 page: nextPage,
44382                 client_id: clientId,
44383                 bbox: [rect[0], rect[1], rect[2], rect[3]].join(','),
44384             });
44385
44386     if (nextPage > maxPages) return;
44387
44388     var id = tile.id + ',' + String(nextPage);
44389     if (cache.loaded[id] || cache.inflight[id]) return;
44390     cache.inflight[id] = request(nextURL)
44391         .mimeType('application/json')
44392         .response(function(xhr) {
44393             var linkHeader = xhr.getResponseHeader('Link');
44394             if (linkHeader) {
44395                 var pagination = parsePagination(xhr.getResponseHeader('Link'));
44396                 if (pagination.next) {
44397                     cache.nextURL[tile.id] = pagination.next;
44398                 }
44399             }
44400
44401             return JSON.parse(xhr.responseText); })
44402         .get(function(err, data) {
44403             cache.loaded[id] = true;
44404             delete cache.inflight[id];
44405             if (err || !data.features || !data.features.length) return;
44406
44407             var features = [],
44408                 feature, loc, d;
44409
44410             for (var i = 0; i < data.features.length; i++) {
44411                 feature = data.features[i];
44412                 loc = feature.geometry.coordinates;
44413                 d = { key: feature.properties.key, loc: loc };
44414                 if (which === 'images') d = { ca: feature.properties.ca, key: feature.properties.key, loc: loc };
44415                 if (which === 'signs') d = { key: feature.properties.detections[0].image_key, loc: loc, value: feature.properties.value };
44416
44417                 features.push({minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1], data: d});
44418             }
44419
44420             cache.rtree.load(features);
44421
44422             if (which === 'images') dispatch$2.call('loadedImages');
44423             if (which === 'signs') dispatch$2.call('loadedSigns');
44424             if (data.features.length === maxResults) {  // more pages to load
44425                 cache.nextPage[tile.id] = nextPage + 1;
44426                 loadNextTilePage(which, currZoom, url, tile);
44427             } else {
44428                 cache.nextPage[tile.id] = Infinity;     // no more pages to load
44429             }
44430         });
44431 }
44432
44433 // extract links to pages of API results
44434 function parsePagination(links) {
44435     return links.split(',').map(function(rel) {
44436         var elements = rel.split(';');
44437         if (elements.length === 2) {
44438             return [
44439                 /<(.+)>/.exec(elements[0])[1],
44440                 /rel="(.+)"/.exec(elements[1])[1]
44441                 ];
44442         } else {
44443             return ['',''];
44444         }
44445     }).reduce(function(pagination, val) {
44446         pagination[val[1]] = val[0];
44447         return pagination;
44448     }, {});
44449 }
44450
44451
44452 // partition viewport into `psize` x `psize` regions
44453 function partitionViewport(psize, projection$$1) {
44454     var dimensions = projection$$1.clipExtent()[1];
44455     psize = psize || 16;
44456     var cols = sequence(0, dimensions[0], psize),
44457         rows = sequence(0, dimensions[1], psize),
44458         partitions = [];
44459
44460     rows.forEach(function(y) {
44461         cols.forEach(function(x) {
44462             var min$$1 = [x, y + psize],
44463                 max$$1 = [x + psize, y];
44464             partitions.push(
44465                 geoExtent$$1(projection$$1.invert(min$$1), projection$$1.invert(max$$1)));
44466         });
44467     });
44468
44469     return partitions;
44470 }
44471
44472
44473 // no more than `limit` results per partition.
44474 function searchLimited(psize, limit, projection$$1, rtree) {
44475     limit = limit || 3;
44476
44477     var partitions = partitionViewport(psize, projection$$1);
44478     return lodash.flatten(lodash.compact(lodash.map(partitions, function(extent$$1) {
44479         return rtree.search(extent$$1.bbox())
44480             .slice(0, limit)
44481             .map(function(d) { return d.data; });
44482     })));
44483 }
44484
44485
44486
44487 var serviceMapillary = {
44488
44489     init: function() {
44490         if (!mapillaryCache) {
44491             this.reset();
44492         }
44493
44494         this.event = utilRebind(this, dispatch$2, 'on');
44495     },
44496
44497     reset: function() {
44498         var cache = mapillaryCache;
44499
44500         if (cache) {
44501             if (cache.images && cache.images.inflight) {
44502                 lodash.forEach(cache.images.inflight, abortRequest);
44503             }
44504             if (cache.signs && cache.signs.inflight) {
44505                 lodash.forEach(cache.signs.inflight, abortRequest);
44506             }
44507         }
44508
44509         mapillaryCache = {
44510             images: { inflight: {}, loaded: {}, nextPage: {}, nextURL: {}, rtree: index$9() },
44511             signs:  { inflight: {}, loaded: {}, nextPage: {}, nextURL: {}, rtree: index$9() }
44512         };
44513
44514         mapillaryImage = null;
44515         mapillaryClicks = [];
44516     },
44517
44518
44519     images: function(projection$$1) {
44520         var psize = 16, limit = 3;
44521         return searchLimited(psize, limit, projection$$1, mapillaryCache.images.rtree);
44522     },
44523
44524
44525     signs: function(projection$$1) {
44526         var psize = 32, limit = 3;
44527         return searchLimited(psize, limit, projection$$1, mapillaryCache.signs.rtree);
44528     },
44529
44530
44531     signsSupported: function() {
44532         var detected = utilDetect();
44533         if (detected.ie) return false;
44534         if ((detected.browser.toLowerCase() === 'safari') && (parseFloat(detected.version) < 10)) return false;
44535         return true;
44536     },
44537
44538
44539     signHTML: function(d) {
44540         if (!mapillarySignDefs || !mapillarySignSprite) return;
44541         var position = mapillarySignDefs[d.value];
44542         if (!position) return '<div></div>';
44543         var iconStyle = [
44544             'background-image:url(' + mapillarySignSprite + ')',
44545             'background-repeat:no-repeat',
44546             'height:' + position.height + 'px',
44547             'width:' + position.width + 'px',
44548             'background-position-x:-' + position.x + 'px',
44549             'background-position-y:-' + position.y + 'px',
44550         ];
44551
44552         return '<div style="' + iconStyle.join(';') +'"></div>';
44553     },
44554
44555
44556     loadImages: function(projection$$1) {
44557         var url = apibase + 'images?';
44558         loadTiles('images', url, projection$$1);
44559     },
44560
44561
44562     loadSigns: function(context, projection$$1) {
44563         var url = apibase + 'objects?';
44564         loadTiles('signs', url, projection$$1);
44565
44566         // load traffic sign defs
44567         if (!mapillarySignDefs) {
44568             mapillarySignSprite = context.asset('img/traffic-signs/traffic-signs.png');
44569             mapillarySignDefs = {};
44570             json(context.asset('img/traffic-signs/traffic-signs.json'), function(err, data) {
44571                 if (err) return;
44572                 mapillarySignDefs = data;
44573             });
44574         }
44575     },
44576
44577
44578     loadViewer: function(context) {
44579         var that = this;
44580         var wrap = select('#content').selectAll('.mapillary-wrap')
44581             .data([0]);
44582
44583         var enter = wrap.enter()
44584             .append('div')
44585             .attr('class', 'mapillary-wrap')
44586             .classed('al', true)       // 'al'=left,  'ar'=right
44587             .classed('hidden', true);
44588
44589         enter
44590             .append('button')
44591             .attr('class', 'thumb-hide')
44592             .on('click', function () { that.hideViewer(); })
44593             .append('div')
44594             .call(svgIcon('#icon-close'));
44595
44596         enter
44597             .append('div')
44598             .attr('id', 'mly')
44599             .attr('class', 'mly-wrapper')
44600             .classed('active', false);
44601
44602         // load mapillary-viewercss
44603         select('head').selectAll('#mapillary-viewercss')
44604             .data([0])
44605             .enter()
44606             .append('link')
44607             .attr('id', 'mapillary-viewercss')
44608             .attr('rel', 'stylesheet')
44609             .attr('href', context.asset(viewercss));
44610
44611         // load mapillary-viewerjs
44612         select('head').selectAll('#mapillary-viewerjs')
44613             .data([0])
44614             .enter()
44615             .append('script')
44616             .attr('id', 'mapillary-viewerjs')
44617             .attr('src', context.asset(viewerjs));
44618     },
44619
44620
44621     showViewer: function() {
44622         select('#content')
44623             .selectAll('.mapillary-wrap')
44624             .classed('hidden', false)
44625             .selectAll('.mly-wrapper')
44626             .classed('active', true);
44627
44628         return this;
44629     },
44630
44631
44632     hideViewer: function() {
44633         select('#content')
44634             .selectAll('.mapillary-wrap')
44635             .classed('hidden', true)
44636             .selectAll('.mly-wrapper')
44637             .classed('active', false);
44638
44639         selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
44640             .classed('selected', false);
44641
44642         mapillaryImage = null;
44643         return this;
44644     },
44645
44646
44647     parsePagination: parsePagination,
44648
44649
44650     updateViewer: function(imageKey, context) {
44651         if (!imageKey) return;
44652
44653         if (!mapillaryViewer) {
44654             this.initViewer(imageKey, context);
44655         } else {
44656             mapillaryViewer.moveToKey(imageKey);
44657         }
44658
44659         return this;
44660     },
44661
44662
44663     initViewer: function(imageKey, context) {
44664         var that = this;
44665         if (Mapillary && imageKey) {
44666             var opts = {
44667                 baseImageSize: 320,
44668                 component: {
44669                     cover: false,
44670                     keyboard: false
44671                 }
44672             };
44673
44674             mapillaryViewer = new Mapillary.Viewer('mly', clientId, imageKey, opts);
44675             mapillaryViewer.on('nodechanged', nodeChanged);
44676         }
44677
44678         function nodeChanged(node) {
44679             var clicks = mapillaryClicks;
44680             var index = clicks.indexOf(node.key);
44681             if (index > -1) {    // nodechange initiated from clicking on a marker..
44682                 clicks.splice(index, 1);
44683             } else {             // nodechange initiated from the Mapillary viewer controls..
44684                 var loc = node.computedLatLon ? [node.computedLatLon.lon, node.computedLatLon.lat] : [node.latLon.lon, node.latLon.lat];
44685                 context.map().centerEase(loc);
44686                 that.selectedImage(node.key, false);
44687             }
44688         }
44689     },
44690
44691
44692     selectedImage: function(imageKey, fromClick) {
44693         if (!arguments.length) return mapillaryImage;
44694
44695         mapillaryImage = imageKey;
44696         if (fromClick) {
44697             mapillaryClicks.push(imageKey);
44698         }
44699
44700         selectAll('.layer-mapillary-images .viewfield-group, .layer-mapillary-signs .icon-sign')
44701             .classed('selected', function(d) { return d.key === imageKey; });
44702
44703         return this;
44704     },
44705
44706
44707     cache: function(_) {
44708         if (!arguments.length) return mapillaryCache;
44709         mapillaryCache = _;
44710         return this;
44711     },
44712
44713
44714     signDefs: function(_) {
44715         if (!arguments.length) return mapillarySignDefs;
44716         mapillarySignDefs = _;
44717         return this;
44718     }
44719
44720 };
44721
44722 var apibase$1 = 'https://nominatim.openstreetmap.org/';
44723 var inflight = {};
44724 var nominatimCache;
44725
44726
44727 var serviceNominatim = {
44728
44729     init: function() {
44730         inflight = {};
44731         nominatimCache = index$9();
44732     },
44733
44734     reset: function() {
44735         lodash.forEach(inflight, function(req) { req.abort(); });
44736         inflight = {};
44737         nominatimCache = index$9();
44738     },
44739
44740
44741     countryCode: function (location, callback) {
44742         var countryCodes = nominatimCache.search(
44743             { minX: location[0], minY: location[1], maxX: location[0], maxY: location[1] }
44744         );
44745
44746         if (countryCodes.length > 0) {
44747             return callback(null, countryCodes[0].data);
44748         }
44749
44750         var params = { format: 'json', addressdetails: 1, lat: location[1], lon: location[0] };
44751         var url = apibase$1 + 'reverse?' + utilQsString(params);
44752         if (inflight[url]) return;
44753
44754         inflight[url] = json(url, function(err, result) {
44755             delete inflight[url];
44756
44757             if (err)
44758                 return callback(err);
44759             else if (result && result.error)
44760                 return callback(result.error);
44761
44762             var extent$$1 = geoExtent$$1(location).padByMeters(1000);
44763             nominatimCache.insert(lodash.assign(extent$$1.bbox(),
44764                 { data: result.address.country_code }
44765             ));
44766
44767             callback(null, result.address.country_code);
44768         });
44769     },
44770
44771
44772     search: function (val, callback) {
44773         var searchVal = encodeURIComponent(val);
44774         var url = apibase$1 + 'search/' + searchVal + '?limit=10&format=json';
44775         if (inflight[url]) return;
44776
44777         inflight[url] = json(url, function(err, result) {
44778             delete inflight[url];
44779             callback(err, result);
44780         });
44781     }
44782
44783 };
44784
44785 var hashes = createCommonjsModule(function (module, exports) {
44786 /**
44787  * jshashes - https://github.com/h2non/jshashes
44788  * Released under the "New BSD" license
44789  *
44790  * Algorithms specification:
44791  *
44792  * MD5 - http://www.ietf.org/rfc/rfc1321.txt
44793  * RIPEMD-160 - http://homes.esat.kuleuven.be/~bosselae/ripemd160.html
44794  * SHA1   - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
44795  * SHA256 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
44796  * SHA512 - http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
44797  * HMAC - http://www.ietf.org/rfc/rfc2104.txt
44798  */
44799 (function() {
44800   var Hashes;
44801
44802   function utf8Encode(str) {
44803     var x, y, output = '',
44804       i = -1,
44805       l;
44806
44807     if (str && str.length) {
44808       l = str.length;
44809       while ((i += 1) < l) {
44810         /* Decode utf-16 surrogate pairs */
44811         x = str.charCodeAt(i);
44812         y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
44813         if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
44814           x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
44815           i += 1;
44816         }
44817         /* Encode output as utf-8 */
44818         if (x <= 0x7F) {
44819           output += String.fromCharCode(x);
44820         } else if (x <= 0x7FF) {
44821           output += String.fromCharCode(0xC0 | ((x >>> 6) & 0x1F),
44822             0x80 | (x & 0x3F));
44823         } else if (x <= 0xFFFF) {
44824           output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
44825             0x80 | ((x >>> 6) & 0x3F),
44826             0x80 | (x & 0x3F));
44827         } else if (x <= 0x1FFFFF) {
44828           output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
44829             0x80 | ((x >>> 12) & 0x3F),
44830             0x80 | ((x >>> 6) & 0x3F),
44831             0x80 | (x & 0x3F));
44832         }
44833       }
44834     }
44835     return output;
44836   }
44837
44838   function utf8Decode(str) {
44839     var i, ac, c1, c2, c3, arr = [],
44840       l;
44841     i = ac = c1 = c2 = c3 = 0;
44842
44843     if (str && str.length) {
44844       l = str.length;
44845       str += '';
44846
44847       while (i < l) {
44848         c1 = str.charCodeAt(i);
44849         ac += 1;
44850         if (c1 < 128) {
44851           arr[ac] = String.fromCharCode(c1);
44852           i += 1;
44853         } else if (c1 > 191 && c1 < 224) {
44854           c2 = str.charCodeAt(i + 1);
44855           arr[ac] = String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
44856           i += 2;
44857         } else {
44858           c2 = str.charCodeAt(i + 1);
44859           c3 = str.charCodeAt(i + 2);
44860           arr[ac] = String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
44861           i += 3;
44862         }
44863       }
44864     }
44865     return arr.join('');
44866   }
44867
44868   /**
44869    * Add integers, wrapping at 2^32. This uses 16-bit operations internally
44870    * to work around bugs in some JS interpreters.
44871    */
44872
44873   function safe_add(x, y) {
44874     var lsw = (x & 0xFFFF) + (y & 0xFFFF),
44875       msw = (x >> 16) + (y >> 16) + (lsw >> 16);
44876     return (msw << 16) | (lsw & 0xFFFF);
44877   }
44878
44879   /**
44880    * Bitwise rotate a 32-bit number to the left.
44881    */
44882
44883   function bit_rol(num, cnt) {
44884     return (num << cnt) | (num >>> (32 - cnt));
44885   }
44886
44887   /**
44888    * Convert a raw string to a hex string
44889    */
44890
44891   function rstr2hex(input, hexcase) {
44892     var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
44893       output = '',
44894       x, i = 0,
44895       l = input.length;
44896     for (; i < l; i += 1) {
44897       x = input.charCodeAt(i);
44898       output += hex_tab.charAt((x >>> 4) & 0x0F) + hex_tab.charAt(x & 0x0F);
44899     }
44900     return output;
44901   }
44902
44903   /**
44904    * Encode a string as utf-16
44905    */
44906
44907   function binb2rstr(input) {
44908     var i, l = input.length * 32,
44909       output = '';
44910     for (i = 0; i < l; i += 8) {
44911       output += String.fromCharCode((input[i >> 5] >>> (24 - i % 32)) & 0xFF);
44912     }
44913     return output;
44914   }
44915
44916   /**
44917    * Convert an array of little-endian words to a string
44918    */
44919
44920   function binl2rstr(input) {
44921     var i, l = input.length * 32,
44922       output = '';
44923     for (i = 0; i < l; i += 8) {
44924       output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
44925     }
44926     return output;
44927   }
44928
44929   /**
44930    * Convert a raw string to an array of little-endian words
44931    * Characters >255 have their high-byte silently ignored.
44932    */
44933
44934   function rstr2binl(input) {
44935     var i, l = input.length * 8,
44936       output = Array(input.length >> 2),
44937       lo = output.length;
44938     for (i = 0; i < lo; i += 1) {
44939       output[i] = 0;
44940     }
44941     for (i = 0; i < l; i += 8) {
44942       output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (i % 32);
44943     }
44944     return output;
44945   }
44946
44947   /**
44948    * Convert a raw string to an array of big-endian words
44949    * Characters >255 have their high-byte silently ignored.
44950    */
44951
44952   function rstr2binb(input) {
44953     var i, l = input.length * 8,
44954       output = Array(input.length >> 2),
44955       lo = output.length;
44956     for (i = 0; i < lo; i += 1) {
44957       output[i] = 0;
44958     }
44959     for (i = 0; i < l; i += 8) {
44960       output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << (24 - i % 32);
44961     }
44962     return output;
44963   }
44964
44965   /**
44966    * Convert a raw string to an arbitrary string encoding
44967    */
44968
44969   function rstr2any(input, encoding) {
44970     var divisor = encoding.length,
44971       remainders = Array(),
44972       i, q, x, ld, quotient, dividend, output, full_length;
44973
44974     /* Convert to an array of 16-bit big-endian values, forming the dividend */
44975     dividend = Array(Math.ceil(input.length / 2));
44976     ld = dividend.length;
44977     for (i = 0; i < ld; i += 1) {
44978       dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
44979     }
44980
44981     /**
44982      * Repeatedly perform a long division. The binary array forms the dividend,
44983      * the length of the encoding is the divisor. Once computed, the quotient
44984      * forms the dividend for the next step. We stop when the dividend is zerHashes.
44985      * All remainders are stored for later use.
44986      */
44987     while (dividend.length > 0) {
44988       quotient = Array();
44989       x = 0;
44990       for (i = 0; i < dividend.length; i += 1) {
44991         x = (x << 16) + dividend[i];
44992         q = Math.floor(x / divisor);
44993         x -= q * divisor;
44994         if (quotient.length > 0 || q > 0) {
44995           quotient[quotient.length] = q;
44996         }
44997       }
44998       remainders[remainders.length] = x;
44999       dividend = quotient;
45000     }
45001
45002     /* Convert the remainders to the output string */
45003     output = '';
45004     for (i = remainders.length - 1; i >= 0; i--) {
45005       output += encoding.charAt(remainders[i]);
45006     }
45007
45008     /* Append leading zero equivalents */
45009     full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
45010     for (i = output.length; i < full_length; i += 1) {
45011       output = encoding[0] + output;
45012     }
45013     return output;
45014   }
45015
45016   /**
45017    * Convert a raw string to a base-64 string
45018    */
45019
45020   function rstr2b64(input, b64pad) {
45021     var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
45022       output = '',
45023       len = input.length,
45024       i, j, triplet;
45025     b64pad = b64pad || '=';
45026     for (i = 0; i < len; i += 3) {
45027       triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
45028       for (j = 0; j < 4; j += 1) {
45029         if (i * 8 + j * 6 > input.length * 8) {
45030           output += b64pad;
45031         } else {
45032           output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
45033         }
45034       }
45035     }
45036     return output;
45037   }
45038
45039   Hashes = {
45040     /**
45041      * @property {String} version
45042      * @readonly
45043      */
45044     VERSION: '1.0.6',
45045     /**
45046      * @member Hashes
45047      * @class Base64
45048      * @constructor
45049      */
45050     Base64: function() {
45051       // private properties
45052       var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
45053         pad = '=', // default pad according with the RFC standard
45054         url = false, // URL encoding support @todo
45055         utf8 = true; // by default enable UTF-8 support encoding
45056
45057       // public method for encoding
45058       this.encode = function(input) {
45059         var i, j, triplet,
45060           output = '',
45061           len = input.length;
45062
45063         pad = pad || '=';
45064         input = (utf8) ? utf8Encode(input) : input;
45065
45066         for (i = 0; i < len; i += 3) {
45067           triplet = (input.charCodeAt(i) << 16) | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
45068           for (j = 0; j < 4; j += 1) {
45069             if (i * 8 + j * 6 > len * 8) {
45070               output += pad;
45071             } else {
45072               output += tab.charAt((triplet >>> 6 * (3 - j)) & 0x3F);
45073             }
45074           }
45075         }
45076         return output;
45077       };
45078
45079       // public method for decoding
45080       this.decode = function(input) {
45081         // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
45082         var i, o1, o2, o3, h1, h2, h3, h4, bits, ac,
45083           dec = '',
45084           arr = [];
45085         if (!input) {
45086           return input;
45087         }
45088
45089         i = ac = 0;
45090         input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '='
45091         //input += '';
45092
45093         do { // unpack four hexets into three octets using index points in b64
45094           h1 = tab.indexOf(input.charAt(i += 1));
45095           h2 = tab.indexOf(input.charAt(i += 1));
45096           h3 = tab.indexOf(input.charAt(i += 1));
45097           h4 = tab.indexOf(input.charAt(i += 1));
45098
45099           bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
45100
45101           o1 = bits >> 16 & 0xff;
45102           o2 = bits >> 8 & 0xff;
45103           o3 = bits & 0xff;
45104           ac += 1;
45105
45106           if (h3 === 64) {
45107             arr[ac] = String.fromCharCode(o1);
45108           } else if (h4 === 64) {
45109             arr[ac] = String.fromCharCode(o1, o2);
45110           } else {
45111             arr[ac] = String.fromCharCode(o1, o2, o3);
45112           }
45113         } while (i < input.length);
45114
45115         dec = arr.join('');
45116         dec = (utf8) ? utf8Decode(dec) : dec;
45117
45118         return dec;
45119       };
45120
45121       // set custom pad string
45122       this.setPad = function(str) {
45123         pad = str || pad;
45124         return this;
45125       };
45126       // set custom tab string characters
45127       this.setTab = function(str) {
45128         tab = str || tab;
45129         return this;
45130       };
45131       this.setUTF8 = function(bool) {
45132         if (typeof bool === 'boolean') {
45133           utf8 = bool;
45134         }
45135         return this;
45136       };
45137     },
45138
45139     /**
45140      * CRC-32 calculation
45141      * @member Hashes
45142      * @method CRC32
45143      * @static
45144      * @param {String} str Input String
45145      * @return {String}
45146      */
45147     CRC32: function(str) {
45148       var crc = 0,
45149         x = 0,
45150         y = 0,
45151         table, i, iTop;
45152       str = utf8Encode(str);
45153
45154       table = [
45155         '00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ',
45156         '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ',
45157         '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ',
45158         '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ',
45159         'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ',
45160         '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ',
45161         'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ',
45162         '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ',
45163         'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ',
45164         '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ',
45165         'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ',
45166         '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ',
45167         'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ',
45168         '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ',
45169         '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ',
45170         '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ',
45171         '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ',
45172         'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ',
45173         '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ',
45174         'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ',
45175         '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ',
45176         'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ',
45177         '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ',
45178         'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ',
45179         '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ',
45180         'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'
45181       ].join('');
45182
45183       crc = crc ^ (-1);
45184       for (i = 0, iTop = str.length; i < iTop; i += 1) {
45185         y = (crc ^ str.charCodeAt(i)) & 0xFF;
45186         x = '0x' + table.substr(y * 9, 8);
45187         crc = (crc >>> 8) ^ x;
45188       }
45189       // always return a positive number (that's what >>> 0 does)
45190       return (crc ^ (-1)) >>> 0;
45191     },
45192     /**
45193      * @member Hashes
45194      * @class MD5
45195      * @constructor
45196      * @param {Object} [config]
45197      *
45198      * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
45199      * Digest Algorithm, as defined in RFC 1321.
45200      * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
45201      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45202      * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
45203      */
45204     MD5: function(options) {
45205       /**
45206        * Private config properties. You may need to tweak these to be compatible with
45207        * the server-side, but the defaults work in most cases.
45208        * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
45209        */
45210       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
45211         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
45212         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
45213
45214       // privileged (public) methods
45215       this.hex = function(s) {
45216         return rstr2hex(rstr(s, utf8), hexcase);
45217       };
45218       this.b64 = function(s) {
45219         return rstr2b64(rstr(s), b64pad);
45220       };
45221       this.any = function(s, e) {
45222         return rstr2any(rstr(s, utf8), e);
45223       };
45224       this.raw = function(s) {
45225         return rstr(s, utf8);
45226       };
45227       this.hex_hmac = function(k, d) {
45228         return rstr2hex(rstr_hmac(k, d), hexcase);
45229       };
45230       this.b64_hmac = function(k, d) {
45231         return rstr2b64(rstr_hmac(k, d), b64pad);
45232       };
45233       this.any_hmac = function(k, d, e) {
45234         return rstr2any(rstr_hmac(k, d), e);
45235       };
45236       /**
45237        * Perform a simple self-test to see if the VM is working
45238        * @return {String} Hexadecimal hash sample
45239        */
45240       this.vm_test = function() {
45241         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45242       };
45243       /**
45244        * Enable/disable uppercase hexadecimal returned string
45245        * @param {Boolean}
45246        * @return {Object} this
45247        */
45248       this.setUpperCase = function(a) {
45249         if (typeof a === 'boolean') {
45250           hexcase = a;
45251         }
45252         return this;
45253       };
45254       /**
45255        * Defines a base64 pad string
45256        * @param {String} Pad
45257        * @return {Object} this
45258        */
45259       this.setPad = function(a) {
45260         b64pad = a || b64pad;
45261         return this;
45262       };
45263       /**
45264        * Defines a base64 pad string
45265        * @param {Boolean}
45266        * @return {Object} [this]
45267        */
45268       this.setUTF8 = function(a) {
45269         if (typeof a === 'boolean') {
45270           utf8 = a;
45271         }
45272         return this;
45273       };
45274
45275       // private methods
45276
45277       /**
45278        * Calculate the MD5 of a raw string
45279        */
45280
45281       function rstr(s) {
45282         s = (utf8) ? utf8Encode(s) : s;
45283         return binl2rstr(binl(rstr2binl(s), s.length * 8));
45284       }
45285
45286       /**
45287        * Calculate the HMAC-MD5, of a key and some data (raw strings)
45288        */
45289
45290       function rstr_hmac(key, data) {
45291         var bkey, ipad, opad, hash, i;
45292
45293         key = (utf8) ? utf8Encode(key) : key;
45294         data = (utf8) ? utf8Encode(data) : data;
45295         bkey = rstr2binl(key);
45296         if (bkey.length > 16) {
45297           bkey = binl(bkey, key.length * 8);
45298         }
45299
45300         ipad = Array(16), opad = Array(16);
45301         for (i = 0; i < 16; i += 1) {
45302           ipad[i] = bkey[i] ^ 0x36363636;
45303           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45304         }
45305         hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
45306         return binl2rstr(binl(opad.concat(hash), 512 + 128));
45307       }
45308
45309       /**
45310        * Calculate the MD5 of an array of little-endian words, and a bit length.
45311        */
45312
45313       function binl(x, len) {
45314         var i, olda, oldb, oldc, oldd,
45315           a = 1732584193,
45316           b = -271733879,
45317           c = -1732584194,
45318           d = 271733878;
45319
45320         /* append padding */
45321         x[len >> 5] |= 0x80 << ((len) % 32);
45322         x[(((len + 64) >>> 9) << 4) + 14] = len;
45323
45324         for (i = 0; i < x.length; i += 16) {
45325           olda = a;
45326           oldb = b;
45327           oldc = c;
45328           oldd = d;
45329
45330           a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
45331           d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
45332           c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
45333           b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
45334           a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
45335           d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
45336           c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
45337           b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
45338           a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
45339           d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
45340           c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
45341           b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
45342           a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
45343           d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
45344           c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
45345           b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
45346
45347           a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
45348           d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
45349           c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
45350           b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
45351           a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
45352           d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
45353           c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
45354           b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
45355           a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
45356           d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
45357           c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
45358           b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
45359           a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
45360           d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
45361           c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
45362           b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
45363
45364           a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
45365           d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
45366           c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
45367           b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
45368           a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
45369           d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
45370           c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
45371           b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
45372           a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
45373           d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
45374           c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
45375           b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
45376           a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
45377           d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
45378           c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
45379           b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
45380
45381           a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
45382           d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
45383           c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
45384           b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
45385           a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
45386           d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
45387           c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
45388           b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
45389           a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
45390           d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
45391           c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
45392           b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
45393           a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
45394           d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
45395           c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
45396           b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
45397
45398           a = safe_add(a, olda);
45399           b = safe_add(b, oldb);
45400           c = safe_add(c, oldc);
45401           d = safe_add(d, oldd);
45402         }
45403         return Array(a, b, c, d);
45404       }
45405
45406       /**
45407        * These functions implement the four basic operations the algorithm uses.
45408        */
45409
45410       function md5_cmn(q, a, b, x, s, t) {
45411         return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
45412       }
45413
45414       function md5_ff(a, b, c, d, x, s, t) {
45415         return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
45416       }
45417
45418       function md5_gg(a, b, c, d, x, s, t) {
45419         return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
45420       }
45421
45422       function md5_hh(a, b, c, d, x, s, t) {
45423         return md5_cmn(b ^ c ^ d, a, b, x, s, t);
45424       }
45425
45426       function md5_ii(a, b, c, d, x, s, t) {
45427         return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
45428       }
45429     },
45430     /**
45431      * @member Hashes
45432      * @class Hashes.SHA1
45433      * @param {Object} [config]
45434      * @constructor
45435      *
45436      * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
45437      * Version 2.2 Copyright Paul Johnston 2000 - 2009.
45438      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45439      * See http://pajhome.org.uk/crypt/md5 for details.
45440      */
45441     SHA1: function(options) {
45442       /**
45443        * Private config properties. You may need to tweak these to be compatible with
45444        * the server-side, but the defaults work in most cases.
45445        * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
45446        */
45447       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase
45448         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=', // base-64 pad character. Defaults to '=' for strict RFC compliance
45449         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true; // enable/disable utf8 encoding
45450
45451       // public methods
45452       this.hex = function(s) {
45453         return rstr2hex(rstr(s, utf8), hexcase);
45454       };
45455       this.b64 = function(s) {
45456         return rstr2b64(rstr(s, utf8), b64pad);
45457       };
45458       this.any = function(s, e) {
45459         return rstr2any(rstr(s, utf8), e);
45460       };
45461       this.raw = function(s) {
45462         return rstr(s, utf8);
45463       };
45464       this.hex_hmac = function(k, d) {
45465         return rstr2hex(rstr_hmac(k, d));
45466       };
45467       this.b64_hmac = function(k, d) {
45468         return rstr2b64(rstr_hmac(k, d), b64pad);
45469       };
45470       this.any_hmac = function(k, d, e) {
45471         return rstr2any(rstr_hmac(k, d), e);
45472       };
45473       /**
45474        * Perform a simple self-test to see if the VM is working
45475        * @return {String} Hexadecimal hash sample
45476        * @public
45477        */
45478       this.vm_test = function() {
45479         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45480       };
45481       /**
45482        * @description Enable/disable uppercase hexadecimal returned string
45483        * @param {boolean}
45484        * @return {Object} this
45485        * @public
45486        */
45487       this.setUpperCase = function(a) {
45488         if (typeof a === 'boolean') {
45489           hexcase = a;
45490         }
45491         return this;
45492       };
45493       /**
45494        * @description Defines a base64 pad string
45495        * @param {string} Pad
45496        * @return {Object} this
45497        * @public
45498        */
45499       this.setPad = function(a) {
45500         b64pad = a || b64pad;
45501         return this;
45502       };
45503       /**
45504        * @description Defines a base64 pad string
45505        * @param {boolean}
45506        * @return {Object} this
45507        * @public
45508        */
45509       this.setUTF8 = function(a) {
45510         if (typeof a === 'boolean') {
45511           utf8 = a;
45512         }
45513         return this;
45514       };
45515
45516       // private methods
45517
45518       /**
45519        * Calculate the SHA-512 of a raw string
45520        */
45521
45522       function rstr(s) {
45523         s = (utf8) ? utf8Encode(s) : s;
45524         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45525       }
45526
45527       /**
45528        * Calculate the HMAC-SHA1 of a key and some data (raw strings)
45529        */
45530
45531       function rstr_hmac(key, data) {
45532         var bkey, ipad, opad, i, hash;
45533         key = (utf8) ? utf8Encode(key) : key;
45534         data = (utf8) ? utf8Encode(data) : data;
45535         bkey = rstr2binb(key);
45536
45537         if (bkey.length > 16) {
45538           bkey = binb(bkey, key.length * 8);
45539         }
45540         ipad = Array(16), opad = Array(16);
45541         for (i = 0; i < 16; i += 1) {
45542           ipad[i] = bkey[i] ^ 0x36363636;
45543           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45544         }
45545         hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
45546         return binb2rstr(binb(opad.concat(hash), 512 + 160));
45547       }
45548
45549       /**
45550        * Calculate the SHA-1 of an array of big-endian words, and a bit length
45551        */
45552
45553       function binb(x, len) {
45554         var i, j, t, olda, oldb, oldc, oldd, olde,
45555           w = Array(80),
45556           a = 1732584193,
45557           b = -271733879,
45558           c = -1732584194,
45559           d = 271733878,
45560           e = -1009589776;
45561
45562         /* append padding */
45563         x[len >> 5] |= 0x80 << (24 - len % 32);
45564         x[((len + 64 >> 9) << 4) + 15] = len;
45565
45566         for (i = 0; i < x.length; i += 16) {
45567           olda = a,
45568           oldb = b;
45569           oldc = c;
45570           oldd = d;
45571           olde = e;
45572
45573           for (j = 0; j < 80; j += 1) {
45574             if (j < 16) {
45575               w[j] = x[i + j];
45576             } else {
45577               w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
45578             }
45579             t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)),
45580               safe_add(safe_add(e, w[j]), sha1_kt(j)));
45581             e = d;
45582             d = c;
45583             c = bit_rol(b, 30);
45584             b = a;
45585             a = t;
45586           }
45587
45588           a = safe_add(a, olda);
45589           b = safe_add(b, oldb);
45590           c = safe_add(c, oldc);
45591           d = safe_add(d, oldd);
45592           e = safe_add(e, olde);
45593         }
45594         return Array(a, b, c, d, e);
45595       }
45596
45597       /**
45598        * Perform the appropriate triplet combination function for the current
45599        * iteration
45600        */
45601
45602       function sha1_ft(t, b, c, d) {
45603         if (t < 20) {
45604           return (b & c) | ((~b) & d);
45605         }
45606         if (t < 40) {
45607           return b ^ c ^ d;
45608         }
45609         if (t < 60) {
45610           return (b & c) | (b & d) | (c & d);
45611         }
45612         return b ^ c ^ d;
45613       }
45614
45615       /**
45616        * Determine the appropriate additive constant for the current iteration
45617        */
45618
45619       function sha1_kt(t) {
45620         return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
45621           (t < 60) ? -1894007588 : -899497514;
45622       }
45623     },
45624     /**
45625      * @class Hashes.SHA256
45626      * @param {config}
45627      *
45628      * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
45629      * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
45630      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45631      * See http://pajhome.org.uk/crypt/md5 for details.
45632      * Also http://anmar.eu.org/projects/jssha2/
45633      */
45634     SHA256: function(options) {
45635       /**
45636        * Private properties configuration variables. You may need to tweak these to be compatible with
45637        * the server-side, but the defaults work in most cases.
45638        * @see this.setUpperCase() method
45639        * @see this.setPad() method
45640        */
45641       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false, // hexadecimal output case format. false - lowercase; true - uppercase  */
45642         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=',
45643         /* base-64 pad character. Default '=' for strict RFC compliance   */
45644         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
45645         /* enable/disable utf8 encoding */
45646         sha256_K;
45647
45648       /* privileged (public) methods */
45649       this.hex = function(s) {
45650         return rstr2hex(rstr(s, utf8));
45651       };
45652       this.b64 = function(s) {
45653         return rstr2b64(rstr(s, utf8), b64pad);
45654       };
45655       this.any = function(s, e) {
45656         return rstr2any(rstr(s, utf8), e);
45657       };
45658       this.raw = function(s) {
45659         return rstr(s, utf8);
45660       };
45661       this.hex_hmac = function(k, d) {
45662         return rstr2hex(rstr_hmac(k, d));
45663       };
45664       this.b64_hmac = function(k, d) {
45665         return rstr2b64(rstr_hmac(k, d), b64pad);
45666       };
45667       this.any_hmac = function(k, d, e) {
45668         return rstr2any(rstr_hmac(k, d), e);
45669       };
45670       /**
45671        * Perform a simple self-test to see if the VM is working
45672        * @return {String} Hexadecimal hash sample
45673        * @public
45674        */
45675       this.vm_test = function() {
45676         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45677       };
45678       /**
45679        * Enable/disable uppercase hexadecimal returned string
45680        * @param {boolean}
45681        * @return {Object} this
45682        * @public
45683        */
45684       this.setUpperCase = function(a) {
45685         if (typeof a === 'boolean') {
45686           hexcase = a;
45687         }
45688         return this;
45689       };
45690       /**
45691        * @description Defines a base64 pad string
45692        * @param {string} Pad
45693        * @return {Object} this
45694        * @public
45695        */
45696       this.setPad = function(a) {
45697         b64pad = a || b64pad;
45698         return this;
45699       };
45700       /**
45701        * Defines a base64 pad string
45702        * @param {boolean}
45703        * @return {Object} this
45704        * @public
45705        */
45706       this.setUTF8 = function(a) {
45707         if (typeof a === 'boolean') {
45708           utf8 = a;
45709         }
45710         return this;
45711       };
45712
45713       // private methods
45714
45715       /**
45716        * Calculate the SHA-512 of a raw string
45717        */
45718
45719       function rstr(s, utf8) {
45720         s = (utf8) ? utf8Encode(s) : s;
45721         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45722       }
45723
45724       /**
45725        * Calculate the HMAC-sha256 of a key and some data (raw strings)
45726        */
45727
45728       function rstr_hmac(key, data) {
45729         key = (utf8) ? utf8Encode(key) : key;
45730         data = (utf8) ? utf8Encode(data) : data;
45731         var hash, i = 0,
45732           bkey = rstr2binb(key),
45733           ipad = Array(16),
45734           opad = Array(16);
45735
45736         if (bkey.length > 16) {
45737           bkey = binb(bkey, key.length * 8);
45738         }
45739
45740         for (; i < 16; i += 1) {
45741           ipad[i] = bkey[i] ^ 0x36363636;
45742           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45743         }
45744
45745         hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
45746         return binb2rstr(binb(opad.concat(hash), 512 + 256));
45747       }
45748
45749       /*
45750        * Main sha256 function, with its support functions
45751        */
45752
45753       function sha256_S(X, n) {
45754         return (X >>> n) | (X << (32 - n));
45755       }
45756
45757       function sha256_R(X, n) {
45758         return (X >>> n);
45759       }
45760
45761       function sha256_Ch(x, y, z) {
45762         return ((x & y) ^ ((~x) & z));
45763       }
45764
45765       function sha256_Maj(x, y, z) {
45766         return ((x & y) ^ (x & z) ^ (y & z));
45767       }
45768
45769       function sha256_Sigma0256(x) {
45770         return (sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22));
45771       }
45772
45773       function sha256_Sigma1256(x) {
45774         return (sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25));
45775       }
45776
45777       function sha256_Gamma0256(x) {
45778         return (sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3));
45779       }
45780
45781       function sha256_Gamma1256(x) {
45782         return (sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10));
45783       }
45784
45785       sha256_K = [
45786         1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987,
45787         1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522,
45788         264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585,
45789         113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291,
45790         1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344,
45791         430227734, 506948616, 659060556, 883997877, 958139571, 1322822218,
45792         1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998
45793       ];
45794
45795       function binb(m, l) {
45796         var HASH = [1779033703, -1150833019, 1013904242, -1521486534,
45797           1359893119, -1694144372, 528734635, 1541459225
45798         ];
45799         var W = new Array(64);
45800         var a, b, c, d, e, f, g, h;
45801         var i, j, T1, T2;
45802
45803         /* append padding */
45804         m[l >> 5] |= 0x80 << (24 - l % 32);
45805         m[((l + 64 >> 9) << 4) + 15] = l;
45806
45807         for (i = 0; i < m.length; i += 16) {
45808           a = HASH[0];
45809           b = HASH[1];
45810           c = HASH[2];
45811           d = HASH[3];
45812           e = HASH[4];
45813           f = HASH[5];
45814           g = HASH[6];
45815           h = HASH[7];
45816
45817           for (j = 0; j < 64; j += 1) {
45818             if (j < 16) {
45819               W[j] = m[j + i];
45820             } else {
45821               W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]),
45822                 sha256_Gamma0256(W[j - 15])), W[j - 16]);
45823             }
45824
45825             T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)),
45826               sha256_K[j]), W[j]);
45827             T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
45828             h = g;
45829             g = f;
45830             f = e;
45831             e = safe_add(d, T1);
45832             d = c;
45833             c = b;
45834             b = a;
45835             a = safe_add(T1, T2);
45836           }
45837
45838           HASH[0] = safe_add(a, HASH[0]);
45839           HASH[1] = safe_add(b, HASH[1]);
45840           HASH[2] = safe_add(c, HASH[2]);
45841           HASH[3] = safe_add(d, HASH[3]);
45842           HASH[4] = safe_add(e, HASH[4]);
45843           HASH[5] = safe_add(f, HASH[5]);
45844           HASH[6] = safe_add(g, HASH[6]);
45845           HASH[7] = safe_add(h, HASH[7]);
45846         }
45847         return HASH;
45848       }
45849
45850     },
45851
45852     /**
45853      * @class Hashes.SHA512
45854      * @param {config}
45855      *
45856      * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
45857      * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
45858      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
45859      * See http://pajhome.org.uk/crypt/md5 for details.
45860      */
45861     SHA512: function(options) {
45862       /**
45863        * Private properties configuration variables. You may need to tweak these to be compatible with
45864        * the server-side, but the defaults work in most cases.
45865        * @see this.setUpperCase() method
45866        * @see this.setPad() method
45867        */
45868       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false,
45869         /* hexadecimal output case format. false - lowercase; true - uppercase  */
45870         b64pad = (options && typeof options.pad === 'string') ? options.pad : '=',
45871         /* base-64 pad character. Default '=' for strict RFC compliance   */
45872         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
45873         /* enable/disable utf8 encoding */
45874         sha512_k;
45875
45876       /* privileged (public) methods */
45877       this.hex = function(s) {
45878         return rstr2hex(rstr(s));
45879       };
45880       this.b64 = function(s) {
45881         return rstr2b64(rstr(s), b64pad);
45882       };
45883       this.any = function(s, e) {
45884         return rstr2any(rstr(s), e);
45885       };
45886       this.raw = function(s) {
45887         return rstr(s, utf8);
45888       };
45889       this.hex_hmac = function(k, d) {
45890         return rstr2hex(rstr_hmac(k, d));
45891       };
45892       this.b64_hmac = function(k, d) {
45893         return rstr2b64(rstr_hmac(k, d), b64pad);
45894       };
45895       this.any_hmac = function(k, d, e) {
45896         return rstr2any(rstr_hmac(k, d), e);
45897       };
45898       /**
45899        * Perform a simple self-test to see if the VM is working
45900        * @return {String} Hexadecimal hash sample
45901        * @public
45902        */
45903       this.vm_test = function() {
45904         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
45905       };
45906       /**
45907        * @description Enable/disable uppercase hexadecimal returned string
45908        * @param {boolean}
45909        * @return {Object} this
45910        * @public
45911        */
45912       this.setUpperCase = function(a) {
45913         if (typeof a === 'boolean') {
45914           hexcase = a;
45915         }
45916         return this;
45917       };
45918       /**
45919        * @description Defines a base64 pad string
45920        * @param {string} Pad
45921        * @return {Object} this
45922        * @public
45923        */
45924       this.setPad = function(a) {
45925         b64pad = a || b64pad;
45926         return this;
45927       };
45928       /**
45929        * @description Defines a base64 pad string
45930        * @param {boolean}
45931        * @return {Object} this
45932        * @public
45933        */
45934       this.setUTF8 = function(a) {
45935         if (typeof a === 'boolean') {
45936           utf8 = a;
45937         }
45938         return this;
45939       };
45940
45941       /* private methods */
45942
45943       /**
45944        * Calculate the SHA-512 of a raw string
45945        */
45946
45947       function rstr(s) {
45948         s = (utf8) ? utf8Encode(s) : s;
45949         return binb2rstr(binb(rstr2binb(s), s.length * 8));
45950       }
45951       /*
45952        * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
45953        */
45954
45955       function rstr_hmac(key, data) {
45956         key = (utf8) ? utf8Encode(key) : key;
45957         data = (utf8) ? utf8Encode(data) : data;
45958
45959         var hash, i = 0,
45960           bkey = rstr2binb(key),
45961           ipad = Array(32),
45962           opad = Array(32);
45963
45964         if (bkey.length > 32) {
45965           bkey = binb(bkey, key.length * 8);
45966         }
45967
45968         for (; i < 32; i += 1) {
45969           ipad[i] = bkey[i] ^ 0x36363636;
45970           opad[i] = bkey[i] ^ 0x5C5C5C5C;
45971         }
45972
45973         hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
45974         return binb2rstr(binb(opad.concat(hash), 1024 + 512));
45975       }
45976
45977       /**
45978        * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
45979        */
45980
45981       function binb(x, len) {
45982         var j, i, l,
45983           W = new Array(80),
45984           hash = new Array(16),
45985           //Initial hash values
45986           H = [
45987             new int64(0x6a09e667, -205731576),
45988             new int64(-1150833019, -2067093701),
45989             new int64(0x3c6ef372, -23791573),
45990             new int64(-1521486534, 0x5f1d36f1),
45991             new int64(0x510e527f, -1377402159),
45992             new int64(-1694144372, 0x2b3e6c1f),
45993             new int64(0x1f83d9ab, -79577749),
45994             new int64(0x5be0cd19, 0x137e2179)
45995           ],
45996           T1 = new int64(0, 0),
45997           T2 = new int64(0, 0),
45998           a = new int64(0, 0),
45999           b = new int64(0, 0),
46000           c = new int64(0, 0),
46001           d = new int64(0, 0),
46002           e = new int64(0, 0),
46003           f = new int64(0, 0),
46004           g = new int64(0, 0),
46005           h = new int64(0, 0),
46006           //Temporary variables not specified by the document
46007           s0 = new int64(0, 0),
46008           s1 = new int64(0, 0),
46009           Ch = new int64(0, 0),
46010           Maj = new int64(0, 0),
46011           r1 = new int64(0, 0),
46012           r2 = new int64(0, 0),
46013           r3 = new int64(0, 0);
46014
46015         if (sha512_k === undefined) {
46016           //SHA512 constants
46017           sha512_k = [
46018             new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd),
46019             new int64(-1245643825, -330482897), new int64(-373957723, -2121671748),
46020             new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031),
46021             new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736),
46022             new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe),
46023             new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302),
46024             new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1),
46025             new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428),
46026             new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3),
46027             new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65),
46028             new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483),
46029             new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459),
46030             new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210),
46031             new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340),
46032             new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395),
46033             new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70),
46034             new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926),
46035             new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473),
46036             new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8),
46037             new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b),
46038             new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023),
46039             new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30),
46040             new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910),
46041             new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8),
46042             new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53),
46043             new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016),
46044             new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893),
46045             new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397),
46046             new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60),
46047             new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec),
46048             new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047),
46049             new int64(-1090935817, -1295615723), new int64(-965641998, -479046869),
46050             new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207),
46051             new int64(-354779690, -840897762), new int64(-176337025, -294727304),
46052             new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026),
46053             new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b),
46054             new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493),
46055             new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620),
46056             new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430),
46057             new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)
46058           ];
46059         }
46060
46061         for (i = 0; i < 80; i += 1) {
46062           W[i] = new int64(0, 0);
46063         }
46064
46065         // append padding to the source string. The format is described in the FIPS.
46066         x[len >> 5] |= 0x80 << (24 - (len & 0x1f));
46067         x[((len + 128 >> 10) << 5) + 31] = len;
46068         l = x.length;
46069         for (i = 0; i < l; i += 32) { //32 dwords is the block size
46070           int64copy(a, H[0]);
46071           int64copy(b, H[1]);
46072           int64copy(c, H[2]);
46073           int64copy(d, H[3]);
46074           int64copy(e, H[4]);
46075           int64copy(f, H[5]);
46076           int64copy(g, H[6]);
46077           int64copy(h, H[7]);
46078
46079           for (j = 0; j < 16; j += 1) {
46080             W[j].h = x[i + 2 * j];
46081             W[j].l = x[i + 2 * j + 1];
46082           }
46083
46084           for (j = 16; j < 80; j += 1) {
46085             //sigma1
46086             int64rrot(r1, W[j - 2], 19);
46087             int64revrrot(r2, W[j - 2], 29);
46088             int64shr(r3, W[j - 2], 6);
46089             s1.l = r1.l ^ r2.l ^ r3.l;
46090             s1.h = r1.h ^ r2.h ^ r3.h;
46091             //sigma0
46092             int64rrot(r1, W[j - 15], 1);
46093             int64rrot(r2, W[j - 15], 8);
46094             int64shr(r3, W[j - 15], 7);
46095             s0.l = r1.l ^ r2.l ^ r3.l;
46096             s0.h = r1.h ^ r2.h ^ r3.h;
46097
46098             int64add4(W[j], s1, W[j - 7], s0, W[j - 16]);
46099           }
46100
46101           for (j = 0; j < 80; j += 1) {
46102             //Ch
46103             Ch.l = (e.l & f.l) ^ (~e.l & g.l);
46104             Ch.h = (e.h & f.h) ^ (~e.h & g.h);
46105
46106             //Sigma1
46107             int64rrot(r1, e, 14);
46108             int64rrot(r2, e, 18);
46109             int64revrrot(r3, e, 9);
46110             s1.l = r1.l ^ r2.l ^ r3.l;
46111             s1.h = r1.h ^ r2.h ^ r3.h;
46112
46113             //Sigma0
46114             int64rrot(r1, a, 28);
46115             int64revrrot(r2, a, 2);
46116             int64revrrot(r3, a, 7);
46117             s0.l = r1.l ^ r2.l ^ r3.l;
46118             s0.h = r1.h ^ r2.h ^ r3.h;
46119
46120             //Maj
46121             Maj.l = (a.l & b.l) ^ (a.l & c.l) ^ (b.l & c.l);
46122             Maj.h = (a.h & b.h) ^ (a.h & c.h) ^ (b.h & c.h);
46123
46124             int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
46125             int64add(T2, s0, Maj);
46126
46127             int64copy(h, g);
46128             int64copy(g, f);
46129             int64copy(f, e);
46130             int64add(e, d, T1);
46131             int64copy(d, c);
46132             int64copy(c, b);
46133             int64copy(b, a);
46134             int64add(a, T1, T2);
46135           }
46136           int64add(H[0], H[0], a);
46137           int64add(H[1], H[1], b);
46138           int64add(H[2], H[2], c);
46139           int64add(H[3], H[3], d);
46140           int64add(H[4], H[4], e);
46141           int64add(H[5], H[5], f);
46142           int64add(H[6], H[6], g);
46143           int64add(H[7], H[7], h);
46144         }
46145
46146         //represent the hash as an array of 32-bit dwords
46147         for (i = 0; i < 8; i += 1) {
46148           hash[2 * i] = H[i].h;
46149           hash[2 * i + 1] = H[i].l;
46150         }
46151         return hash;
46152       }
46153
46154       //A constructor for 64-bit numbers
46155
46156       function int64(h, l) {
46157         this.h = h;
46158         this.l = l;
46159         //this.toString = int64toString;
46160       }
46161
46162       //Copies src into dst, assuming both are 64-bit numbers
46163
46164       function int64copy(dst, src) {
46165         dst.h = src.h;
46166         dst.l = src.l;
46167       }
46168
46169       //Right-rotates a 64-bit number by shift
46170       //Won't handle cases of shift>=32
46171       //The function revrrot() is for that
46172
46173       function int64rrot(dst, x, shift) {
46174         dst.l = (x.l >>> shift) | (x.h << (32 - shift));
46175         dst.h = (x.h >>> shift) | (x.l << (32 - shift));
46176       }
46177
46178       //Reverses the dwords of the source and then rotates right by shift.
46179       //This is equivalent to rotation by 32+shift
46180
46181       function int64revrrot(dst, x, shift) {
46182         dst.l = (x.h >>> shift) | (x.l << (32 - shift));
46183         dst.h = (x.l >>> shift) | (x.h << (32 - shift));
46184       }
46185
46186       //Bitwise-shifts right a 64-bit number by shift
46187       //Won't handle shift>=32, but it's never needed in SHA512
46188
46189       function int64shr(dst, x, shift) {
46190         dst.l = (x.l >>> shift) | (x.h << (32 - shift));
46191         dst.h = (x.h >>> shift);
46192       }
46193
46194       //Adds two 64-bit numbers
46195       //Like the original implementation, does not rely on 32-bit operations
46196
46197       function int64add(dst, x, y) {
46198         var w0 = (x.l & 0xffff) + (y.l & 0xffff);
46199         var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
46200         var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
46201         var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
46202         dst.l = (w0 & 0xffff) | (w1 << 16);
46203         dst.h = (w2 & 0xffff) | (w3 << 16);
46204       }
46205
46206       //Same, except with 4 addends. Works faster than adding them one by one.
46207
46208       function int64add4(dst, a, b, c, d) {
46209         var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
46210         var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
46211         var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
46212         var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
46213         dst.l = (w0 & 0xffff) | (w1 << 16);
46214         dst.h = (w2 & 0xffff) | (w3 << 16);
46215       }
46216
46217       //Same, except with 5 addends
46218
46219       function int64add5(dst, a, b, c, d, e) {
46220         var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
46221           w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
46222           w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
46223           w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
46224         dst.l = (w0 & 0xffff) | (w1 << 16);
46225         dst.h = (w2 & 0xffff) | (w3 << 16);
46226       }
46227     },
46228     /**
46229      * @class Hashes.RMD160
46230      * @constructor
46231      * @param {Object} [config]
46232      *
46233      * A JavaScript implementation of the RIPEMD-160 Algorithm
46234      * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
46235      * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
46236      * See http://pajhome.org.uk/crypt/md5 for details.
46237      * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
46238      */
46239     RMD160: function(options) {
46240       /**
46241        * Private properties configuration variables. You may need to tweak these to be compatible with
46242        * the server-side, but the defaults work in most cases.
46243        * @see this.setUpperCase() method
46244        * @see this.setPad() method
46245        */
46246       var hexcase = (options && typeof options.uppercase === 'boolean') ? options.uppercase : false,
46247         /* hexadecimal output case format. false - lowercase; true - uppercase  */
46248         b64pad = (options && typeof options.pad === 'string') ? options.pa : '=',
46249         /* base-64 pad character. Default '=' for strict RFC compliance   */
46250         utf8 = (options && typeof options.utf8 === 'boolean') ? options.utf8 : true,
46251         /* enable/disable utf8 encoding */
46252         rmd160_r1 = [
46253           0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
46254           7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
46255           3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
46256           1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
46257           4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
46258         ],
46259         rmd160_r2 = [
46260           5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
46261           6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
46262           15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
46263           8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
46264           12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
46265         ],
46266         rmd160_s1 = [
46267           11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
46268           7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
46269           11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
46270           11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
46271           9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
46272         ],
46273         rmd160_s2 = [
46274           8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
46275           9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
46276           9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
46277           15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
46278           8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
46279         ];
46280
46281       /* privileged (public) methods */
46282       this.hex = function(s) {
46283         return rstr2hex(rstr(s, utf8));
46284       };
46285       this.b64 = function(s) {
46286         return rstr2b64(rstr(s, utf8), b64pad);
46287       };
46288       this.any = function(s, e) {
46289         return rstr2any(rstr(s, utf8), e);
46290       };
46291       this.raw = function(s) {
46292         return rstr(s, utf8);
46293       };
46294       this.hex_hmac = function(k, d) {
46295         return rstr2hex(rstr_hmac(k, d));
46296       };
46297       this.b64_hmac = function(k, d) {
46298         return rstr2b64(rstr_hmac(k, d), b64pad);
46299       };
46300       this.any_hmac = function(k, d, e) {
46301         return rstr2any(rstr_hmac(k, d), e);
46302       };
46303       /**
46304        * Perform a simple self-test to see if the VM is working
46305        * @return {String} Hexadecimal hash sample
46306        * @public
46307        */
46308       this.vm_test = function() {
46309         return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
46310       };
46311       /**
46312        * @description Enable/disable uppercase hexadecimal returned string
46313        * @param {boolean}
46314        * @return {Object} this
46315        * @public
46316        */
46317       this.setUpperCase = function(a) {
46318         if (typeof a === 'boolean') {
46319           hexcase = a;
46320         }
46321         return this;
46322       };
46323       /**
46324        * @description Defines a base64 pad string
46325        * @param {string} Pad
46326        * @return {Object} this
46327        * @public
46328        */
46329       this.setPad = function(a) {
46330         if (typeof a !== 'undefined') {
46331           b64pad = a;
46332         }
46333         return this;
46334       };
46335       /**
46336        * @description Defines a base64 pad string
46337        * @param {boolean}
46338        * @return {Object} this
46339        * @public
46340        */
46341       this.setUTF8 = function(a) {
46342         if (typeof a === 'boolean') {
46343           utf8 = a;
46344         }
46345         return this;
46346       };
46347
46348       /* private methods */
46349
46350       /**
46351        * Calculate the rmd160 of a raw string
46352        */
46353
46354       function rstr(s) {
46355         s = (utf8) ? utf8Encode(s) : s;
46356         return binl2rstr(binl(rstr2binl(s), s.length * 8));
46357       }
46358
46359       /**
46360        * Calculate the HMAC-rmd160 of a key and some data (raw strings)
46361        */
46362
46363       function rstr_hmac(key, data) {
46364         key = (utf8) ? utf8Encode(key) : key;
46365         data = (utf8) ? utf8Encode(data) : data;
46366         var i, hash,
46367           bkey = rstr2binl(key),
46368           ipad = Array(16),
46369           opad = Array(16);
46370
46371         if (bkey.length > 16) {
46372           bkey = binl(bkey, key.length * 8);
46373         }
46374
46375         for (i = 0; i < 16; i += 1) {
46376           ipad[i] = bkey[i] ^ 0x36363636;
46377           opad[i] = bkey[i] ^ 0x5C5C5C5C;
46378         }
46379         hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
46380         return binl2rstr(binl(opad.concat(hash), 512 + 160));
46381       }
46382
46383       /**
46384        * Convert an array of little-endian words to a string
46385        */
46386
46387       function binl2rstr(input) {
46388         var i, output = '',
46389           l = input.length * 32;
46390         for (i = 0; i < l; i += 8) {
46391           output += String.fromCharCode((input[i >> 5] >>> (i % 32)) & 0xFF);
46392         }
46393         return output;
46394       }
46395
46396       /**
46397        * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
46398        */
46399
46400       function binl(x, len) {
46401         var T, j, i, l,
46402           h0 = 0x67452301,
46403           h1 = 0xefcdab89,
46404           h2 = 0x98badcfe,
46405           h3 = 0x10325476,
46406           h4 = 0xc3d2e1f0,
46407           A1, B1, C1, D1, E1,
46408           A2, B2, C2, D2, E2;
46409
46410         /* append padding */
46411         x[len >> 5] |= 0x80 << (len % 32);
46412         x[(((len + 64) >>> 9) << 4) + 14] = len;
46413         l = x.length;
46414
46415         for (i = 0; i < l; i += 16) {
46416           A1 = A2 = h0;
46417           B1 = B2 = h1;
46418           C1 = C2 = h2;
46419           D1 = D2 = h3;
46420           E1 = E2 = h4;
46421           for (j = 0; j <= 79; j += 1) {
46422             T = safe_add(A1, rmd160_f(j, B1, C1, D1));
46423             T = safe_add(T, x[i + rmd160_r1[j]]);
46424             T = safe_add(T, rmd160_K1(j));
46425             T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
46426             A1 = E1;
46427             E1 = D1;
46428             D1 = bit_rol(C1, 10);
46429             C1 = B1;
46430             B1 = T;
46431             T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
46432             T = safe_add(T, x[i + rmd160_r2[j]]);
46433             T = safe_add(T, rmd160_K2(j));
46434             T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
46435             A2 = E2;
46436             E2 = D2;
46437             D2 = bit_rol(C2, 10);
46438             C2 = B2;
46439             B2 = T;
46440           }
46441
46442           T = safe_add(h1, safe_add(C1, D2));
46443           h1 = safe_add(h2, safe_add(D1, E2));
46444           h2 = safe_add(h3, safe_add(E1, A2));
46445           h3 = safe_add(h4, safe_add(A1, B2));
46446           h4 = safe_add(h0, safe_add(B1, C2));
46447           h0 = T;
46448         }
46449         return [h0, h1, h2, h3, h4];
46450       }
46451
46452       // specific algorithm methods
46453
46454       function rmd160_f(j, x, y, z) {
46455         return (0 <= j && j <= 15) ? (x ^ y ^ z) :
46456           (16 <= j && j <= 31) ? (x & y) | (~x & z) :
46457           (32 <= j && j <= 47) ? (x | ~y) ^ z :
46458           (48 <= j && j <= 63) ? (x & z) | (y & ~z) :
46459           (64 <= j && j <= 79) ? x ^ (y | ~z) :
46460           'rmd160_f: j out of range';
46461       }
46462
46463       function rmd160_K1(j) {
46464         return (0 <= j && j <= 15) ? 0x00000000 :
46465           (16 <= j && j <= 31) ? 0x5a827999 :
46466           (32 <= j && j <= 47) ? 0x6ed9eba1 :
46467           (48 <= j && j <= 63) ? 0x8f1bbcdc :
46468           (64 <= j && j <= 79) ? 0xa953fd4e :
46469           'rmd160_K1: j out of range';
46470       }
46471
46472       function rmd160_K2(j) {
46473         return (0 <= j && j <= 15) ? 0x50a28be6 :
46474           (16 <= j && j <= 31) ? 0x5c4dd124 :
46475           (32 <= j && j <= 47) ? 0x6d703ef3 :
46476           (48 <= j && j <= 63) ? 0x7a6d76e9 :
46477           (64 <= j && j <= 79) ? 0x00000000 :
46478           'rmd160_K2: j out of range';
46479       }
46480     }
46481   };
46482
46483   // exposes Hashes
46484   (function(window, undefined) {
46485     var freeExports = false;
46486     {
46487       freeExports = exports;
46488       if (exports && typeof commonjsGlobal === 'object' && commonjsGlobal && commonjsGlobal === commonjsGlobal.global) {
46489         window = commonjsGlobal;
46490       }
46491     }
46492
46493     if (typeof undefined === 'function' && typeof undefined.amd === 'object' && undefined.amd) {
46494       // define as an anonymous module, so, through path mapping, it can be aliased
46495       undefined(function() {
46496         return Hashes;
46497       });
46498     } else if (freeExports) {
46499       // in Node.js or RingoJS v0.8.0+
46500       if ('object' === 'object' && module && module.exports === freeExports) {
46501         module.exports = Hashes;
46502       }
46503       // in Narwhal or RingoJS v0.7.0-
46504       else {
46505         freeExports.Hashes = Hashes;
46506       }
46507     } else {
46508       // in a browser or Rhino
46509       window.Hashes = Hashes;
46510     }
46511   }(this));
46512 }()); // IIFE
46513 });
46514
46515 var immutable = extend$2;
46516
46517 var hasOwnProperty = Object.prototype.hasOwnProperty;
46518
46519 function extend$2() {
46520     var target = {};
46521
46522     for (var i = 0; i < arguments.length; i++) {
46523         var source = arguments[i];
46524
46525         for (var key in source) {
46526             if (hasOwnProperty.call(source, key)) {
46527                 target[key] = source[key];
46528             }
46529         }
46530     }
46531
46532     return target
46533 }
46534
46535 var sha1 = new hashes.SHA1();
46536
46537 var ohauth = {};
46538
46539 ohauth.qsString = function(obj) {
46540     return Object.keys(obj).sort().map(function(key) {
46541         return ohauth.percentEncode(key) + '=' +
46542             ohauth.percentEncode(obj[key]);
46543     }).join('&');
46544 };
46545
46546 ohauth.stringQs = function(str) {
46547     return str.split('&').filter(function (pair) {
46548         return pair !== '';
46549     }).reduce(function(obj, pair){
46550         var parts = pair.split('=');
46551         obj[decodeURIComponent(parts[0])] = (null === parts[1]) ?
46552             '' : decodeURIComponent(parts[1]);
46553         return obj;
46554     }, {});
46555 };
46556
46557 ohauth.rawxhr = function(method, url, data, headers, callback) {
46558     var xhr = new XMLHttpRequest(),
46559         twoHundred = /^20\d$/;
46560     xhr.onreadystatechange = function() {
46561         if (4 === xhr.readyState && 0 !== xhr.status) {
46562             if (twoHundred.test(xhr.status)) callback(null, xhr);
46563             else return callback(xhr, null);
46564         }
46565     };
46566     xhr.onerror = function(e) { return callback(e, null); };
46567     xhr.open(method, url, true);
46568     for (var h in headers) xhr.setRequestHeader(h, headers[h]);
46569     xhr.send(data);
46570     return xhr;
46571 };
46572
46573 ohauth.xhr = function(method, url, auth, data, options, callback) {
46574     var headers = (options && options.header) || {
46575         'Content-Type': 'application/x-www-form-urlencoded'
46576     };
46577     headers.Authorization = 'OAuth ' + ohauth.authHeader(auth);
46578     return ohauth.rawxhr(method, url, data, headers, callback);
46579 };
46580
46581 ohauth.nonce = function() {
46582     for (var o = ''; o.length < 6;) {
46583         o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
46584     }
46585     return o;
46586 };
46587
46588 ohauth.authHeader = function(obj) {
46589     return Object.keys(obj).sort().map(function(key) {
46590         return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
46591     }).join(', ');
46592 };
46593
46594 ohauth.timestamp = function() { return ~~((+new Date()) / 1000); };
46595
46596 ohauth.percentEncode = function(s) {
46597     return encodeURIComponent(s)
46598         .replace(/\!/g, '%21').replace(/\'/g, '%27')
46599         .replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
46600 };
46601
46602 ohauth.baseString = function(method, url, params) {
46603     if (params.oauth_signature) delete params.oauth_signature;
46604     return [
46605         method,
46606         ohauth.percentEncode(url),
46607         ohauth.percentEncode(ohauth.qsString(params))].join('&');
46608 };
46609
46610 ohauth.signature = function(oauth_secret, token_secret, baseString) {
46611     return sha1.b64_hmac(
46612         ohauth.percentEncode(oauth_secret) + '&' +
46613         ohauth.percentEncode(token_secret),
46614         baseString);
46615 };
46616
46617 /**
46618  * Takes an options object for configuration (consumer_key,
46619  * consumer_secret, version, signature_method, token, token_secret)
46620  * and returns a function that generates the Authorization header
46621  * for given data.
46622  *
46623  * The returned function takes these parameters:
46624  * - method: GET/POST/...
46625  * - uri: full URI with protocol, port, path and query string
46626  * - extra_params: any extra parameters (that are passed in the POST data),
46627  *   can be an object or a from-urlencoded string.
46628  *
46629  * Returned function returns full OAuth header with "OAuth" string in it.
46630  */
46631
46632 ohauth.headerGenerator = function(options) {
46633     options = options || {};
46634     var consumer_key = options.consumer_key || '',
46635         consumer_secret = options.consumer_secret || '',
46636         signature_method = options.signature_method || 'HMAC-SHA1',
46637         version = options.version || '1.0',
46638         token = options.token || '',
46639         token_secret = options.token_secret || '';
46640
46641     return function(method, uri, extra_params) {
46642         method = method.toUpperCase();
46643         if (typeof extra_params === 'string' && extra_params.length > 0) {
46644             extra_params = ohauth.stringQs(extra_params);
46645         }
46646
46647         var uri_parts = uri.split('?', 2),
46648         base_uri = uri_parts[0];
46649
46650         var query_params = uri_parts.length === 2 ?
46651             ohauth.stringQs(uri_parts[1]) : {};
46652
46653         var oauth_params = {
46654             oauth_consumer_key: consumer_key,
46655             oauth_signature_method: signature_method,
46656             oauth_version: version,
46657             oauth_timestamp: ohauth.timestamp(),
46658             oauth_nonce: ohauth.nonce()
46659         };
46660
46661         if (token) oauth_params.oauth_token = token;
46662
46663         var all_params = immutable({}, oauth_params, query_params, extra_params),
46664             base_str = ohauth.baseString(method, base_uri, all_params);
46665
46666         oauth_params.oauth_signature = ohauth.signature(consumer_secret, token_secret, base_str);
46667
46668         return 'OAuth ' + ohauth.authHeader(oauth_params);
46669     };
46670 };
46671
46672 var index$13 = ohauth;
46673
46674 var store = createCommonjsModule(function (module, exports) {
46675 "use strict"
46676 // Module export pattern from
46677 // https://github.com/umdjs/umd/blob/master/returnExports.js
46678 ;(function (root, factory) {
46679     if (typeof undefined === 'function' && undefined.amd) {
46680         // AMD. Register as an anonymous module.
46681         undefined([], factory);
46682     } else {
46683         // Node. Does not work with strict CommonJS, but
46684         // only CommonJS-like environments that support module.exports,
46685         // like Node.
46686         module.exports = factory();
46687     }
46688 }(commonjsGlobal, function () {
46689         
46690         // Store.js
46691         var store = {},
46692                 win = (typeof window != 'undefined' ? window : commonjsGlobal),
46693                 doc = win.document,
46694                 localStorageName = 'localStorage',
46695                 scriptTag = 'script',
46696                 storage;
46697
46698         store.disabled = false;
46699         store.version = '1.3.20';
46700         store.set = function(key, value) {};
46701         store.get = function(key, defaultVal) {};
46702         store.has = function(key) { return store.get(key) !== undefined };
46703         store.remove = function(key) {};
46704         store.clear = function() {};
46705         store.transact = function(key, defaultVal, transactionFn) {
46706                 if (transactionFn == null) {
46707                         transactionFn = defaultVal;
46708                         defaultVal = null;
46709                 }
46710                 if (defaultVal == null) {
46711                         defaultVal = {};
46712                 }
46713                 var val = store.get(key, defaultVal);
46714                 transactionFn(val);
46715                 store.set(key, val);
46716         };
46717         store.getAll = function() {};
46718         store.forEach = function() {};
46719
46720         store.serialize = function(value) {
46721                 return JSON.stringify(value)
46722         };
46723         store.deserialize = function(value) {
46724                 if (typeof value != 'string') { return undefined }
46725                 try { return JSON.parse(value) }
46726                 catch(e) { return value || undefined }
46727         };
46728
46729         // Functions to encapsulate questionable FireFox 3.6.13 behavior
46730         // when about.config::dom.storage.enabled === false
46731         // See https://github.com/marcuswestin/store.js/issues#issue/13
46732         function isLocalStorageNameSupported() {
46733                 try { return (localStorageName in win && win[localStorageName]) }
46734                 catch(err) { return false }
46735         }
46736
46737         if (isLocalStorageNameSupported()) {
46738                 storage = win[localStorageName];
46739                 store.set = function(key, val) {
46740                         if (val === undefined) { return store.remove(key) }
46741                         storage.setItem(key, store.serialize(val));
46742                         return val
46743                 };
46744                 store.get = function(key, defaultVal) {
46745                         var val = store.deserialize(storage.getItem(key));
46746                         return (val === undefined ? defaultVal : val)
46747                 };
46748                 store.remove = function(key) { storage.removeItem(key); };
46749                 store.clear = function() { storage.clear(); };
46750                 store.getAll = function() {
46751                         var ret = {};
46752                         store.forEach(function(key, val) {
46753                                 ret[key] = val;
46754                         });
46755                         return ret
46756                 };
46757                 store.forEach = function(callback) {
46758                         for (var i=0; i<storage.length; i++) {
46759                                 var key = storage.key(i);
46760                                 callback(key, store.get(key));
46761                         }
46762                 };
46763         } else if (doc && doc.documentElement.addBehavior) {
46764                 var storageOwner,
46765                         storageContainer;
46766                 // Since #userData storage applies only to specific paths, we need to
46767                 // somehow link our data to a specific path.  We choose /favicon.ico
46768                 // as a pretty safe option, since all browsers already make a request to
46769                 // this URL anyway and being a 404 will not hurt us here.  We wrap an
46770                 // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
46771                 // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
46772                 // since the iframe access rules appear to allow direct access and
46773                 // manipulation of the document element, even for a 404 page.  This
46774                 // document can be used instead of the current document (which would
46775                 // have been limited to the current path) to perform #userData storage.
46776                 try {
46777                         storageContainer = new ActiveXObject('htmlfile');
46778                         storageContainer.open();
46779                         storageContainer.write('<'+scriptTag+'>document.w=window</'+scriptTag+'><iframe src="/favicon.ico"></iframe>');
46780                         storageContainer.close();
46781                         storageOwner = storageContainer.w.frames[0].document;
46782                         storage = storageOwner.createElement('div');
46783                 } catch(e) {
46784                         // somehow ActiveXObject instantiation failed (perhaps some special
46785                         // security settings or otherwse), fall back to per-path storage
46786                         storage = doc.createElement('div');
46787                         storageOwner = doc.body;
46788                 }
46789                 var withIEStorage = function(storeFunction) {
46790                         return function() {
46791                                 var args = Array.prototype.slice.call(arguments, 0);
46792                                 args.unshift(storage);
46793                                 // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
46794                                 // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
46795                                 storageOwner.appendChild(storage);
46796                                 storage.addBehavior('#default#userData');
46797                                 storage.load(localStorageName);
46798                                 var result = storeFunction.apply(store, args);
46799                                 storageOwner.removeChild(storage);
46800                                 return result
46801                         }
46802                 };
46803
46804                 // In IE7, keys cannot start with a digit or contain certain chars.
46805                 // See https://github.com/marcuswestin/store.js/issues/40
46806                 // See https://github.com/marcuswestin/store.js/issues/83
46807                 var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
46808                 var ieKeyFix = function(key) {
46809                         return key.replace(/^d/, '___$&').replace(forbiddenCharsRegex, '___')
46810                 };
46811                 store.set = withIEStorage(function(storage, key, val) {
46812                         key = ieKeyFix(key);
46813                         if (val === undefined) { return store.remove(key) }
46814                         storage.setAttribute(key, store.serialize(val));
46815                         storage.save(localStorageName);
46816                         return val
46817                 });
46818                 store.get = withIEStorage(function(storage, key, defaultVal) {
46819                         key = ieKeyFix(key);
46820                         var val = store.deserialize(storage.getAttribute(key));
46821                         return (val === undefined ? defaultVal : val)
46822                 });
46823                 store.remove = withIEStorage(function(storage, key) {
46824                         key = ieKeyFix(key);
46825                         storage.removeAttribute(key);
46826                         storage.save(localStorageName);
46827                 });
46828                 store.clear = withIEStorage(function(storage) {
46829                         var attributes = storage.XMLDocument.documentElement.attributes;
46830                         storage.load(localStorageName);
46831                         for (var i=attributes.length-1; i>=0; i--) {
46832                                 storage.removeAttribute(attributes[i].name);
46833                         }
46834                         storage.save(localStorageName);
46835                 });
46836                 store.getAll = function(storage) {
46837                         var ret = {};
46838                         store.forEach(function(key, val) {
46839                                 ret[key] = val;
46840                         });
46841                         return ret
46842                 };
46843                 store.forEach = withIEStorage(function(storage, callback) {
46844                         var attributes = storage.XMLDocument.documentElement.attributes;
46845                         for (var i=0, attr; attr=attributes[i]; ++i) {
46846                                 callback(attr.name, store.deserialize(storage.getAttribute(attr.name)));
46847                         }
46848                 });
46849         }
46850
46851         try {
46852                 var testKey = '__storejs__';
46853                 store.set(testKey, testKey);
46854                 if (store.get(testKey) != testKey) { store.disabled = true; }
46855                 store.remove(testKey);
46856         } catch(e) {
46857                 store.disabled = true;
46858         }
46859         store.enabled = !store.disabled;
46860         
46861         return store
46862 }));
46863 });
46864
46865 // # osm-auth
46866 //
46867 // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
46868 // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
46869 // does not support custom headers, which this uses everywhere.
46870 var index$12 = function(o) {
46871
46872     var oauth = {};
46873
46874     // authenticated users will also have a request token secret, but it's
46875     // not used in transactions with the server
46876     oauth.authenticated = function() {
46877         return !!(token('oauth_token') && token('oauth_token_secret'));
46878     };
46879
46880     oauth.logout = function() {
46881         token('oauth_token', '');
46882         token('oauth_token_secret', '');
46883         token('oauth_request_token_secret', '');
46884         return oauth;
46885     };
46886
46887     // TODO: detect lack of click event
46888     oauth.authenticate = function(callback) {
46889         if (oauth.authenticated()) return callback();
46890
46891         oauth.logout();
46892
46893         // ## Getting a request token
46894         var params = timenonce(getAuth(o)),
46895             url = o.url + '/oauth/request_token';
46896
46897         params.oauth_signature = index$13.signature(
46898             o.oauth_secret, '',
46899             index$13.baseString('POST', url, params));
46900
46901         if (!o.singlepage) {
46902             // Create a 600x550 popup window in the center of the screen
46903             var w = 600, h = 550,
46904                 settings = [
46905                     ['width', w], ['height', h],
46906                     ['left', screen.width / 2 - w / 2],
46907                     ['top', screen.height / 2 - h / 2]].map(function(x) {
46908                         return x.join('=');
46909                     }).join(','),
46910                 popup = window.open('about:blank', 'oauth_window', settings);
46911         }
46912
46913         // Request a request token. When this is complete, the popup
46914         // window is redirected to OSM's authorization page.
46915         index$13.xhr('POST', url, params, null, {}, reqTokenDone);
46916         o.loading();
46917
46918         function reqTokenDone(err, xhr) {
46919             o.done();
46920             if (err) return callback(err);
46921             var resp = index$13.stringQs(xhr.response);
46922             token('oauth_request_token_secret', resp.oauth_token_secret);
46923             var authorize_url = o.url + '/oauth/authorize?' + index$13.qsString({
46924                 oauth_token: resp.oauth_token,
46925                 oauth_callback: location.href.replace('index.html', '')
46926                     .replace(/#.*/, '').replace(location.search, '') + o.landing
46927             });
46928
46929             if (o.singlepage) {
46930                 location.href = authorize_url;
46931             } else {
46932                 popup.location = authorize_url;
46933             }
46934         }
46935
46936         // Called by a function in a landing page, in the popup window. The
46937         // window closes itself.
46938         window.authComplete = function(token) {
46939             var oauth_token = index$13.stringQs(token.split('?')[1]);
46940             get_access_token(oauth_token.oauth_token);
46941             delete window.authComplete;
46942         };
46943
46944         // ## Getting an request token
46945         //
46946         // At this point we have an `oauth_token`, brought in from a function
46947         // call on a landing page popup.
46948         function get_access_token(oauth_token) {
46949             var url = o.url + '/oauth/access_token',
46950                 params = timenonce(getAuth(o)),
46951                 request_token_secret = token('oauth_request_token_secret');
46952             params.oauth_token = oauth_token;
46953             params.oauth_signature = index$13.signature(
46954                 o.oauth_secret,
46955                 request_token_secret,
46956                 index$13.baseString('POST', url, params));
46957
46958             // ## Getting an access token
46959             //
46960             // The final token required for authentication. At this point
46961             // we have a `request token secret`
46962             index$13.xhr('POST', url, params, null, {}, accessTokenDone);
46963             o.loading();
46964         }
46965
46966         function accessTokenDone(err, xhr) {
46967             o.done();
46968             if (err) return callback(err);
46969             var access_token = index$13.stringQs(xhr.response);
46970             token('oauth_token', access_token.oauth_token);
46971             token('oauth_token_secret', access_token.oauth_token_secret);
46972             callback(null, oauth);
46973         }
46974     };
46975
46976     oauth.bootstrapToken = function(oauth_token, callback) {
46977         // ## Getting an request token
46978         // At this point we have an `oauth_token`, brought in from a function
46979         // call on a landing page popup.
46980         function get_access_token(oauth_token) {
46981             var url = o.url + '/oauth/access_token',
46982                 params = timenonce(getAuth(o)),
46983                 request_token_secret = token('oauth_request_token_secret');
46984             params.oauth_token = oauth_token;
46985             params.oauth_signature = index$13.signature(
46986                 o.oauth_secret,
46987                 request_token_secret,
46988                 index$13.baseString('POST', url, params));
46989
46990             // ## Getting an access token
46991             // The final token required for authentication. At this point
46992             // we have a `request token secret`
46993             index$13.xhr('POST', url, params, null, {}, accessTokenDone);
46994             o.loading();
46995         }
46996
46997         function accessTokenDone(err, xhr) {
46998             o.done();
46999             if (err) return callback(err);
47000             var access_token = index$13.stringQs(xhr.response);
47001             token('oauth_token', access_token.oauth_token);
47002             token('oauth_token_secret', access_token.oauth_token_secret);
47003             callback(null, oauth);
47004         }
47005
47006         get_access_token(oauth_token);
47007     };
47008
47009     // # xhr
47010     //
47011     // A single XMLHttpRequest wrapper that does authenticated calls if the
47012     // user has logged in.
47013     oauth.xhr = function(options, callback) {
47014         if (!oauth.authenticated()) {
47015             if (o.auto) {
47016                 return oauth.authenticate(run);
47017             } else {
47018                 callback('not authenticated', null);
47019                 return;
47020             }
47021         } else {
47022             return run();
47023         }
47024
47025         function run() {
47026             var params = timenonce(getAuth(o)),
47027                 oauth_token_secret = token('oauth_token_secret'),
47028                 url = (options.prefix !== false) ? o.url + options.path : options.path,
47029                 url_parts = url.replace(/#.*$/, '').split('?', 2),
47030                 base_url = url_parts[0],
47031                 query = (url_parts.length === 2) ? url_parts[1] : '';
47032
47033             // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
47034             if ((!options.options || !options.options.header ||
47035                 options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') &&
47036                 options.content) {
47037                 params = immutable(params, index$13.stringQs(options.content));
47038             }
47039
47040             params.oauth_token = token('oauth_token');
47041             params.oauth_signature = index$13.signature(
47042                 o.oauth_secret,
47043                 oauth_token_secret,
47044                 index$13.baseString(options.method, base_url, immutable(params, index$13.stringQs(query)))
47045             );
47046
47047             return index$13.xhr(options.method, url, params, options.content, options.options, done);
47048         }
47049
47050         function done(err, xhr) {
47051             if (err) return callback(err);
47052             else if (xhr.responseXML) return callback(err, xhr.responseXML);
47053             else return callback(err, xhr.response);
47054         }
47055     };
47056
47057     // pre-authorize this object, if we can just get a token and token_secret
47058     // from the start
47059     oauth.preauth = function(c) {
47060         if (!c) return;
47061         if (c.oauth_token) token('oauth_token', c.oauth_token);
47062         if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
47063         return oauth;
47064     };
47065
47066     oauth.options = function(_) {
47067         if (!arguments.length) return o;
47068
47069         o = _;
47070         o.url = o.url || 'http://www.openstreetmap.org';
47071         o.landing = o.landing || 'land.html';
47072         o.singlepage = o.singlepage || false;
47073
47074         // Optional loading and loading-done functions for nice UI feedback.
47075         // by default, no-ops
47076         o.loading = o.loading || function() {};
47077         o.done = o.done || function() {};
47078
47079         return oauth.preauth(o);
47080     };
47081
47082     // 'stamp' an authentication object from `getAuth()`
47083     // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
47084     // and timestamp
47085     function timenonce(o) {
47086         o.oauth_timestamp = index$13.timestamp();
47087         o.oauth_nonce = index$13.nonce();
47088         return o;
47089     }
47090
47091     // get/set tokens. These are prefixed with the base URL so that `osm-auth`
47092     // can be used with multiple APIs and the keys in `localStorage`
47093     // will not clash
47094     var token;
47095
47096     if (store.enabled) {
47097         token = function (x, y) {
47098             if (arguments.length === 1) return store.get(o.url + x);
47099             else if (arguments.length === 2) return store.set(o.url + x, y);
47100         };
47101     } else {
47102         var storage = {};
47103         token = function (x, y) {
47104             if (arguments.length === 1) return storage[o.url + x];
47105             else if (arguments.length === 2) return storage[o.url + x] = y;
47106         };
47107     }
47108
47109     // Get an authentication object. If you just add and remove properties
47110     // from a single object, you'll need to use `delete` to make sure that
47111     // it doesn't contain undesired properties for authentication
47112     function getAuth(o) {
47113         return {
47114             oauth_consumer_key: o.oauth_consumer_key,
47115             oauth_signature_method: 'HMAC-SHA1'
47116         };
47117     }
47118
47119     // potentially pre-authorize
47120     oauth.options(o);
47121
47122     return oauth;
47123 };
47124
47125 var JXON = new (function () {
47126   var
47127     sValueProp = 'keyValue', sAttributesProp = 'keyAttributes', sAttrPref = '@', /* you can customize these values */
47128     aCache = [], rIsNull = /^\s*$/, rIsBool = /^(?:true|false)$/i;
47129
47130   function parseText (sValue) {
47131     if (rIsNull.test(sValue)) { return null; }
47132     if (rIsBool.test(sValue)) { return sValue.toLowerCase() === 'true'; }
47133     if (isFinite(sValue)) { return parseFloat(sValue); }
47134     if (isFinite(Date.parse(sValue))) { return new Date(sValue); }
47135     return sValue;
47136   }
47137
47138   function EmptyTree () { }
47139   EmptyTree.prototype.toString = function () { return 'null'; };
47140   EmptyTree.prototype.valueOf = function () { return null; };
47141
47142   function objectify (vValue) {
47143     return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
47144   }
47145
47146   function createObjTree (oParentNode, nVerb, bFreeze, bNesteAttr) {
47147     var
47148       nLevelStart = aCache.length, bChildren = oParentNode.hasChildNodes(),
47149       bAttributes = oParentNode.hasAttributes(), bHighVerb = Boolean(nVerb & 2);
47150
47151     var
47152       sProp, vContent, nLength = 0, sCollectedTxt = '',
47153       vResult = bHighVerb ? {} : /* put here the default value for empty nodes: */ true;
47154
47155     if (bChildren) {
47156       for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
47157         oNode = oParentNode.childNodes.item(nItem);
47158         if (oNode.nodeType === 4) { sCollectedTxt += oNode.nodeValue; } /* nodeType is 'CDATASection' (4) */
47159         else if (oNode.nodeType === 3) { sCollectedTxt += oNode.nodeValue.trim(); } /* nodeType is 'Text' (3) */
47160         else if (oNode.nodeType === 1 && !oNode.prefix) { aCache.push(oNode); } /* nodeType is 'Element' (1) */
47161       }
47162     }
47163
47164     var nLevelEnd = aCache.length, vBuiltVal = parseText(sCollectedTxt);
47165
47166     if (!bHighVerb && (bChildren || bAttributes)) { vResult = nVerb === 0 ? objectify(vBuiltVal) : {}; }
47167
47168     for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
47169       sProp = aCache[nElId].nodeName.toLowerCase();
47170       vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
47171       if (vResult.hasOwnProperty(sProp)) {
47172         if (vResult[sProp].constructor !== Array) { vResult[sProp] = [vResult[sProp]]; }
47173         vResult[sProp].push(vContent);
47174       } else {
47175         vResult[sProp] = vContent;
47176         nLength++;
47177       }
47178     }
47179
47180     if (bAttributes) {
47181       var
47182         nAttrLen = oParentNode.attributes.length,
47183         sAPrefix = bNesteAttr ? '' : sAttrPref, oAttrParent = bNesteAttr ? {} : vResult;
47184
47185       for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
47186         oAttrib = oParentNode.attributes.item(nAttrib);
47187         oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
47188       }
47189
47190       if (bNesteAttr) {
47191         if (bFreeze) { Object.freeze(oAttrParent); }
47192         vResult[sAttributesProp] = oAttrParent;
47193         nLength -= nAttrLen - 1;
47194       }
47195     }
47196
47197     if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
47198       vResult[sValueProp] = vBuiltVal;
47199     } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
47200       vResult = vBuiltVal;
47201     }
47202
47203     if (bFreeze && (bHighVerb || nLength > 0)) { Object.freeze(vResult); }
47204
47205     aCache.length = nLevelStart;
47206
47207     return vResult;
47208   }
47209
47210   function loadObjTree (oXMLDoc, oParentEl, oParentObj) {
47211     var vValue, oChild;
47212
47213     if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
47214       oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString())); /* verbosity level is 0 */
47215     } else if (oParentObj.constructor === Date) {
47216       oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));    
47217     }
47218
47219     for (var sName in oParentObj) {
47220       vValue = oParentObj[sName];
47221       if (isFinite(sName) || vValue instanceof Function) { continue; } /* verbosity level is 0 */
47222       if (sName === sValueProp) {
47223         if (vValue !== null && vValue !== true) { oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue))); }
47224       } else if (sName === sAttributesProp) { /* verbosity level is 3 */
47225         for (var sAttrib in vValue) { oParentEl.setAttribute(sAttrib, vValue[sAttrib]); }
47226       } else if (sName.charAt(0) === sAttrPref) {
47227         oParentEl.setAttribute(sName.slice(1), vValue);
47228       } else if (vValue.constructor === Array) {
47229         for (var nItem = 0; nItem < vValue.length; nItem++) {
47230           oChild = oXMLDoc.createElement(sName);
47231           loadObjTree(oXMLDoc, oChild, vValue[nItem]);
47232           oParentEl.appendChild(oChild);
47233         }
47234       } else {
47235         oChild = oXMLDoc.createElement(sName);
47236         if (vValue instanceof Object) {
47237           loadObjTree(oXMLDoc, oChild, vValue);
47238         } else if (vValue !== null && vValue !== true) {
47239           oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
47240         }
47241         oParentEl.appendChild(oChild);
47242      }
47243    }
47244   }
47245
47246   this.build = function (oXMLParent, nVerbosity /* optional */, bFreeze /* optional */, bNesteAttributes /* optional */) {
47247     var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 : /* put here the default verbosity level: */ 1;
47248     return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);    
47249   };
47250
47251   this.unbuild = function (oObjTree) {    
47252     var oNewDoc = document.implementation.createDocument('', '', null);
47253     loadObjTree(oNewDoc, oNewDoc, oObjTree);
47254     return oNewDoc;
47255   };
47256
47257   this.stringify = function (oObjTree) {
47258     return (new XMLSerializer()).serializeToString(JXON.unbuild(oObjTree));
47259   };
47260 })();
47261
47262 // var myObject = JXON.build(doc);
47263 // we got our javascript object! try: alert(JSON.stringify(myObject));
47264
47265 // var newDoc = JXON.unbuild(myObject);
47266 // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
47267
47268 var dispatch$3 = dispatch('authLoading', 'authDone', 'change', 'loading', 'loaded');
47269 var urlroot = 'https://www.openstreetmap.org';
47270 var blacklists = ['.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*'];
47271 var inflight$1 = {};
47272 var loadedTiles = {};
47273 var tileZoom$1 = 16;
47274 var oauth = index$12({
47275         url: urlroot,
47276         oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
47277         oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
47278         loading: authLoading,
47279         done: authDone
47280     });
47281 var rateLimitError;
47282 var userChangesets;
47283 var userDetails;
47284 var off;
47285
47286
47287 function authLoading() {
47288     dispatch$3.call('authLoading');
47289 }
47290
47291
47292 function authDone() {
47293     dispatch$3.call('authDone');
47294 }
47295
47296
47297 function abortRequest$1(i) {
47298     if (i) {
47299         i.abort();
47300     }
47301 }
47302
47303
47304 function getLoc(attrs) {
47305     var lon = attrs.lon && attrs.lon.value,
47306         lat = attrs.lat && attrs.lat.value;
47307     return [parseFloat(lon), parseFloat(lat)];
47308 }
47309
47310
47311 function getNodes(obj) {
47312     var elems = obj.getElementsByTagName('nd'),
47313         nodes = new Array(elems.length);
47314     for (var i = 0, l = elems.length; i < l; i++) {
47315         nodes[i] = 'n' + elems[i].attributes.ref.value;
47316     }
47317     return nodes;
47318 }
47319
47320
47321 function getTags(obj) {
47322     var elems = obj.getElementsByTagName('tag'),
47323         tags = {};
47324     for (var i = 0, l = elems.length; i < l; i++) {
47325         var attrs = elems[i].attributes;
47326         tags[attrs.k.value] = attrs.v.value;
47327     }
47328
47329     return tags;
47330 }
47331
47332
47333 function getMembers(obj) {
47334     var elems = obj.getElementsByTagName('member'),
47335         members = new Array(elems.length);
47336     for (var i = 0, l = elems.length; i < l; i++) {
47337         var attrs = elems[i].attributes;
47338         members[i] = {
47339             id: attrs.type.value[0] + attrs.ref.value,
47340             type: attrs.type.value,
47341             role: attrs.role.value
47342         };
47343     }
47344     return members;
47345 }
47346
47347
47348 function getVisible(attrs) {
47349     return (!attrs.visible || attrs.visible.value !== 'false');
47350 }
47351
47352
47353 var parsers = {
47354     node: function nodeData(obj) {
47355         var attrs = obj.attributes;
47356         return new osmNode({
47357             id: osmEntity$$1.id.fromOSM('node', attrs.id.value),
47358             loc: getLoc(attrs),
47359             version: attrs.version.value,
47360             user: attrs.user && attrs.user.value,
47361             tags: getTags(obj),
47362             visible: getVisible(attrs)
47363         });
47364     },
47365
47366     way: function wayData(obj) {
47367         var attrs = obj.attributes;
47368         return new osmWay({
47369             id: osmEntity$$1.id.fromOSM('way', attrs.id.value),
47370             version: attrs.version.value,
47371             user: attrs.user && attrs.user.value,
47372             tags: getTags(obj),
47373             nodes: getNodes(obj),
47374             visible: getVisible(attrs)
47375         });
47376     },
47377
47378     relation: function relationData(obj) {
47379         var attrs = obj.attributes;
47380         return new osmRelation({
47381             id: osmEntity$$1.id.fromOSM('relation', attrs.id.value),
47382             version: attrs.version.value,
47383             user: attrs.user && attrs.user.value,
47384             tags: getTags(obj),
47385             members: getMembers(obj),
47386             visible: getVisible(attrs)
47387         });
47388     }
47389 };
47390
47391
47392 function parse$1(xml$$1) {
47393     if (!xml$$1 || !xml$$1.childNodes) return;
47394
47395     var root = xml$$1.childNodes[0],
47396         children = root.childNodes,
47397         entities = [];
47398
47399     for (var i = 0, l = children.length; i < l; i++) {
47400         var child = children[i],
47401             parser = parsers[child.nodeName];
47402         if (parser) {
47403             entities.push(parser(child));
47404         }
47405     }
47406
47407     return entities;
47408 }
47409
47410
47411 var serviceOsm = {
47412
47413     init: function() {
47414         utilRebind(this, dispatch$3, 'on');
47415     },
47416
47417
47418     reset: function() {
47419         userChangesets = undefined;
47420         userDetails = undefined;
47421         rateLimitError = undefined;
47422         lodash.forEach(inflight$1, abortRequest$1);
47423         loadedTiles = {};
47424         inflight$1 = {};
47425         return this;
47426     },
47427
47428
47429     changesetURL: function(changesetId) {
47430         return urlroot + '/changeset/' + changesetId;
47431     },
47432
47433
47434     changesetsURL: function(center, zoom$$1) {
47435         var precision = Math.max(0, Math.ceil(Math.log(zoom$$1) / Math.LN2));
47436         return urlroot + '/history#map=' +
47437             Math.floor(zoom$$1) + '/' +
47438             center[1].toFixed(precision) + '/' +
47439             center[0].toFixed(precision);
47440     },
47441
47442
47443     entityURL: function(entity) {
47444         return urlroot + '/' + entity.type + '/' + entity.osmId();
47445     },
47446
47447
47448     userURL: function(username) {
47449         return urlroot + '/user/' + username;
47450     },
47451
47452
47453     loadFromAPI: function(path$$1, callback) {
47454         var that = this;
47455
47456         function done(err, xml$$1) {
47457             var isAuthenticated = that.authenticated();
47458
47459             // 400 Bad Request, 401 Unauthorized, 403 Forbidden
47460             // Logout and retry the request..
47461             if (isAuthenticated && err &&
47462                     (err.status === 400 || err.status === 401 || err.status === 403)) {
47463                 that.logout();
47464                 that.loadFromAPI(path$$1, callback);
47465
47466             // else, no retry..
47467             } else {
47468                 // 509 Bandwidth Limit Exceeded, 429 Too Many Requests
47469                 // Set the rateLimitError flag and trigger a warning..
47470                 if (!isAuthenticated && !rateLimitError && err &&
47471                         (err.status === 509 || err.status === 429)) {
47472                     rateLimitError = err;
47473                     dispatch$3.call('change');
47474                 }
47475
47476                 if (callback) {
47477                     callback(err, parse$1(xml$$1));
47478                 }
47479             }
47480         }
47481
47482         if (this.authenticated()) {
47483             return oauth.xhr({ method: 'GET', path: path$$1 }, done);
47484         } else {
47485             var url = urlroot + path$$1;
47486             return xml(url).get(done);
47487         }
47488     },
47489
47490
47491     loadEntity: function(id, callback) {
47492         var type = osmEntity$$1.id.type(id),
47493             osmID = osmEntity$$1.id.toOSM(id);
47494
47495         this.loadFromAPI(
47496             '/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : ''),
47497             function(err, entities) {
47498                 if (callback) callback(err, { data: entities });
47499             }
47500         );
47501     },
47502
47503
47504     loadEntityVersion: function(id, version$$1, callback) {
47505         var type = osmEntity$$1.id.type(id),
47506             osmID = osmEntity$$1.id.toOSM(id);
47507
47508         this.loadFromAPI(
47509             '/api/0.6/' + type + '/' + osmID + '/' + version$$1,
47510             function(err, entities) {
47511                 if (callback) callback(err, { data: entities });
47512             }
47513         );
47514     },
47515
47516
47517     loadMultiple: function(ids, callback) {
47518         var that = this;
47519         lodash.each(lodash.groupBy(lodash.uniq(ids), osmEntity$$1.id.type), function(v, k) {
47520             var type = k + 's',
47521                 osmIDs = lodash.map(v, osmEntity$$1.id.toOSM);
47522
47523             lodash.each(lodash.chunk(osmIDs, 150), function(arr) {
47524                 that.loadFromAPI(
47525                     '/api/0.6/' + type + '?' + type + '=' + arr.join(),
47526                     function(err, entities) {
47527                         if (callback) callback(err, { data: entities });
47528                     }
47529                 );
47530             });
47531         });
47532     },
47533
47534
47535     authenticated: function() {
47536         return oauth.authenticated();
47537     },
47538
47539
47540     putChangeset: function(changeset, changes, callback) {
47541
47542         // Create the changeset..
47543         oauth.xhr({
47544             method: 'PUT',
47545             path: '/api/0.6/changeset/create',
47546             options: { header: { 'Content-Type': 'text/xml' } },
47547             content: JXON.stringify(changeset.asJXON())
47548         }, createdChangeset);
47549
47550
47551         function createdChangeset(err, changeset_id) {
47552             if (err) return callback(err);
47553             changeset = changeset.update({ id: changeset_id });
47554
47555             // Upload the changeset..
47556             oauth.xhr({
47557                 method: 'POST',
47558                 path: '/api/0.6/changeset/' + changeset_id + '/upload',
47559                 options: { header: { 'Content-Type': 'text/xml' } },
47560                 content: JXON.stringify(changeset.osmChangeJXON(changes))
47561             }, uploadedChangeset);
47562         }
47563
47564
47565         function uploadedChangeset(err) {
47566             if (err) return callback(err);
47567
47568             // Upload was successful, safe to call the callback.
47569             // Add delay to allow for postgres replication #1646 #2678
47570             window.setTimeout(function() {
47571                 callback(null, changeset);
47572             }, 2500);
47573
47574             // Still attempt to close changeset, but ignore response because #2667
47575             oauth.xhr({
47576                 method: 'PUT',
47577                 path: '/api/0.6/changeset/' + changeset.id + '/close',
47578                 options: { header: { 'Content-Type': 'text/xml' } }
47579             }, function() { return true; });
47580         }
47581     },
47582
47583
47584     userDetails: function(callback) {
47585         if (userDetails) {
47586             callback(undefined, userDetails);
47587             return;
47588         }
47589
47590         function done(err, user_details) {
47591             if (err) return callback(err);
47592
47593             var u = user_details.getElementsByTagName('user')[0],
47594                 img = u.getElementsByTagName('img'),
47595                 image_url = '';
47596
47597             if (img && img[0] && img[0].getAttribute('href')) {
47598                 image_url = img[0].getAttribute('href');
47599             }
47600
47601             userDetails = {
47602                 display_name: u.attributes.display_name.value,
47603                 image_url: image_url,
47604                 id: u.attributes.id.value
47605             };
47606
47607             callback(undefined, userDetails);
47608         }
47609
47610         oauth.xhr({ method: 'GET', path: '/api/0.6/user/details' }, done);
47611     },
47612
47613
47614     userChangesets: function(callback) {
47615         if (userChangesets) {
47616             callback(undefined, userChangesets);
47617             return;
47618         }
47619
47620         this.userDetails(function(err, user) {
47621             if (err) {
47622                 callback(err);
47623                 return;
47624             }
47625
47626             function done(err, changesets) {
47627                 if (err) {
47628                     callback(err);
47629                 } else {
47630                     userChangesets = Array.prototype.map.call(
47631                         changesets.getElementsByTagName('changeset'),
47632                         function (changeset) {
47633                             return { tags: getTags(changeset) };
47634                         }
47635                     ).filter(function (changeset) {
47636                         var comment = changeset.tags.comment;
47637                         return comment && comment !== '';
47638                     });
47639                     callback(undefined, userChangesets);
47640                 }
47641             }
47642
47643             oauth.xhr({ method: 'GET', path: '/api/0.6/changesets?user=' + user.id }, done);
47644         });
47645     },
47646
47647
47648     status: function(callback) {
47649         function done(xml$$1) {
47650             // update blacklists
47651             var elements = xml$$1.getElementsByTagName('blacklist'),
47652                 regexes = [];
47653             for (var i = 0; i < elements.length; i++) {
47654                 var regex = elements[i].getAttribute('regex');  // needs unencode?
47655                 if (regex) {
47656                     regexes.push(regex);
47657                 }
47658             }
47659             if (regexes.length) {
47660                 blacklists = regexes;
47661             }
47662
47663
47664             if (rateLimitError) {
47665                 callback(rateLimitError, 'rateLimited');
47666             } else {
47667                 var apiStatus = xml$$1.getElementsByTagName('status'),
47668                     val = apiStatus[0].getAttribute('api');
47669
47670                 callback(undefined, val);
47671             }
47672         }
47673
47674         xml(urlroot + '/api/capabilities').get()
47675             .on('load', done)
47676             .on('error', callback);
47677     },
47678
47679
47680     imageryBlacklists: function() {
47681         return blacklists;
47682     },
47683
47684
47685     tileZoom: function(_) {
47686         if (!arguments.length) return tileZoom$1;
47687         tileZoom$1 = _;
47688         return this;
47689     },
47690
47691
47692     loadTiles: function(projection$$1, dimensions, callback) {
47693         if (off) return;
47694
47695         var that = this,
47696             s = projection$$1.scale() * 2 * Math.PI,
47697             z = Math.max(Math.log(s) / Math.log(2) - 8, 0),
47698             ts = 256 * Math.pow(2, z - tileZoom$1),
47699             origin = [
47700                 s / 2 - projection$$1.translate()[0],
47701                 s / 2 - projection$$1.translate()[1]
47702             ];
47703
47704         var tiles = d3geoTile()
47705             .scaleExtent([tileZoom$1, tileZoom$1])
47706             .scale(s)
47707             .size(dimensions)
47708             .translate(projection$$1.translate())()
47709             .map(function(tile) {
47710                 var x = tile[0] * ts - origin[0],
47711                     y = tile[1] * ts - origin[1];
47712
47713                 return {
47714                     id: tile.toString(),
47715                     extent: geoExtent$$1(
47716                         projection$$1.invert([x, y + ts]),
47717                         projection$$1.invert([x + ts, y]))
47718                 };
47719             });
47720
47721         lodash.filter(inflight$1, function(v, i) {
47722             var wanted = lodash.find(tiles, function(tile) {
47723                 return i === tile.id;
47724             });
47725             if (!wanted) delete inflight$1[i];
47726             return !wanted;
47727         }).map(abortRequest$1);
47728
47729         tiles.forEach(function(tile) {
47730             var id = tile.id;
47731
47732             if (loadedTiles[id] || inflight$1[id]) return;
47733
47734             if (lodash.isEmpty(inflight$1)) {
47735                 dispatch$3.call('loading');
47736             }
47737
47738             inflight$1[id] = that.loadFromAPI(
47739                 '/api/0.6/map?bbox=' + tile.extent.toParam(),
47740                 function(err, parsed) {
47741                     delete inflight$1[id];
47742                     if (!err) {
47743                         loadedTiles[id] = true;
47744                     }
47745
47746                     if (callback) {
47747                         callback(err, lodash.extend({ data: parsed }, tile));
47748                     }
47749
47750                     if (lodash.isEmpty(inflight$1)) {
47751                         dispatch$3.call('loaded');
47752                     }
47753                 }
47754             );
47755         });
47756     },
47757
47758
47759     switch: function(options) {
47760         urlroot = options.urlroot;
47761
47762         oauth.options(lodash.extend({
47763             url: urlroot,
47764             loading: authLoading,
47765             done: authDone
47766         }, options));
47767
47768         dispatch$3.call('change');
47769         this.reset();
47770         this.userChangesets(function() {});  // eagerly load user details/changesets
47771         return this;
47772     },
47773
47774
47775     toggle: function(_) {
47776         off = !_;
47777         return this;
47778     },
47779
47780
47781     loadedTiles: function(_) {
47782         if (!arguments.length) return loadedTiles;
47783         loadedTiles = _;
47784         return this;
47785     },
47786
47787
47788     logout: function() {
47789         userChangesets = undefined;
47790         userDetails = undefined;
47791         oauth.logout();
47792         dispatch$3.call('change');
47793         return this;
47794     },
47795
47796
47797     authenticate: function(callback) {
47798         var that = this;
47799         userChangesets = undefined;
47800         userDetails = undefined;
47801
47802         function done(err, res) {
47803             rateLimitError = undefined;
47804             dispatch$3.call('change');
47805             if (callback) callback(err, res);
47806             that.userChangesets(function() {});  // eagerly load user details/changesets
47807         }
47808
47809         return oauth.authenticate(done);
47810     }
47811 };
47812
47813 var apibase$2 = 'https://taginfo.openstreetmap.org/api/4/';
47814 var inflight$2 = {};
47815 var popularKeys = {};
47816 var taginfoCache = {};
47817 var tag_sorts = {
47818         point: 'count_nodes',
47819         vertex: 'count_nodes',
47820         area: 'count_ways',
47821         line: 'count_ways'
47822     };
47823 var tag_sort_members = {
47824         point: 'count_node_members',
47825         vertex: 'count_node_members',
47826         area: 'count_way_members',
47827         line: 'count_way_members',
47828         relation: 'count_relation_members'
47829     };
47830 var tag_filters = {
47831         point: 'nodes',
47832         vertex: 'nodes',
47833         area: 'ways',
47834         line: 'ways'
47835     };
47836 var tag_members_fractions = {
47837         point: 'count_node_members_fraction',
47838         vertex: 'count_node_members_fraction',
47839         area: 'count_way_members_fraction',
47840         line: 'count_way_members_fraction',
47841         relation: 'count_relation_members_fraction'
47842     };
47843
47844
47845 function sets(params, n, o) {
47846     if (params.geometry && o[params.geometry]) {
47847         params[n] = o[params.geometry];
47848     }
47849     return params;
47850 }
47851
47852
47853 function setFilter(params) {
47854     return sets(params, 'filter', tag_filters);
47855 }
47856
47857
47858 function setSort(params) {
47859     return sets(params, 'sortname', tag_sorts);
47860 }
47861
47862
47863 function setSortMembers(params) {
47864     return sets(params, 'sortname', tag_sort_members);
47865 }
47866
47867
47868 function clean(params) {
47869     return lodash.omit(params, ['geometry', 'debounce']);
47870 }
47871
47872
47873 function filterKeys(type) {
47874     var count_type = type ? 'count_' + type : 'count_all';
47875     return function(d) {
47876         return parseFloat(d[count_type]) > 2500 || d.in_wiki;
47877     };
47878 }
47879
47880
47881 function filterMultikeys(prefix) {
47882     return function(d) {
47883         // d.key begins with prefix, and d.key contains no additional ':'s
47884         var re = new RegExp('^' + prefix + '(.*)$');
47885         var matches = d.key.match(re) || [];
47886         return (matches.length === 2 && matches[1].indexOf(':') === -1);
47887     };
47888 }
47889
47890
47891 function filterValues(allowUpperCase) {
47892     return function(d) {
47893         if (d.value.match(/[;,]/) !== null) return false;  // exclude some punctuation
47894         if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null) return false;  // exclude uppercase letters
47895         return parseFloat(d.fraction) > 0.0 || d.in_wiki;
47896     };
47897 }
47898
47899
47900 function filterRoles(geometry) {
47901     return function(d) {
47902         if (d.role === '') return false; // exclude empty role
47903         if (d.role.match(/[A-Z*;,]/) !== null) return false;  // exclude uppercase letters and some punctuation
47904         return parseFloat(d[tag_members_fractions[geometry]]) > 0.0;
47905     };
47906 }
47907
47908
47909 function valKey(d) {
47910     return {
47911         value: d.key,
47912         title: d.key
47913     };
47914 }
47915
47916
47917 function valKeyDescription(d) {
47918     return {
47919         value: d.value,
47920         title: d.description || d.value
47921     };
47922 }
47923
47924
47925 function roleKey(d) {
47926     return {
47927         value: d.role,
47928         title: d.role
47929     };
47930 }
47931
47932
47933 // sort keys with ':' lower than keys without ':'
47934 function sortKeys(a, b) {
47935     return (a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1) ? -1
47936         : (a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1) ? 1
47937         : 0;
47938 }
47939
47940
47941 var debouncedRequest = lodash.debounce(request$1, 500, { leading: false });
47942
47943 function request$1(url, params, exactMatch, callback, loaded) {
47944     if (inflight$2[url]) return;
47945
47946     if (checkCache(url, params, exactMatch, callback)) return;
47947
47948     inflight$2[url] = json(url, function (err, data) {
47949         delete inflight$2[url];
47950         loaded(err, data);
47951     });
47952 }
47953
47954
47955 function checkCache(url, params, exactMatch, callback) {
47956     var rp = params.rp || 25,
47957         testQuery = params.query || '',
47958         testUrl = url;
47959
47960     do {
47961         var hit = taginfoCache[testUrl];
47962
47963         // exact match, or shorter match yielding fewer than max results (rp)
47964         if (hit && (url === testUrl || hit.length < rp)) {
47965             callback(null, hit);
47966             return true;
47967         }
47968
47969         // don't try to shorten the query
47970         if (exactMatch || !testQuery.length) return false;
47971
47972         // do shorten the query to see if we already have a cached result
47973         // that has returned fewer than max results (rp)
47974         testQuery = testQuery.slice(0, -1);
47975         testUrl = url.replace(/&query=(.*?)&/, '&query=' + testQuery + '&');
47976     } while (testQuery.length >= 0);
47977
47978     return false;
47979 }
47980
47981
47982 var serviceTaginfo = {
47983
47984     init: function() {
47985         inflight$2 = {};
47986         taginfoCache = {};
47987         popularKeys = {};
47988
47989         // Fetch popular keys.  We'll exclude these from `values`
47990         // lookups because they stress taginfo, and they aren't likely
47991         // to yield meaningful autocomplete results.. see #3955
47992         var params = { rp: 100, sortname: 'values_all', sortorder: 'desc', page: 1, debounce: false };
47993         this.keys(params, function(err, data) {
47994             if (err) return;
47995             data.forEach(function(d) {
47996                 if (d.value === 'opening_hours') return;  // exception
47997                 popularKeys[d.value] = true;
47998             });
47999         });
48000     },
48001
48002
48003     reset: function() {
48004         lodash.forEach(inflight$2, function(req) { req.abort(); });
48005         inflight$2 = {};
48006     },
48007
48008
48009     keys: function(params, callback) {
48010         var doRequest = params.debounce ? debouncedRequest : request$1;
48011         params = clean(setSort(params));
48012         params = lodash.extend({ rp: 10, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
48013
48014         var url = apibase$2 + 'keys/all?' + utilQsString(params);
48015         doRequest(url, params, false, callback, function(err, d) {
48016             if (err) {
48017                 callback(err);
48018             } else {
48019                 var f = filterKeys(params.filter);
48020                 var result = d.data.filter(f).sort(sortKeys).map(valKey);
48021                 taginfoCache[url] = result;
48022                 callback(null, result);
48023             }
48024         });
48025     },
48026
48027
48028     multikeys: function(params, callback) {
48029         var doRequest = params.debounce ? debouncedRequest : request$1;
48030         params = clean(setSort(params));
48031         params = lodash.extend({ rp: 25, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
48032         var prefix = params.query;
48033
48034         var url = apibase$2 + 'keys/all?' + utilQsString(params);
48035         doRequest(url, params, true, callback, function(err, d) {
48036             if (err) {
48037                 callback(err);
48038             } else {
48039                 var f = filterMultikeys(prefix);
48040                 var result = d.data.filter(f).map(valKey);
48041                 taginfoCache[url] = result;
48042                 callback(null, result);
48043             }
48044         });
48045     },
48046
48047
48048     values: function(params, callback) {
48049         // Exclude popular keys from values lookups.. see #3955
48050         var key = params.key;
48051         if (key && popularKeys[key]) {
48052             callback(null, []);
48053             return;
48054         }
48055
48056         var doRequest = params.debounce ? debouncedRequest : request$1;
48057         params = clean(setSort(setFilter(params)));
48058         params = lodash.extend({ rp: 25, sortname: 'count_all', sortorder: 'desc', page: 1 }, params);
48059
48060         var url = apibase$2 + 'key/values?' + utilQsString(params);
48061         doRequest(url, params, false, callback, function(err, d) {
48062             if (err) {
48063                 callback(err);
48064             } else {
48065                 // In most cases we prefer taginfo value results with lowercase letters.
48066                 // A few OSM keys expect values to contain uppercase values (see #3377).
48067                 // This is not an exhaustive list (e.g. `name` also has uppercase values)
48068                 // but these are the fields where taginfo value lookup is most useful.
48069                 var re = /network|taxon|genus|species|brand|grape_variety|_hours|_times/;
48070                 var allowUpperCase = (params.key.match(re) !== null);
48071                 var f = filterValues(allowUpperCase);
48072
48073                 var result = d.data.filter(f).map(valKeyDescription);
48074                 taginfoCache[url] = result;
48075                 callback(null, result);
48076             }
48077         });
48078     },
48079
48080
48081     roles: function(params, callback) {
48082         var doRequest = params.debounce ? debouncedRequest : request$1;
48083         var geometry = params.geometry;
48084         params = clean(setSortMembers(params));
48085         params = lodash.extend({ rp: 25, sortname: 'count_all_members', sortorder: 'desc', page: 1 }, params);
48086
48087         var url = apibase$2 + 'relation/roles?' + utilQsString(params);
48088         doRequest(url, params, true, callback, function(err, d) {
48089             if (err) {
48090                 callback(err);
48091             } else {
48092                 var f = filterRoles(geometry);
48093                 var result = d.data.filter(f).map(roleKey);
48094                 taginfoCache[url] = result;
48095                 callback(null, result);
48096             }
48097         });
48098     },
48099
48100
48101     docs: function(params, callback) {
48102         var doRequest = params.debounce ? debouncedRequest : request$1;
48103         params = clean(setSort(params));
48104
48105         var path$$1 = 'key/wiki_pages?';
48106         if (params.value) path$$1 = 'tag/wiki_pages?';
48107         else if (params.rtype) path$$1 = 'relation/wiki_pages?';
48108
48109         var url = apibase$2 + path$$1 + utilQsString(params);
48110         doRequest(url, params, true, callback, function(err, d) {
48111             if (err) {
48112                 callback(err);
48113             } else {
48114                 taginfoCache[url] = d.data;
48115                 callback(null, d.data);
48116             }
48117         });
48118     },
48119
48120
48121     apibase: function(_) {
48122         if (!arguments.length) return apibase$2;
48123         apibase$2 = _;
48124         return this;
48125     }
48126
48127 };
48128
48129 var jsonpCache = {};
48130 window.jsonpCache = jsonpCache;
48131
48132 function jsonpRequest(url, callback) {
48133
48134   if (window.JSONP_FIX) {
48135     if (window.JSONP_DELAY === 0) {
48136       callback(window.JSONP_FIX);
48137     } else {
48138       setTimeout(function() {
48139         callback(window.JSONP_FIX);
48140       }, window.JSONP_DELAY || 0);
48141     }
48142     return;
48143   }
48144
48145   function rand() {
48146     var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
48147       c = '', i = -1;
48148     while (++i < 15) c += chars.charAt(Math.floor(Math.random() * 52));
48149     return c;
48150   }
48151
48152   function create(url) {
48153     var e = url.match(/callback=(\w+)/),
48154       c = e ? e[1] : rand();
48155     jsonpCache[c] = function(data) {
48156       callback(data);
48157       delete jsonpCache[c];
48158       script.remove();
48159     };
48160     return 'jsonpCache.' + c;
48161   }
48162
48163   var cb = create(url),
48164     script = select('head')
48165     .append('script')
48166     .attr('type', 'text/javascript')
48167     .attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
48168 }
48169
48170 var endpoint = 'https://www.wikidata.org/w/api.php?';
48171
48172 var serviceWikidata = {
48173
48174     init: function() {},
48175     reset: function() {},
48176
48177
48178     // Given a Wikipedia language and article title, return an array of
48179     // corresponding Wikidata entities.
48180     itemsByTitle: function(lang, title, callback) {
48181         if (!title) {
48182             callback('', {});
48183             return;
48184         }
48185
48186         lang = lang || 'en';
48187         jsonpRequest(endpoint + utilQsString({
48188             action: 'wbgetentities',
48189             format: 'json',
48190             sites: lang.replace(/-/g, '_') + 'wiki',
48191             titles: title,
48192             languages: 'en', // shrink response by filtering to one language
48193             callback: '{callback}'
48194         }), function(data) {
48195             if (!data || data.error) {
48196                 callback('', {});
48197             } else {
48198                 callback(title, data.entities || {});
48199             }
48200         });
48201     }
48202
48203 };
48204
48205 var endpoint$1 = 'https://en.wikipedia.org/w/api.php?';
48206
48207 var serviceWikipedia = {
48208
48209     init: function() {},
48210     reset: function() {},
48211
48212
48213     search: function(lang, query, callback) {
48214         if (!query) {
48215             callback('', []);
48216             return;
48217         }
48218
48219         lang = lang || 'en';
48220         jsonpRequest(endpoint$1.replace('en', lang) +
48221             utilQsString({
48222                 action: 'query',
48223                 list: 'search',
48224                 srlimit: '10',
48225                 srinfo: 'suggestion',
48226                 format: 'json',
48227                 callback: '{callback}',
48228                 srsearch: query
48229             }), function(data) {
48230                 if (!data || !data.query || !data.query.search || data.error) {
48231                     callback('', []);
48232                 } else {
48233                     var results = data.query.search.map(function(d) { return d.title; });
48234                     callback(query, results);
48235                 }
48236             }
48237         );
48238     },
48239
48240
48241     suggestions: function(lang, query, callback) {
48242         if (!query) {
48243             callback('', []);
48244             return;
48245         }
48246
48247         lang = lang || 'en';
48248         jsonpRequest(endpoint$1.replace('en', lang) +
48249             utilQsString({
48250                 action: 'opensearch',
48251                 namespace: 0,
48252                 suggest: '',
48253                 format: 'json',
48254                 callback: '{callback}',
48255                 search: query
48256             }), function(data) {
48257                 if (!data || data.error) {
48258                     callback('', []);
48259                 } else {
48260                     callback(data[0], data[1] || []);
48261                 }
48262             }
48263         );
48264     },
48265
48266
48267     translations: function(lang, title, callback) {
48268         if (!title) {
48269             callback({});
48270             return;
48271         }
48272
48273         jsonpRequest(endpoint$1.replace('en', lang) +
48274             utilQsString({
48275                 action: 'query',
48276                 prop: 'langlinks',
48277                 format: 'json',
48278                 callback: '{callback}',
48279                 lllimit: 500,
48280                 titles: title
48281             }), function(data) {
48282                 if (!data || !data.query || !data.query.pages || data.error) {
48283                     callback({});
48284                 } else {
48285                     var list = data.query.pages[Object.keys(data.query.pages)[0]],
48286                         translations = {};
48287                     if (list && list.langlinks) {
48288                         list.langlinks.forEach(function(d) {
48289                             translations[d.lang] = d['*'];
48290                         });
48291                     }
48292                     callback(translations);
48293                 }
48294             }
48295         );
48296     }
48297
48298 };
48299
48300 var services = {
48301     mapillary: serviceMapillary,
48302     geocoder: serviceNominatim,
48303     osm: serviceOsm,
48304     taginfo: serviceTaginfo,
48305     wikidata: serviceWikidata,
48306     wikipedia: serviceWikipedia
48307 };
48308
48309 function svgMapillaryImages(projection$$1, context, dispatch$$1) {
48310     var throttledRedraw = lodash.throttle(function () { dispatch$$1.call('change'); }, 1000),
48311         minZoom = 12,
48312         minViewfieldZoom = 17,
48313         layer = select(null),
48314         _mapillary;
48315
48316
48317     function init() {
48318         if (svgMapillaryImages.initialized) return;  // run once
48319         svgMapillaryImages.enabled = false;
48320         svgMapillaryImages.initialized = true;
48321     }
48322
48323
48324     function getMapillary() {
48325         if (services.mapillary && !_mapillary) {
48326             _mapillary = services.mapillary;
48327             _mapillary.event.on('loadedImages', throttledRedraw);
48328         } else if (!services.mapillary && _mapillary) {
48329             _mapillary = null;
48330         }
48331
48332         return _mapillary;
48333     }
48334
48335
48336     function showLayer() {
48337         var mapillary = getMapillary();
48338         if (!mapillary) return;
48339
48340         mapillary.loadViewer(context);
48341         editOn();
48342
48343         layer
48344             .style('opacity', 0)
48345             .transition()
48346             .duration(500)
48347             .style('opacity', 1)
48348             .on('end', function () { dispatch$$1.call('change'); });
48349     }
48350
48351
48352     function hideLayer() {
48353         var mapillary = getMapillary();
48354         if (mapillary) {
48355             mapillary.hideViewer();
48356         }
48357
48358         throttledRedraw.cancel();
48359
48360         layer
48361             .transition()
48362             .duration(500)
48363             .style('opacity', 0)
48364             .on('end', editOff);
48365     }
48366
48367
48368     function editOn() {
48369         layer.style('display', 'block');
48370     }
48371
48372
48373     function editOff() {
48374         layer.selectAll('.viewfield-group').remove();
48375         layer.style('display', 'none');
48376     }
48377
48378
48379     function click(d) {
48380         var mapillary = getMapillary();
48381         if (!mapillary) return;
48382
48383         context.map().centerEase(d.loc);
48384
48385         mapillary
48386             .selectedImage(d.key, true)
48387             .updateViewer(d.key, context)
48388             .showViewer();
48389     }
48390
48391
48392     function transform$$1(d) {
48393         var t = svgPointTransform(projection$$1)(d);
48394         if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
48395         return t;
48396     }
48397
48398
48399     function update() {
48400         var mapillary = getMapillary(),
48401             data = (mapillary ? mapillary.images(projection$$1) : []),
48402             imageKey = mapillary ? mapillary.selectedImage() : null;
48403
48404         var markers = layer.selectAll('.viewfield-group')
48405             .data(data, function(d) { return d.key; });
48406
48407         markers.exit()
48408             .remove();
48409
48410         var enter = markers.enter()
48411             .append('g')
48412             .attr('class', 'viewfield-group')
48413             .classed('selected', function(d) { return d.key === imageKey; })
48414             .on('click', click);
48415
48416         markers = markers
48417             .merge(enter)
48418             .attr('transform', transform$$1);
48419
48420
48421        var viewfields = markers.selectAll('.viewfield')
48422             .data(~~context.map().zoom() >= minViewfieldZoom ? [0] : []);
48423
48424         viewfields.exit()
48425             .remove();
48426
48427         viewfields.enter()
48428             .append('path')
48429             .attr('class', 'viewfield')
48430             .attr('transform', 'scale(1.5,1.5),translate(-8, -13)')
48431             .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');
48432
48433         markers.selectAll('circle')
48434             .data([0])
48435             .enter()
48436             .append('circle')
48437             .attr('dx', '0')
48438             .attr('dy', '0')
48439             .attr('r', '6');
48440     }
48441
48442
48443     function drawImages(selection$$1) {
48444         var enabled = svgMapillaryImages.enabled,
48445             mapillary = getMapillary();
48446
48447         layer = selection$$1.selectAll('.layer-mapillary-images')
48448             .data(mapillary ? [0] : []);
48449
48450         layer.exit()
48451             .remove();
48452
48453         layer = layer.enter()
48454             .append('g')
48455             .attr('class', 'layer-mapillary-images')
48456             .style('display', enabled ? 'block' : 'none')
48457             .merge(layer);
48458
48459         if (enabled) {
48460             if (mapillary && ~~context.map().zoom() >= minZoom) {
48461                 editOn();
48462                 update();
48463                 mapillary.loadImages(projection$$1);
48464             } else {
48465                 editOff();
48466             }
48467         }
48468     }
48469
48470
48471     drawImages.enabled = function(_) {
48472         if (!arguments.length) return svgMapillaryImages.enabled;
48473         svgMapillaryImages.enabled = _;
48474         if (svgMapillaryImages.enabled) {
48475             showLayer();
48476         } else {
48477             hideLayer();
48478         }
48479         dispatch$$1.call('change');
48480         return this;
48481     };
48482
48483
48484     drawImages.supported = function() {
48485         return !!getMapillary();
48486     };
48487
48488
48489     init();
48490     return drawImages;
48491 }
48492
48493 function svgMapillarySigns(projection$$1, context, dispatch$$1) {
48494     var throttledRedraw = lodash.throttle(function () { dispatch$$1.call('change'); }, 1000),
48495         minZoom = 12,
48496         layer = select(null),
48497         _mapillary;
48498
48499
48500     function init() {
48501         if (svgMapillarySigns.initialized) return;  // run once
48502         svgMapillarySigns.enabled = false;
48503         svgMapillarySigns.initialized = true;
48504     }
48505
48506
48507     function getMapillary() {
48508         if (services.mapillary && !_mapillary) {
48509             _mapillary = services.mapillary;
48510             _mapillary.event.on('loadedSigns', throttledRedraw);
48511         } else if (!services.mapillary && _mapillary) {
48512             _mapillary = null;
48513         }
48514         return _mapillary;
48515     }
48516
48517
48518     function showLayer() {
48519         editOn();
48520     }
48521
48522
48523     function hideLayer() {
48524         throttledRedraw.cancel();
48525         editOff();
48526     }
48527
48528
48529     function editOn() {
48530         layer.style('display', 'block');
48531     }
48532
48533
48534     function editOff() {
48535         layer.selectAll('.icon-sign').remove();
48536         layer.style('display', 'none');
48537     }
48538
48539
48540     function click(d) {
48541         var mapillary = getMapillary();
48542         if (!mapillary) return;
48543
48544         context.map().centerEase(d.loc);
48545
48546         mapillary
48547             .selectedImage(d.key, true)
48548             .updateViewer(d.key, context)
48549             .showViewer();
48550     }
48551
48552
48553     function update() {
48554         var mapillary = getMapillary(),
48555             data = (mapillary ? mapillary.signs(projection$$1) : []),
48556             imageKey = mapillary ? mapillary.selectedImage() : null;
48557
48558         var signs = layer.selectAll('.icon-sign')
48559             .data(data, function(d) { return d.key; });
48560
48561         signs.exit()
48562             .remove();
48563
48564         var enter = signs.enter()
48565             .append('foreignObject')
48566             .attr('class', 'icon-sign')
48567             .attr('width', '32px')      // for Firefox
48568             .attr('height', '32px')     // for Firefox
48569             .classed('selected', function(d) { return d.key === imageKey; })
48570             .on('click', click);
48571
48572         enter
48573             .append('xhtml:body')
48574             .attr('class', 'icon-sign-body')
48575             .html(mapillary.signHTML);
48576
48577         signs
48578             .merge(enter)
48579             .attr('x', function(d) { return projection$$1(d.loc)[0] - 16; })   // offset by -16px to
48580             .attr('y', function(d) { return projection$$1(d.loc)[1] - 16; });  // center signs on loc
48581     }
48582
48583
48584     function drawSigns(selection$$1) {
48585         var enabled = svgMapillarySigns.enabled,
48586             mapillary = getMapillary();
48587
48588         layer = selection$$1.selectAll('.layer-mapillary-signs')
48589             .data(mapillary ? [0] : []);
48590
48591         layer.exit()
48592             .remove();
48593
48594         layer = layer.enter()
48595             .append('g')
48596             .attr('class', 'layer-mapillary-signs')
48597             .style('display', enabled ? 'block' : 'none')
48598             .merge(layer);
48599
48600         if (enabled) {
48601             if (mapillary && ~~context.map().zoom() >= minZoom) {
48602                 editOn();
48603                 update();
48604                 mapillary.loadSigns(context, projection$$1);
48605             } else {
48606                 editOff();
48607             }
48608         }
48609     }
48610
48611
48612     drawSigns.enabled = function(_) {
48613         if (!arguments.length) return svgMapillarySigns.enabled;
48614         svgMapillarySigns.enabled = _;
48615         if (svgMapillarySigns.enabled) {
48616             showLayer();
48617         } else {
48618             hideLayer();
48619         }
48620         dispatch$$1.call('change');
48621         return this;
48622     };
48623
48624
48625     drawSigns.supported = function() {
48626         var mapillary = getMapillary();
48627         return (mapillary && mapillary.signsSupported());
48628     };
48629
48630
48631     init();
48632     return drawSigns;
48633 }
48634
48635 function svgOsm() {
48636     return function drawOsm(selection) {
48637         var layers = selection.selectAll('.layer-osm')
48638             .data(['areas', 'lines', 'hit', 'halo', 'label']);
48639
48640         layers.enter()
48641             .append('g')
48642             .attr('class', function(d) { return 'layer-osm layer-' + d; });
48643     };
48644 }
48645
48646 function svgLayers(projection$$1, context) {
48647     var dispatch$$1 = dispatch('change'),
48648         svg = select(null),
48649         layers = [
48650             { id: 'osm', layer: svgOsm(projection$$1, context, dispatch$$1) },
48651             { id: 'gpx', layer: svgGpx(projection$$1, context, dispatch$$1) },
48652             { id: 'mapillary-images', layer: svgMapillaryImages(projection$$1, context, dispatch$$1) },
48653             { id: 'mapillary-signs',  layer: svgMapillarySigns(projection$$1, context, dispatch$$1) },
48654             { id: 'debug', layer: svgDebug(projection$$1, context, dispatch$$1) }
48655         ];
48656
48657
48658     function drawLayers(selection$$1) {
48659         svg = selection$$1.selectAll('.surface')
48660             .data([0]);
48661
48662         svg = svg.enter()
48663             .append('svg')
48664             .attr('class', 'surface')
48665             .merge(svg);
48666
48667         var defs = svg.selectAll('.surface-defs')
48668             .data([0]);
48669
48670         defs.enter()
48671             .append('defs')
48672             .attr('class', 'surface-defs');
48673
48674         var groups = svg.selectAll('.data-layer')
48675             .data(layers);
48676
48677         groups.exit()
48678             .remove();
48679
48680         groups.enter()
48681             .append('g')
48682             .attr('class', function(d) { return 'data-layer data-layer-' + d.id; })
48683             .merge(groups)
48684             .each(function(d) { select(this).call(d.layer); });
48685     }
48686
48687
48688     drawLayers.all = function() {
48689         return layers;
48690     };
48691
48692
48693     drawLayers.layer = function(id) {
48694         var obj = lodash.find(layers, function(o) {return o.id === id;});
48695         return obj && obj.layer;
48696     };
48697
48698
48699     drawLayers.only = function(what) {
48700         var arr = [].concat(what);
48701         drawLayers.remove(lodash.difference(lodash.map(layers, 'id'), arr));
48702         return this;
48703     };
48704
48705
48706     drawLayers.remove = function(what) {
48707         var arr = [].concat(what);
48708         arr.forEach(function(id) {
48709             layers = lodash.reject(layers, function(o) {return o.id === id;});
48710         });
48711         dispatch$$1.call('change');
48712         return this;
48713     };
48714
48715
48716     drawLayers.add = function(what) {
48717         var arr = [].concat(what);
48718         arr.forEach(function(obj) {
48719             if ('id' in obj && 'layer' in obj) {
48720                 layers.push(obj);
48721             }
48722         });
48723         dispatch$$1.call('change');
48724         return this;
48725     };
48726
48727
48728     drawLayers.dimensions = function(_) {
48729         if (!arguments.length) return utilGetDimensions(svg);
48730         utilSetDimensions(svg, _);
48731         return this;
48732     };
48733
48734
48735     return utilRebind(drawLayers, dispatch$$1, 'on');
48736 }
48737
48738 function svgLines$$1(projection$$1, context) {
48739     var detected = utilDetect();
48740
48741     var highway_stack = {
48742         motorway: 0,
48743         motorway_link: 1,
48744         trunk: 2,
48745         trunk_link: 3,
48746         primary: 4,
48747         primary_link: 5,
48748         secondary: 6,
48749         tertiary: 7,
48750         unclassified: 8,
48751         residential: 9,
48752         service: 10,
48753         footway: 11
48754     };
48755
48756
48757     function drawLines(selection$$1, graph, entities, filter) {
48758
48759
48760         function waystack(a, b) {
48761             var selected = context.selectedIDs(),
48762                 scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0,
48763                 scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
48764
48765             if (a.tags.highway) { scoreA -= highway_stack[a.tags.highway]; }
48766             if (b.tags.highway) { scoreB -= highway_stack[b.tags.highway]; }
48767             return scoreA - scoreB;
48768         }
48769
48770
48771         function drawLineGroup(selection$$1, klass, isSelected) {
48772             var lines = selection$$1
48773                 .selectAll('path')
48774                 .filter(filter)
48775                 .data(getPathData(isSelected), osmEntity$$1.key);
48776
48777             lines.exit()
48778                 .remove();
48779
48780             // Optimization: call simple TagClasses only on enter selection. This
48781             // works because osmEntity.key is defined to include the entity v attribute.
48782             lines.enter()
48783                 .append('path')
48784                 .attr('class', function(d) {
48785                     return 'way line ' + klass + ' ' + d.id + (isSelected ? ' selected' : '') +
48786                         (oldMultiPolygonOuters[d.id] ? ' old-multipolygon' : '');
48787                 })
48788                 .call(svgTagClasses())
48789                 .merge(lines)
48790                 .sort(waystack)
48791                 .attr('d', getPath)
48792                 .call(svgTagClasses().tags(svgRelationMemberTags(graph)));
48793
48794             return selection$$1;
48795         }
48796
48797
48798         function getPathData(isSelected) {
48799             return function() {
48800                 var layer = this.parentNode.__data__;
48801                 var data = pathdata[layer] || [];
48802                 return data.filter(function(d) {
48803                     if (isSelected)
48804                         return context.selectedIDs().indexOf(d.id) !== -1;
48805                     else
48806                         return context.selectedIDs().indexOf(d.id) === -1;
48807                 });
48808             };
48809         }
48810
48811
48812         var getPath = svgPath(projection$$1, graph),
48813             ways = [],
48814             pathdata = {},
48815             onewaydata = {},
48816             oldMultiPolygonOuters = {};
48817
48818         for (var i = 0; i < entities.length; i++) {
48819             var entity = entities[i],
48820                 outer = osmSimpleMultipolygonOuterMember(entity, graph);
48821             if (outer) {
48822                 ways.push(entity.mergeTags(outer.tags));
48823                 oldMultiPolygonOuters[outer.id] = true;
48824             } else if (entity.geometry(graph) === 'line') {
48825                 ways.push(entity);
48826             }
48827         }
48828
48829         ways = ways.filter(getPath);
48830         pathdata = lodash.groupBy(ways, function(way) { return way.layer(); });
48831
48832         lodash.forOwn(pathdata, function(v, k) {
48833             onewaydata[k] = lodash(v)
48834                 .filter(function(d) { return d.isOneWay(); })
48835                 .map(svgOneWaySegments(projection$$1, graph, 35))
48836                 .flatten()
48837                 .valueOf();
48838         });
48839
48840
48841         var layer = selection$$1.selectAll('.layer-lines');
48842
48843         var layergroup = layer
48844             .selectAll('g.layergroup')
48845             .data(sequence(-10, 11));
48846
48847         layergroup = layergroup.enter()
48848             .append('g')
48849             .attr('class', function(d) { return 'layergroup layer' + String(d); })
48850             .merge(layergroup);
48851
48852         layergroup
48853             .selectAll('g.linegroup')
48854             .data(['shadow', 'casing', 'stroke', 'shadow-highlighted', 'casing-highlighted', 'stroke-highlighted'])
48855             .enter()
48856             .append('g')
48857             .attr('class', function(d) { return 'linegroup line-' + d; });
48858
48859
48860         layergroup.selectAll('g.line-shadow')
48861             .call(drawLineGroup, 'shadow', false);
48862         layergroup.selectAll('g.line-casing')
48863             .call(drawLineGroup, 'casing', false);
48864         layergroup.selectAll('g.line-stroke')
48865             .call(drawLineGroup, 'stroke', false);
48866
48867         layergroup.selectAll('g.line-shadow-highlighted')
48868             .call(drawLineGroup, 'shadow', true);
48869         layergroup.selectAll('g.line-casing-highlighted')
48870             .call(drawLineGroup, 'casing', true);
48871         layergroup.selectAll('g.line-stroke-highlighted')
48872             .call(drawLineGroup, 'stroke', true);
48873
48874
48875         var onewaygroup = layergroup
48876             .selectAll('g.onewaygroup')
48877             .data(['oneway']);
48878
48879         onewaygroup = onewaygroup.enter()
48880             .append('g')
48881             .attr('class', 'onewaygroup')
48882             .merge(onewaygroup);
48883
48884         var oneways = onewaygroup
48885             .selectAll('path')
48886             .filter(filter)
48887             .data(
48888                 function() { return onewaydata[this.parentNode.__data__] || []; },
48889                 function(d) { return [d.id, d.index]; }
48890             );
48891
48892         oneways.exit()
48893             .remove();
48894
48895         oneways = oneways.enter()
48896             .append('path')
48897             .attr('class', 'oneway')
48898             .attr('marker-mid', 'url(#oneway-marker)')
48899             .merge(oneways)
48900             .attr('d', function(d) { return d.d; });
48901
48902         if (detected.ie) {
48903             oneways.each(function() { this.parentNode.insertBefore(this, this); });
48904         }
48905     }
48906
48907
48908     return drawLines;
48909 }
48910
48911 function svgMidpoints$$1(projection, context) {
48912
48913     return function drawMidpoints(selection, graph, entities, filter, extent) {
48914         var layer = selection.selectAll('.layer-hit');
48915
48916         var mode = context.mode();
48917         if (mode && mode.id !== 'select') {
48918             layer.selectAll('g.midpoint').remove();
48919             return;
48920         }
48921
48922         var poly = extent.polygon(),
48923             midpoints = {};
48924
48925         for (var i = 0; i < entities.length; i++) {
48926             var entity = entities[i];
48927
48928             if (entity.type !== 'way')
48929                 continue;
48930             if (!filter(entity))
48931                 continue;
48932             if (context.selectedIDs().indexOf(entity.id) < 0)
48933                 continue;
48934
48935             var nodes = graph.childNodes(entity);
48936             for (var j = 0; j < nodes.length - 1; j++) {
48937
48938                 var a = nodes[j],
48939                     b = nodes[j + 1],
48940                     id = [a.id, b.id].sort().join('-');
48941
48942                 if (midpoints[id]) {
48943                     midpoints[id].parents.push(entity);
48944                 } else {
48945                     if (geoEuclideanDistance(projection(a.loc), projection(b.loc)) > 40) {
48946                         var point = geoInterp(a.loc, b.loc, 0.5),
48947                             loc = null;
48948
48949                         if (extent.intersects(point)) {
48950                             loc = point;
48951                         } else {
48952                             for (var k = 0; k < 4; k++) {
48953                                 point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
48954                                 if (point &&
48955                                     geoEuclideanDistance(projection(a.loc), projection(point)) > 20 &&
48956                                     geoEuclideanDistance(projection(b.loc), projection(point)) > 20)
48957                                 {
48958                                     loc = point;
48959                                     break;
48960                                 }
48961                             }
48962                         }
48963
48964                         if (loc) {
48965                             midpoints[id] = {
48966                                 type: 'midpoint',
48967                                 id: id,
48968                                 loc: loc,
48969                                 edge: [a.id, b.id],
48970                                 parents: [entity]
48971                             };
48972                         }
48973                     }
48974                 }
48975             }
48976         }
48977
48978
48979         function midpointFilter(d) {
48980             if (midpoints[d.id])
48981                 return true;
48982
48983             for (var i = 0; i < d.parents.length; i++) {
48984                 if (filter(d.parents[i])) {
48985                     return true;
48986                 }
48987             }
48988
48989             return false;
48990         }
48991
48992
48993         var groups = layer
48994             .selectAll('g.midpoint')
48995             .filter(midpointFilter)
48996             .data(lodash.values(midpoints), function(d) { return d.id; });
48997
48998         groups.exit()
48999             .remove();
49000
49001         var enter = groups.enter()
49002             .insert('g', ':first-child')
49003             .attr('class', 'midpoint');
49004
49005         enter.append('polygon')
49006             .attr('points', '-6,8 10,0 -6,-8')
49007             .attr('class', 'shadow');
49008
49009         enter.append('polygon')
49010             .attr('points', '-3,4 5,0 -3,-4')
49011             .attr('class', 'fill');
49012
49013         groups = groups
49014             .merge(enter)
49015             .attr('transform', function(d) {
49016                 var translate = svgPointTransform(projection),
49017                     a = graph.entity(d.edge[0]),
49018                     b = graph.entity(d.edge[1]),
49019                     angleVal = Math.round(geoAngle(a, b, projection) * (180 / Math.PI));
49020                 return translate(d) + ' rotate(' + angleVal + ')';
49021             })
49022             .call(svgTagClasses().tags(
49023                 function(d) { return d.parents[0].tags; }
49024             ));
49025
49026         // Propagate data bindings.
49027         groups.select('polygon.shadow');
49028         groups.select('polygon.fill');
49029
49030     };
49031 }
49032
49033 function svgOneWaySegments(projection$$1, graph, dt) {
49034     return function(entity) {
49035         var a,
49036             b,
49037             i = 0,
49038             offset = dt,
49039             segments = [],
49040             clip = identity$5().clipExtent(projection$$1.clipExtent()).stream,
49041             coordinates = graph.childNodes(entity).map(function(n) {
49042                 return n.loc;
49043             });
49044
49045         if (entity.tags.oneway === '-1') coordinates.reverse();
49046
49047         geoStream({
49048             type: 'LineString',
49049             coordinates: coordinates
49050         }, projection$$1.stream(clip({
49051             lineStart: function() {},
49052             lineEnd: function() {
49053                 a = null;
49054             },
49055             point: function(x, y) {
49056                 b = [x, y];
49057
49058                 if (a) {
49059                     var span = geoEuclideanDistance(a, b) - offset;
49060
49061                     if (span >= 0) {
49062                         var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
49063                             dx = dt * Math.cos(angle),
49064                             dy = dt * Math.sin(angle),
49065                             p = [a[0] + offset * Math.cos(angle),
49066                                  a[1] + offset * Math.sin(angle)];
49067
49068                         var segment = 'M' + a[0] + ',' + a[1] +
49069                                       'L' + p[0] + ',' + p[1];
49070
49071                         for (span -= dt; span >= 0; span -= dt) {
49072                             p[0] += dx;
49073                             p[1] += dy;
49074                             segment += 'L' + p[0] + ',' + p[1];
49075                         }
49076
49077                         segment += 'L' + b[0] + ',' + b[1];
49078                         segments.push({id: entity.id, index: i, d: segment});
49079                     }
49080
49081                     offset = -span;
49082                     i++;
49083                 }
49084
49085                 a = b;
49086             }
49087         })));
49088
49089         return segments;
49090     };
49091 }
49092
49093 function svgPath(projection$$1, graph, isArea) {
49094
49095     // Explanation of magic numbers:
49096     // "padding" here allows space for strokes to extend beyond the viewport,
49097     // so that the stroke isn't drawn along the edge of the viewport when
49098     // the shape is clipped.
49099     //
49100     // When drawing lines, pad viewport by 5px.
49101     // When drawing areas, pad viewport by 65px in each direction to allow
49102     // for 60px area fill stroke (see ".fill-partial path.fill" css rule)
49103
49104     var cache = {},
49105         padding = isArea ? 65 : 5,
49106         viewport = projection$$1.clipExtent(),
49107         paddedExtent = [
49108             [viewport[0][0] - padding, viewport[0][1] - padding],
49109             [viewport[1][0] + padding, viewport[1][1] + padding]
49110         ],
49111         clip = identity$5().clipExtent(paddedExtent).stream,
49112         project = projection$$1.stream,
49113         path$$1 = index$4()
49114             .projection({stream: function(output) { return project(clip(output)); }});
49115
49116     return function(entity) {
49117         if (entity.id in cache) {
49118             return cache[entity.id];
49119         } else {
49120             return cache[entity.id] = path$$1(entity.asGeoJSON(graph));
49121         }
49122     };
49123 }
49124
49125 function svgPoints$$1(projection, context) {
49126
49127     function markerPath(selection, klass) {
49128         selection
49129             .attr('class', klass)
49130             .attr('transform', 'translate(-8, -23)')
49131             .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');
49132     }
49133
49134     function sortY(a, b) {
49135         return b.loc[1] - a.loc[1];
49136     }
49137
49138
49139     return function drawPoints(selection, graph, entities, filter) {
49140         var wireframe = context.surface().classed('fill-wireframe'),
49141             points = wireframe ? [] : lodash.filter(entities, function(e) {
49142                 return e.geometry(graph) === 'point';
49143             });
49144
49145         points.sort(sortY);
49146
49147         var layer = selection.selectAll('.layer-hit');
49148
49149         var groups = layer.selectAll('g.point')
49150             .filter(filter)
49151             .data(points, osmEntity$$1.key);
49152
49153         groups.exit()
49154             .remove();
49155
49156         var enter = groups.enter()
49157             .append('g')
49158             .attr('class', function(d) { return 'node point ' + d.id; })
49159             .order();
49160
49161         enter.append('path')
49162             .call(markerPath, 'shadow');
49163
49164         enter.append('ellipse')
49165             .attr('cx', 0.5)
49166             .attr('cy', 1)
49167             .attr('rx', 6.5)
49168             .attr('ry', 3)
49169             .attr('class', 'stroke');
49170
49171         enter.append('path')
49172             .call(markerPath, 'stroke');
49173
49174         enter.append('use')
49175             .attr('transform', 'translate(-5, -19)')
49176             .attr('class', 'icon')
49177             .attr('width', '11px')
49178             .attr('height', '11px');
49179
49180         groups = groups
49181             .merge(enter)
49182             .attr('transform', svgPointTransform(projection))
49183             .call(svgTagClasses());
49184
49185         // Selecting the following implicitly
49186         // sets the data (point entity) on the element
49187         groups.select('.shadow');
49188         groups.select('.stroke');
49189         groups.select('.icon')
49190             .attr('xlink:href', function(entity) {
49191                 var preset = context.presets().match(entity, graph),
49192                     picon = preset && preset.icon;
49193
49194                 if (!picon)
49195                     return '';
49196                 else {
49197                     var isMaki = dataFeatureIcons.indexOf(picon) !== -1;
49198                     return '#' + picon + (isMaki ? '-11' : '');
49199                 }
49200             });
49201     };
49202 }
49203
49204 function svgRelationMemberTags(graph) {
49205     return function(entity) {
49206         var tags = entity.tags;
49207         graph.parentRelations(entity).forEach(function(relation) {
49208             var type = relation.tags.type;
49209             if (type === 'multipolygon' || type === 'boundary') {
49210                 tags = lodash.extend({}, relation.tags, tags);
49211             }
49212         });
49213         return tags;
49214     };
49215 }
49216
49217 function svgTagClasses() {
49218     var primaries = [
49219             'building', 'highway', 'railway', 'waterway', 'aeroway',
49220             'motorway', 'boundary', 'power', 'amenity', 'natural', 'landuse',
49221             'leisure', 'military', 'place'
49222         ],
49223         statuses = [
49224             'proposed', 'construction', 'disused', 'abandoned', 'dismantled',
49225             'razed', 'demolished', 'obliterated'
49226         ],
49227         secondaries = [
49228             'oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier',
49229             'surface', 'tracktype', 'crossing'
49230         ],
49231         tagClassRe = /^tag-/,
49232         tags = function(entity) { return entity.tags; };
49233
49234
49235     var tagClasses = function(selection$$1) {
49236         selection$$1.each(function tagClassesEach(entity) {
49237             var value = this.className,
49238                 classes, primary, status;
49239
49240             if (value.baseVal !== undefined) value = value.baseVal;
49241
49242             classes = value.trim().split(/\s+/).filter(function(name) {
49243                 return name.length && !tagClassRe.test(name);
49244             }).join(' ');
49245
49246             var t = tags(entity), i, k, v;
49247
49248             // pick at most one primary classification tag..
49249             for (i = 0; i < primaries.length; i++) {
49250                 k = primaries[i];
49251                 v = t[k];
49252                 if (!v || v === 'no') continue;
49253
49254                 primary = k;
49255                 if (statuses.indexOf(v) !== -1) {   // e.g. `railway=abandoned`
49256                     status = v;
49257                     classes += ' tag-' + k;
49258                 } else {
49259                     classes += ' tag-' + k + ' tag-' + k + '-' + v;
49260                 }
49261
49262                 break;
49263             }
49264
49265             // add at most one status tag, only if relates to primary tag..
49266             if (!status) {
49267                 for (i = 0; i < statuses.length; i++) {
49268                     k = statuses[i];
49269                     v = t[k];
49270                     if (!v || v === 'no') continue;
49271
49272                     if (v === 'yes') {   // e.g. `railway=rail + abandoned=yes`
49273                         status = k;
49274                     }
49275                     else if (primary && primary === v) {  // e.g. `railway=rail + abandoned=railway`
49276                         status = k;
49277                     } else if (!primary && primaries.indexOf(v) !== -1) {  // e.g. `abandoned=railway`
49278                         status = k;
49279                         primary = v;
49280                         classes += ' tag-' + v;
49281                     }  // else ignore e.g.  `highway=path + abandoned=railway`
49282
49283                     if (status) break;
49284                 }
49285             }
49286
49287             if (status) {
49288                 classes += ' tag-status tag-status-' + status;
49289             }
49290
49291             // add any secondary (structure) tags
49292             for (i = 0; i < secondaries.length; i++) {
49293                 k = secondaries[i];
49294                 v = t[k];
49295                 if (!v || v === 'no') continue;
49296                 classes += ' tag-' + k + ' tag-' + k + '-' + v;
49297             }
49298
49299             // For highways, look for surface tagging..
49300             if (primary === 'highway') {
49301                 var paved = (t.highway !== 'track');
49302                 for (k in t) {
49303                     v = t[k];
49304                     if (k in osmPavedTags) {
49305                         paved = !!osmPavedTags[k][v];
49306                         break;
49307                     }
49308                 }
49309                 if (!paved) {
49310                     classes += ' tag-unpaved';
49311                 }
49312             }
49313
49314             classes = classes.trim();
49315
49316             if (classes !== value) {
49317                 select(this).attr('class', classes);
49318             }
49319         });
49320     };
49321
49322
49323     tagClasses.tags = function(_) {
49324         if (!arguments.length) return tags;
49325         tags = _;
49326         return tagClasses;
49327     };
49328
49329     return tagClasses;
49330 }
49331
49332 function svgTurns(projection) {
49333
49334     return function drawTurns(selection, graph, turns) {
49335
49336         function key(turn) {
49337             return [turn.from.node + turn.via.node + turn.to.node].join('-');
49338         }
49339
49340         function icon(turn) {
49341             var u = turn.u ? '-u' : '';
49342             if (!turn.restriction)
49343                 return '#turn-yes' + u;
49344             var restriction = graph.entity(turn.restriction).tags.restriction;
49345             return '#turn-' +
49346                 (!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
49347         }
49348
49349         var groups = selection.selectAll('.layer-hit').selectAll('g.turn')
49350             .data(turns, key);
49351
49352         groups.exit()
49353             .remove();
49354
49355
49356         var enter = groups.enter()
49357             .append('g')
49358             .attr('class', 'turn');
49359
49360         var nEnter = enter
49361             .filter(function (turn) { return !turn.u; });
49362
49363         nEnter.append('rect')
49364             .attr('transform', 'translate(-22, -12)')
49365             .attr('width', '44')
49366             .attr('height', '24');
49367
49368         nEnter.append('use')
49369             .attr('transform', 'translate(-22, -12)')
49370             .attr('width', '44')
49371             .attr('height', '24');
49372
49373
49374         var uEnter = enter
49375             .filter(function (turn) { return turn.u; });
49376
49377         uEnter.append('circle')
49378             .attr('r', '16');
49379
49380         uEnter.append('use')
49381             .attr('transform', 'translate(-16, -16)')
49382             .attr('width', '32')
49383             .attr('height', '32');
49384
49385
49386         groups = groups
49387             .merge(enter);
49388
49389         groups
49390             .attr('transform', function (turn) {
49391                 var v = graph.entity(turn.via.node),
49392                     t = graph.entity(turn.to.node),
49393                     a = geoAngle(v, t, projection),
49394                     p = projection(v.loc),
49395                     r = turn.u ? 0 : 60;
49396
49397                 return 'translate(' + (r * Math.cos(a) + p[0]) + ',' + (r * Math.sin(a) + p[1]) + ') ' +
49398                     'rotate(' + a * 180 / Math.PI + ')';
49399             });
49400
49401         groups.select('use')
49402             .attr('xlink:href', icon);
49403
49404         groups.select('rect');
49405         groups.select('circle');
49406
49407         return this;
49408     };
49409 }
49410
49411 function svgVertices$$1(projection$$1, context) {
49412     var radiuses = {
49413         //       z16-, z17, z18+, tagged
49414         shadow: [6,    7.5,   7.5,  11.5],
49415         stroke: [2.5,  3.5,   3.5,  7],
49416         fill:   [1,    1.5,   1.5,  1.5]
49417     };
49418
49419     var hover;
49420
49421
49422     function siblingAndChildVertices(ids, graph, extent$$1) {
49423         var vertices = {};
49424
49425         function addChildVertices(entity) {
49426             if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) {
49427                 var i;
49428                 if (entity.type === 'way') {
49429                     for (i = 0; i < entity.nodes.length; i++) {
49430                         addChildVertices(graph.entity(entity.nodes[i]));
49431                     }
49432                 } else if (entity.type === 'relation') {
49433                     for (i = 0; i < entity.members.length; i++) {
49434                         var member = context.hasEntity(entity.members[i].id);
49435                         if (member) {
49436                             addChildVertices(member);
49437                         }
49438                     }
49439                 } else if (entity.intersects(extent$$1, graph)) {
49440                     vertices[entity.id] = entity;
49441                 }
49442             }
49443         }
49444
49445         ids.forEach(function(id) {
49446             var entity = context.hasEntity(id);
49447             if (entity && entity.type === 'node') {
49448                 vertices[entity.id] = entity;
49449                 context.graph().parentWays(entity).forEach(function(entity) {
49450                     addChildVertices(entity);
49451                 });
49452             } else if (entity) {
49453                 addChildVertices(entity);
49454             }
49455         });
49456
49457         return vertices;
49458     }
49459
49460
49461     function draw(selection$$1, vertices, klass, graph, zoom$$1, siblings$$1) {
49462
49463         function icon(entity) {
49464             if (entity.id in icons) return icons[entity.id];
49465             icons[entity.id] =
49466                 entity.hasInterestingTags() &&
49467                 context.presets().match(entity, graph).icon;
49468             return icons[entity.id];
49469         }
49470
49471         function setClass(klass) {
49472             return function(entity) {
49473                 this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
49474             };
49475         }
49476
49477         function setAttributes(selection$$1) {
49478             ['shadow','stroke','fill'].forEach(function(klass) {
49479                 var rads = radiuses[klass];
49480                 selection$$1.selectAll('.' + klass)
49481                     .each(function(entity) {
49482                         var i = z && icon(entity),
49483                             c = i ? 0.5 : 0,
49484                             r = rads[i ? 3 : z];
49485
49486                         // slightly increase the size of unconnected endpoints #3775
49487                         if (entity.isEndpoint(graph) && !entity.isConnected(graph)) {
49488                             r += 1.5;
49489                         }
49490
49491                         this.setAttribute('cx', c);
49492                         this.setAttribute('cy', -c);
49493                         this.setAttribute('r', r);
49494                         if (i && klass === 'fill') {
49495                             this.setAttribute('visibility', 'hidden');
49496                         } else {
49497                             this.removeAttribute('visibility');
49498                         }
49499                     });
49500             });
49501
49502             selection$$1.selectAll('use')
49503                 .each(function() {
49504                     if (z) {
49505                         this.removeAttribute('visibility');
49506                     } else {
49507                         this.setAttribute('visibility', 'hidden');
49508                     }
49509                 });
49510         }
49511
49512
49513         siblings$$1 = siblings$$1 || {};
49514
49515         var icons = {},
49516             z = (zoom$$1 < 17 ? 0 : zoom$$1 < 18 ? 1 : 2);
49517
49518         var groups = selection$$1
49519             .data(vertices, osmEntity$$1.key);
49520
49521         groups.exit()
49522             .remove();
49523
49524         var enter = groups.enter()
49525             .append('g')
49526             .attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });
49527
49528         enter.append('circle')
49529             .each(setClass('shadow'));
49530
49531         enter.append('circle')
49532             .each(setClass('stroke'));
49533
49534         // Vertices with icons get a `use`.
49535         enter.filter(function(d) { return icon(d); })
49536             .append('use')
49537             .attr('transform', 'translate(-5, -6)')
49538             .attr('xlink:href', function(d) {
49539                 var picon = icon(d),
49540                     isMaki = dataFeatureIcons.indexOf(picon) !== -1;
49541                 return '#' + picon + (isMaki ? '-11' : '');
49542             })
49543             .attr('width', '11px')
49544             .attr('height', '11px')
49545             .each(setClass('icon'));
49546
49547         // Vertices with tags get a fill.
49548         enter.filter(function(d) { return d.hasInterestingTags(); })
49549             .append('circle')
49550             .each(setClass('fill'));
49551
49552         groups
49553             .merge(enter)
49554             .attr('transform', svgPointTransform(projection$$1))
49555             .classed('sibling', function(entity) { return entity.id in siblings$$1; })
49556             .classed('shared', function(entity) { return graph.isShared(entity); })
49557             .classed('endpoint', function(entity) { return entity.isEndpoint(graph); })
49558             .call(setAttributes);
49559     }
49560
49561
49562     function drawVertices(selection$$1, graph, entities, filter, extent$$1, zoom$$1) {
49563         var siblings$$1 = siblingAndChildVertices(context.selectedIDs(), graph, extent$$1),
49564             wireframe = context.surface().classed('fill-wireframe'),
49565             vertices = [];
49566
49567         for (var i = 0; i < entities.length; i++) {
49568             var entity = entities[i],
49569                 geometry = entity.geometry(graph);
49570
49571             if (wireframe && geometry === 'point') {
49572                 vertices.push(entity);
49573                 continue;
49574             }
49575
49576             if (geometry !== 'vertex')
49577                 continue;
49578
49579             if (entity.id in siblings$$1 ||
49580                 entity.hasInterestingTags() ||
49581                 entity.isEndpoint(graph) ||
49582                 entity.isConnected(graph)) {
49583                 vertices.push(entity);
49584             }
49585         }
49586
49587         var layer = selection$$1.selectAll('.layer-hit');
49588         layer.selectAll('g.vertex.vertex-persistent')
49589             .filter(filter)
49590             .call(draw, vertices, 'vertex-persistent', graph, zoom$$1, siblings$$1);
49591
49592         drawHover(selection$$1, graph, extent$$1, zoom$$1);
49593     }
49594
49595
49596     function drawHover(selection$$1, graph, extent$$1, zoom$$1) {
49597         var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent$$1) : {};
49598         var layer = selection$$1.selectAll('.layer-hit');
49599
49600         layer.selectAll('g.vertex.vertex-hover')
49601             .call(draw, values(hovered), 'vertex-hover', graph, zoom$$1);
49602     }
49603
49604
49605     drawVertices.drawHover = function(selection$$1, graph, target, extent$$1, zoom$$1) {
49606         if (target === hover) return;
49607         hover = target;
49608         drawHover(selection$$1, graph, extent$$1, zoom$$1);
49609     };
49610
49611     return drawVertices;
49612 }
49613
49614 function behaviorEdit(context) {
49615
49616     function edit() {
49617         context.map()
49618             .minzoom(context.minEditableZoom());
49619     }
49620
49621
49622     edit.off = function() {
49623         context.map()
49624             .minzoom(0);
49625     };
49626
49627
49628     return edit;
49629 }
49630
49631 /*
49632    The hover behavior adds the `.hover` class on mouseover to all elements to which
49633    the identical datum is bound, and removes it on mouseout.
49634
49635    The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
49636    representation may consist of several elements scattered throughout the DOM hierarchy.
49637    Only one of these elements can have the :hover pseudo-class, but all of them will
49638    have the .hover class.
49639  */
49640 function behaviorHover(context) {
49641     var dispatch$$1 = dispatch('hover'),
49642         _selection = select(null),
49643         newId = null,
49644         buttonDown,
49645         altDisables,
49646         target;
49647
49648
49649     function keydown() {
49650         if (altDisables && event.keyCode === d3keybinding.modifierCodes.alt) {
49651             _selection.selectAll('.hover')
49652                 .classed('hover-suppressed', true)
49653                 .classed('hover', false);
49654
49655             _selection
49656                 .classed('hover-disabled', true);
49657
49658             dispatch$$1.call('hover', this, null);
49659         }
49660     }
49661
49662
49663     function keyup() {
49664         if (altDisables && event.keyCode === d3keybinding.modifierCodes.alt) {
49665             _selection.selectAll('.hover-suppressed')
49666                 .classed('hover-suppressed', false)
49667                 .classed('hover', true);
49668
49669             _selection
49670                 .classed('hover-disabled', false);
49671
49672             dispatch$$1.call('hover', this, target ? target.id : null);
49673         }
49674     }
49675
49676
49677     var hover = function(selection$$1) {
49678         _selection = selection$$1;
49679         newId = null;
49680
49681         _selection
49682             .on('mouseover.hover', mouseover)
49683             .on('mouseout.hover', mouseout)
49684             .on('mousedown.hover', mousedown);
49685
49686         select(window)
49687             .on('keydown.hover', keydown)
49688             .on('keyup.hover', keyup);
49689
49690
49691         function mouseover() {
49692             if (buttonDown) return;
49693             var target = event.target;
49694             enter(target ? target.__data__ : null);
49695         }
49696
49697
49698         function mouseout() {
49699             if (buttonDown) return;
49700             var target = event.relatedTarget;
49701             enter(target ? target.__data__ : null);
49702         }
49703
49704
49705         function mousedown() {
49706             buttonDown = true;
49707             select(window)
49708                 .on('mouseup.hover', mouseup, true);
49709         }
49710
49711
49712         function mouseup() {
49713             buttonDown = false;
49714             select(window)
49715                 .on('mouseup.hover', null, true);
49716         }
49717
49718
49719         function enter(d) {
49720             if (d === target) return;
49721             target = d;
49722
49723             _selection.selectAll('.hover')
49724                 .classed('hover', false);
49725             _selection.selectAll('.hover-suppressed')
49726                 .classed('hover-suppressed', false);
49727
49728             if (target instanceof osmEntity$$1 && target.id !== newId) {
49729
49730                 // If drawing a way, don't hover on a node that was just placed. #3974
49731                 var mode = context.mode() && context.mode().id;
49732                 if ((mode === 'draw-line' || mode === 'draw-area') && !newId && target.type === 'node') {
49733                     newId = target.id;
49734                     return;
49735                 }
49736
49737                 var selector$$1 = '.' + target.id;
49738
49739                 if (target.type === 'relation') {
49740                     target.members.forEach(function(member) {
49741                         selector$$1 += ', .' + member.id;
49742                     });
49743                 }
49744
49745                 var suppressed = altDisables && event && event.altKey;
49746
49747                 _selection.selectAll(selector$$1)
49748                     .classed(suppressed ? 'hover-suppressed' : 'hover', true);
49749
49750                 dispatch$$1.call('hover', this, !suppressed && target.id);
49751
49752             } else {
49753                 dispatch$$1.call('hover', this, null);
49754             }
49755         }
49756
49757     };
49758
49759
49760     hover.off = function(selection$$1) {
49761         selection$$1.selectAll('.hover')
49762             .classed('hover', false);
49763         selection$$1.selectAll('.hover-suppressed')
49764             .classed('hover-suppressed', false);
49765         selection$$1
49766             .classed('hover-disabled', false);
49767
49768
49769         selection$$1
49770             .on('mouseover.hover', null)
49771             .on('mouseout.hover', null)
49772             .on('mousedown.hover', null);
49773
49774         select(window)
49775             .on('keydown.hover', null)
49776             .on('keyup.hover', null);
49777     };
49778
49779
49780     hover.altDisables = function(_) {
49781         if (!arguments.length) return altDisables;
49782         altDisables = _;
49783         return hover;
49784     };
49785
49786
49787     return utilRebind(hover, dispatch$$1, 'on');
49788 }
49789
49790 function behaviorTail() {
49791     var text$$1,
49792         container,
49793         xmargin = 25,
49794         tooltipSize = [0, 0],
49795         selectionSize = [0, 0];
49796
49797
49798     function tail(selection$$1) {
49799         if (!text$$1) return;
49800
49801         select(window)
49802             .on('resize.tail', function() { selectionSize = utilGetDimensions(selection$$1); });
49803
49804         container = select(document.body)
49805             .append('div')
49806             .style('display', 'none')
49807             .attr('class', 'tail tooltip-inner');
49808
49809         container.append('div')
49810             .text(text$$1);
49811
49812         selection$$1
49813             .on('mousemove.tail', mousemove)
49814             .on('mouseenter.tail', mouseenter)
49815             .on('mouseleave.tail', mouseleave);
49816
49817         container
49818             .on('mousemove.tail', mousemove);
49819
49820         tooltipSize = utilGetDimensions(container);
49821         selectionSize = utilGetDimensions(selection$$1);
49822
49823
49824         function show() {
49825             container.style('display', 'block');
49826             tooltipSize = utilGetDimensions(container);
49827         }
49828
49829
49830         function mousemove() {
49831             if (container.style('display') === 'none') show();
49832             var xoffset = ((event.clientX + tooltipSize[0] + xmargin) > selectionSize[0]) ?
49833                 -tooltipSize[0] - xmargin : xmargin;
49834             container.classed('left', xoffset > 0);
49835             utilSetTransform(container, event.clientX + xoffset, event.clientY);
49836         }
49837
49838
49839         function mouseleave() {
49840             if (event.relatedTarget !== container.node()) {
49841                 container.style('display', 'none');
49842             }
49843         }
49844
49845
49846         function mouseenter() {
49847             if (event.relatedTarget !== container.node()) {
49848                 show();
49849             }
49850         }
49851     }
49852
49853
49854     tail.off = function(selection$$1) {
49855         if (!text$$1) return;
49856
49857         container
49858             .on('mousemove.tail', null)
49859             .remove();
49860
49861         selection$$1
49862             .on('mousemove.tail', null)
49863             .on('mouseenter.tail', null)
49864             .on('mouseleave.tail', null);
49865
49866         select(window)
49867             .on('resize.tail', null);
49868     };
49869
49870
49871     tail.text = function(_) {
49872         if (!arguments.length) return text$$1;
49873         text$$1 = _;
49874         return tail;
49875     };
49876
49877
49878     return tail;
49879 }
49880
49881 var usedTails = {};
49882 var disableSpace = false;
49883 var lastSpace = null;
49884
49885
49886 function behaviorDraw(context) {
49887     var dispatch$$1 = dispatch('move', 'click', 'clickWay',
49888             'clickNode', 'undo', 'cancel', 'finish'),
49889         keybinding = d3keybinding('draw'),
49890         hover = behaviorHover(context)
49891             .altDisables(true)
49892             .on('hover', context.ui().sidebar.hover),
49893         tail = behaviorTail(),
49894         edit = behaviorEdit(context),
49895         closeTolerance = 4,
49896         tolerance = 12,
49897         mouseLeave = false,
49898         lastMouse = null;
49899
49900
49901     function datum() {
49902         if (event.altKey) return {};
49903
49904         if (event.type === 'keydown') {
49905             return (lastMouse && lastMouse.target.__data__) || {};
49906         } else {
49907             return event.target.__data__ || {};
49908         }
49909     }
49910
49911
49912     function mousedown() {
49913
49914         function point() {
49915             var p = context.container().node();
49916             return touchId !== null ? touches(p).filter(function(p) {
49917                 return p.identifier === touchId;
49918             })[0] : mouse(p);
49919         }
49920
49921         var element = select(this),
49922             touchId = event.touches ? event.changedTouches[0].identifier : null,
49923             t1 = +new Date(),
49924             p1 = point();
49925
49926         element.on('mousemove.draw', null);
49927
49928         select(window).on('mouseup.draw', function() {
49929             var t2 = +new Date(),
49930                 p2 = point(),
49931                 dist = geoEuclideanDistance(p1, p2);
49932
49933             element.on('mousemove.draw', mousemove);
49934             select(window).on('mouseup.draw', null);
49935
49936             if (dist < closeTolerance || (dist < tolerance && (t2 - t1) < 500)) {
49937                 // Prevent a quick second click
49938                 select(window).on('click.draw-block', function() {
49939                     event.stopPropagation();
49940                 }, true);
49941
49942                 context.map().dblclickEnable(false);
49943
49944                 window.setTimeout(function() {
49945                     context.map().dblclickEnable(true);
49946                     select(window).on('click.draw-block', null);
49947                 }, 500);
49948
49949                 click();
49950             }
49951         }, true);
49952     }
49953
49954
49955     function mousemove() {
49956         lastMouse = event;
49957         dispatch$$1.call('move', this, datum());
49958     }
49959
49960
49961     function mouseenter() {
49962         mouseLeave = false;
49963     }
49964
49965
49966     function mouseleave() {
49967         mouseLeave = true;
49968     }
49969
49970
49971     function click() {
49972         var d = datum();
49973         if (d.type === 'way') {
49974             var dims = context.map().dimensions(),
49975                 mouse$$1 = context.mouse(),
49976                 pad = 5,
49977                 trySnap = mouse$$1[0] > pad && mouse$$1[0] < dims[0] - pad &&
49978                     mouse$$1[1] > pad && mouse$$1[1] < dims[1] - pad;
49979
49980             if (trySnap) {
49981                 var choice = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection),
49982                     edge = [d.nodes[choice.index - 1], d.nodes[choice.index]];
49983                 dispatch$$1.call('clickWay', this, choice.loc, edge);
49984             } else {
49985                 dispatch$$1.call('click', this, context.map().mouseCoordinates());
49986             }
49987
49988         } else if (d.type === 'node') {
49989             dispatch$$1.call('clickNode', this, d);
49990
49991         } else {
49992             dispatch$$1.call('click', this, context.map().mouseCoordinates());
49993         }
49994     }
49995
49996
49997     function space() {
49998         event.preventDefault();
49999         event.stopPropagation();
50000
50001         var currSpace = context.mouse();
50002         if (disableSpace && lastSpace) {
50003             var dist = geoEuclideanDistance(lastSpace, currSpace);
50004             if (dist > tolerance) {
50005                 disableSpace = false;
50006             }
50007         }
50008
50009         if (disableSpace || mouseLeave || !lastMouse) return;
50010
50011         // user must move mouse or release space bar to allow another click
50012         lastSpace = currSpace;
50013         disableSpace = true;
50014
50015         select(window).on('keyup.space-block', function() {
50016             event.preventDefault();
50017             event.stopPropagation();
50018             disableSpace = false;
50019             select(window).on('keyup.space-block', null);
50020         });
50021
50022         click();
50023     }
50024
50025
50026     function backspace() {
50027         event.preventDefault();
50028         dispatch$$1.call('undo');
50029     }
50030
50031
50032     function del() {
50033         event.preventDefault();
50034         dispatch$$1.call('cancel');
50035     }
50036
50037
50038     function ret() {
50039         event.preventDefault();
50040         dispatch$$1.call('finish');
50041     }
50042
50043
50044     function draw(selection$$1) {
50045         context.install(hover);
50046         context.install(edit);
50047
50048         if (!context.inIntro() && !usedTails[tail.text()]) {
50049             context.install(tail);
50050         }
50051
50052         keybinding
50053             .on('⌫', backspace)
50054             .on('⌦', del)
50055             .on('⎋', ret)
50056             .on('↩', ret)
50057             .on('space', space)
50058             .on('⌥space', space);
50059
50060         selection$$1
50061             .on('mouseenter.draw', mouseenter)
50062             .on('mouseleave.draw', mouseleave)
50063             .on('mousedown.draw', mousedown)
50064             .on('mousemove.draw', mousemove);
50065
50066         select(document)
50067             .call(keybinding);
50068
50069         return draw;
50070     }
50071
50072
50073     draw.off = function(selection$$1) {
50074         context.ui().sidebar.hover.cancel();
50075         context.uninstall(hover);
50076         context.uninstall(edit);
50077
50078         if (!context.inIntro() && !usedTails[tail.text()]) {
50079             context.uninstall(tail);
50080             usedTails[tail.text()] = true;
50081         }
50082
50083         selection$$1
50084             .on('mouseenter.draw', null)
50085             .on('mouseleave.draw', null)
50086             .on('mousedown.draw', null)
50087             .on('mousemove.draw', null);
50088
50089         select(window)
50090             .on('mouseup.draw', null);
50091             // note: keyup.space-block, click.draw-block should remain
50092
50093         select(document)
50094             .call(keybinding.off);
50095     };
50096
50097
50098     draw.tail = function(_) {
50099         tail.text(_);
50100         return draw;
50101     };
50102
50103
50104     return utilRebind(draw, dispatch$$1, 'on');
50105 }
50106
50107 function behaviorAddWay(context) {
50108     var dispatch$$1 = dispatch('start', 'startFromWay', 'startFromNode'),
50109         draw = behaviorDraw(context);
50110
50111     var addWay = function(surface) {
50112         draw.on('click', function() { dispatch$$1.apply('start', this, arguments); })
50113             .on('clickWay', function() { dispatch$$1.apply('startFromWay', this, arguments); })
50114             .on('clickNode', function() { dispatch$$1.apply('startFromNode', this, arguments); })
50115             .on('cancel', addWay.cancel)
50116             .on('finish', addWay.cancel);
50117
50118         context.map()
50119             .dblclickEnable(false);
50120
50121         surface.call(draw);
50122     };
50123
50124
50125     addWay.off = function(surface) {
50126         surface.call(draw.off);
50127     };
50128
50129
50130     addWay.cancel = function() {
50131         window.setTimeout(function() {
50132             context.map().dblclickEnable(true);
50133         }, 1000);
50134
50135         context.enter(modeBrowse(context));
50136     };
50137
50138
50139     addWay.tail = function(text$$1) {
50140         draw.tail(text$$1);
50141         return addWay;
50142     };
50143
50144
50145     return utilRebind(addWay, dispatch$$1, 'on');
50146 }
50147
50148 function behaviorBreathe() {
50149     var duration = 800,
50150         steps = 4,
50151         selector$$1 = '.selected.shadow, .selected .shadow',
50152         selected = select(null),
50153         classed = '',
50154         params = {},
50155         done = false,
50156         timer$$1;
50157
50158
50159     function ratchetyInterpolator(a, b, steps, units) {
50160         a = parseFloat(a);
50161         b = parseFloat(b);
50162         var sample = quantize$1()
50163             .domain([0, 1])
50164             .range(quantize(reinterpolate(a, b), steps));
50165
50166         return function(t) {
50167             return String(sample(t)) + (units || '');
50168         };
50169     }
50170
50171
50172     function reset(selection$$1) {
50173         selection$$1
50174             .style('stroke-opacity', null)
50175             .style('stroke-width', null)
50176             .style('fill-opacity', null)
50177             .style('r', null);
50178     }
50179
50180
50181     function setAnimationParams(transition$$1, fromTo) {
50182         var toFrom = (fromTo === 'from' ? 'to' : 'from');
50183
50184         transition$$1
50185             .styleTween('stroke-opacity', function(d) {
50186                 return ratchetyInterpolator(
50187                     params[d.id][toFrom].opacity,
50188                     params[d.id][fromTo].opacity,
50189                     steps
50190                 );
50191             })
50192             .styleTween('stroke-width', function(d) {
50193                 return ratchetyInterpolator(
50194                     params[d.id][toFrom].width,
50195                     params[d.id][fromTo].width,
50196                     steps,
50197                     'px'
50198                 );
50199             })
50200             .styleTween('fill-opacity', function(d) {
50201                 return ratchetyInterpolator(
50202                     params[d.id][toFrom].opacity,
50203                     params[d.id][fromTo].opacity,
50204                     steps
50205                 );
50206             })
50207             .styleTween('r', function(d) {
50208                 return ratchetyInterpolator(
50209                     params[d.id][toFrom].width,
50210                     params[d.id][fromTo].width,
50211                     steps,
50212                     'px'
50213                 );
50214             });
50215     }
50216
50217
50218     function calcAnimationParams(selection$$1) {
50219         selection$$1
50220             .call(reset)
50221             .each(function(d) {
50222                 var s = select(this),
50223                     tag = s.node().tagName,
50224                     p = {'from': {}, 'to': {}},
50225                     opacity, width;
50226
50227                 // determine base opacity and width
50228                 if (tag === 'circle') {
50229                     opacity = parseFloat(s.style('fill-opacity') || 0.5);
50230                     width = parseFloat(s.style('r') || 15.5);
50231                 } else {
50232                     opacity = parseFloat(s.style('stroke-opacity') || 0.7);
50233                     width = parseFloat(s.style('stroke-width') || 10);
50234                 }
50235
50236                 // calculate from/to interpolation params..
50237                 p.tag = tag;
50238                 p.from.opacity = opacity * 0.6;
50239                 p.to.opacity = opacity * 1.25;
50240                 p.from.width = width * 0.7;
50241                 p.to.width = width * (tag === 'circle' ? 1.5 : 1);
50242                 params[d.id] = p;
50243             });
50244     }
50245
50246
50247     function run(surface, fromTo) {
50248         var toFrom = (fromTo === 'from' ? 'to' : 'from'),
50249             currSelected = surface.selectAll(selector$$1),
50250             currClassed = surface.attr('class');
50251
50252         if (done || currSelected.empty()) {
50253             selected.call(reset);
50254             return;
50255         }
50256
50257         if (!lodash.isEqual(currSelected.data(), selected.data()) || currClassed !== classed) {
50258             selected.call(reset);
50259             classed = currClassed;
50260             selected = currSelected.call(calcAnimationParams);
50261         }
50262
50263         selected
50264             .transition()
50265             .duration(duration)
50266             .call(setAnimationParams, fromTo)
50267             .on('end', function() {
50268                 surface.call(run, toFrom);
50269             });
50270     }
50271
50272
50273     var breathe = function(surface) {
50274         done = false;
50275         timer$$1 = timer(function() {
50276             // wait for elements to actually become selected
50277             if (surface.selectAll(selector$$1).empty()) {
50278                 return false;
50279             }
50280
50281             surface.call(run, 'from');
50282             timer$$1.stop();
50283             return true;
50284         }, 20);
50285     };
50286
50287
50288     breathe.off = function() {
50289         done = true;
50290         if (timer$$1) {
50291             timer$$1.stop();
50292         }
50293         selected
50294             .interrupt()
50295             .call(reset);
50296     };
50297
50298
50299     return breathe;
50300 }
50301
50302 function behaviorCopy(context) {
50303     var keybinding = d3keybinding('copy');
50304
50305
50306     function groupEntities(ids, graph) {
50307         var entities = ids.map(function (id) { return graph.entity(id); });
50308         return lodash.extend({relation: [], way: [], node: []},
50309             lodash.groupBy(entities, function(entity) { return entity.type; }));
50310     }
50311
50312
50313     function getDescendants(id, graph, descendants) {
50314         var entity = graph.entity(id),
50315             i, children;
50316
50317         descendants = descendants || {};
50318
50319         if (entity.type === 'relation') {
50320             children = lodash.map(entity.members, 'id');
50321         } else if (entity.type === 'way') {
50322             children = entity.nodes;
50323         } else {
50324             children = [];
50325         }
50326
50327         for (i = 0; i < children.length; i++) {
50328             if (!descendants[children[i]]) {
50329                 descendants[children[i]] = true;
50330                 descendants = getDescendants(children[i], graph, descendants);
50331             }
50332         }
50333
50334         return descendants;
50335     }
50336
50337
50338     function doCopy() {
50339         event.preventDefault();
50340
50341         var graph = context.graph(),
50342             selected = groupEntities(context.selectedIDs(), graph),
50343             canCopy = [],
50344             skip = {},
50345             i, entity;
50346
50347         for (i = 0; i < selected.relation.length; i++) {
50348             entity = selected.relation[i];
50349             if (!skip[entity.id] && entity.isComplete(graph)) {
50350                 canCopy.push(entity.id);
50351                 skip = getDescendants(entity.id, graph, skip);
50352             }
50353         }
50354         for (i = 0; i < selected.way.length; i++) {
50355             entity = selected.way[i];
50356             if (!skip[entity.id]) {
50357                 canCopy.push(entity.id);
50358                 skip = getDescendants(entity.id, graph, skip);
50359             }
50360         }
50361         for (i = 0; i < selected.node.length; i++) {
50362             entity = selected.node[i];
50363             if (!skip[entity.id]) {
50364                 canCopy.push(entity.id);
50365             }
50366         }
50367
50368         context.copyIDs(canCopy);
50369     }
50370
50371
50372     function copy() {
50373         keybinding.on(uiCmd('⌘C'), doCopy);
50374         select(document).call(keybinding);
50375         return copy;
50376     }
50377
50378
50379     copy.off = function() {
50380         select(document).call(keybinding.off);
50381     };
50382
50383
50384     return copy;
50385 }
50386
50387 /*
50388     `behaviorDrag` is like `d3.behavior.drag`, with the following differences:
50389
50390     * The `origin` function is expected to return an [x, y] tuple rather than an
50391       {x, y} object.
50392     * The events are `start`, `move`, and `end`.
50393       (https://github.com/mbostock/d3/issues/563)
50394     * The `start` event is not dispatched until the first cursor movement occurs.
50395       (https://github.com/mbostock/d3/pull/368)
50396     * The `move` event has a `point` and `delta` [x, y] tuple properties rather
50397       than `x`, `y`, `dx`, and `dy` properties.
50398     * The `end` event is not dispatched if no movement occurs.
50399     * An `off` function is available that unbinds the drag's internal event handlers.
50400  */
50401
50402 function behaviorDrag() {
50403     var event$$1 = dispatch('start', 'move', 'end'),
50404         origin = null,
50405         selector$$1 = '',
50406         filter = null,
50407         event_, target, surface;
50408
50409
50410     var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect'),
50411         d3_event_userSelectSuppress = function() {
50412             var selection$$1 = selection(),
50413                 select$$1 = selection$$1.style(d3_event_userSelectProperty);
50414             selection$$1.style(d3_event_userSelectProperty, 'none');
50415             return function() {
50416                 selection$$1.style(d3_event_userSelectProperty, select$$1);
50417             };
50418         };
50419
50420
50421     function d3_eventCancel() {
50422         event.stopPropagation();
50423         event.preventDefault();
50424     }
50425
50426
50427     function eventOf(thiz, argumentz) {
50428         return function(e1) {
50429             e1.target = drag$$1;
50430             customEvent(e1, event$$1.apply, event$$1, [e1.type, thiz, argumentz]);
50431         };
50432     }
50433
50434
50435     function dragstart() {
50436         target = this;
50437         event_ = eventOf(target, arguments);
50438
50439         var eventTarget = event.target,
50440             touchId = event.touches ? event.changedTouches[0].identifier : null,
50441             offset,
50442             origin_ = point(),
50443             started = false,
50444             selectEnable = d3_event_userSelectSuppress(touchId !== null ? 'drag-' + touchId : 'drag');
50445
50446         select(window)
50447             .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', dragmove)
50448             .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', dragend, true);
50449
50450         if (origin) {
50451             offset = origin.apply(target, arguments);
50452             offset = [offset[0] - origin_[0], offset[1] - origin_[1]];
50453         } else {
50454             offset = [0, 0];
50455         }
50456
50457         if (touchId === null) {
50458             event.stopPropagation();
50459         }
50460
50461
50462         function point() {
50463             var p = surface || target.parentNode;
50464             return touchId !== null ? touches(p).filter(function(p) {
50465                 return p.identifier === touchId;
50466             })[0] : mouse(p);
50467         }
50468
50469
50470         function dragmove() {
50471             var p = point(),
50472                 dx = p[0] - origin_[0],
50473                 dy = p[1] - origin_[1];
50474
50475             if (dx === 0 && dy === 0)
50476                 return;
50477
50478             if (!started) {
50479                 started = true;
50480                 event_({ type: 'start' });
50481             }
50482
50483             origin_ = p;
50484             d3_eventCancel();
50485
50486             event_({
50487                 type: 'move',
50488                 point: [p[0] + offset[0],  p[1] + offset[1]],
50489                 delta: [dx, dy]
50490             });
50491         }
50492
50493
50494         function dragend() {
50495             if (started) {
50496                 event_({ type: 'end' });
50497
50498                 d3_eventCancel();
50499                 if (event.target === eventTarget) {
50500                     select(window)
50501                         .on('click.drag', click, true);
50502                 }
50503             }
50504
50505             select(window)
50506                 .on(touchId !== null ? 'touchmove.drag-' + touchId : 'mousemove.drag', null)
50507                 .on(touchId !== null ? 'touchend.drag-' + touchId : 'mouseup.drag', null);
50508
50509             selectEnable();
50510         }
50511
50512
50513         function click() {
50514             d3_eventCancel();
50515             select(window)
50516                 .on('click.drag', null);
50517         }
50518     }
50519
50520
50521     function drag$$1(selection$$1) {
50522         var matchesSelector = utilPrefixDOMProperty('matchesSelector'),
50523             delegate = dragstart;
50524
50525         if (selector$$1) {
50526             delegate = function() {
50527                 var root = this,
50528                     target = event.target;
50529                 for (; target && target !== root; target = target.parentNode) {
50530                     if (target[matchesSelector](selector$$1) &&
50531                             (!filter || filter(target.__data__))) {
50532                         return dragstart.call(target, target.__data__);
50533                     }
50534                 }
50535             };
50536         }
50537
50538         selection$$1
50539             .on('mousedown.drag' + selector$$1, delegate)
50540             .on('touchstart.drag' + selector$$1, delegate);
50541     }
50542
50543
50544     drag$$1.off = function(selection$$1) {
50545         selection$$1
50546             .on('mousedown.drag' + selector$$1, null)
50547             .on('touchstart.drag' + selector$$1, null);
50548     };
50549
50550
50551     drag$$1.selector = function(_) {
50552         if (!arguments.length) return selector$$1;
50553         selector$$1 = _;
50554         return drag$$1;
50555     };
50556
50557
50558     drag$$1.filter = function(_) {
50559         if (!arguments.length) return origin;
50560         filter = _;
50561         return drag$$1;
50562     };
50563
50564
50565     drag$$1.origin = function (_) {
50566         if (!arguments.length) return origin;
50567         origin = _;
50568         return drag$$1;
50569     };
50570
50571
50572     drag$$1.cancel = function() {
50573         select(window)
50574             .on('mousemove.drag', null)
50575             .on('mouseup.drag', null);
50576         return drag$$1;
50577     };
50578
50579
50580     drag$$1.target = function() {
50581         if (!arguments.length) return target;
50582         target = arguments[0];
50583         event_ = eventOf(target, Array.prototype.slice.call(arguments, 1));
50584         return drag$$1;
50585     };
50586
50587
50588     drag$$1.surface = function() {
50589         if (!arguments.length) return surface;
50590         surface = arguments[0];
50591         return drag$$1;
50592     };
50593
50594
50595     return utilRebind(drag$$1, event$$1, 'on');
50596 }
50597
50598 function behaviorDrawWay(context, wayId, index, mode, startGraph) {
50599
50600     var origWay = context.entity(wayId),
50601         isArea = context.geometry(wayId) === 'area',
50602         tempEdits = 0,
50603         annotation = t((origWay.isDegenerate() ?
50604             'operations.start.annotation.' :
50605             'operations.continue.annotation.') + context.geometry(wayId)),
50606         draw = behaviorDraw(context),
50607         startIndex,
50608         start,
50609         end,
50610         segment;
50611
50612
50613     // initialize the temporary drawing entities
50614     if (!isArea) {
50615         startIndex = typeof index === 'undefined' ? origWay.nodes.length - 1 : 0;
50616         start = osmNode({ id: 'nStart', loc: context.entity(origWay.nodes[startIndex]).loc });
50617         end = osmNode({ id: 'nEnd', loc: context.map().mouseCoordinates() });
50618         segment = osmWay({ id: 'wTemp',
50619             nodes: typeof index === 'undefined' ? [start.id, end.id] : [end.id, start.id],
50620             tags: lodash.clone(origWay.tags)
50621         });
50622     } else {
50623         end = osmNode({ loc: context.map().mouseCoordinates() });
50624     }
50625
50626     // Push an annotated state for undo to return back to.
50627     // We must make sure to remove this edit later.
50628     context.perform(actionNoop(), annotation);
50629     tempEdits++;
50630
50631     // Add the temporary drawing entities to the graph.
50632     // We must make sure to remove this edit later.
50633     context.perform(AddDrawEntities());
50634     tempEdits++;
50635
50636
50637     function move(datum) {
50638         var loc;
50639
50640         if (datum.type === 'node' && datum.id !== end.id) {
50641             loc = datum.loc;
50642
50643         } else if (datum.type === 'way') {
50644             var dims = context.map().dimensions(),
50645                 mouse = context.mouse(),
50646                 pad = 5,
50647                 trySnap = mouse[0] > pad && mouse[0] < dims[0] - pad &&
50648                     mouse[1] > pad && mouse[1] < dims[1] - pad;
50649
50650             if (trySnap) {
50651                 loc = geoChooseEdge(context.childNodes(datum), context.mouse(), context.projection).loc;
50652             }
50653         }
50654
50655         if (!loc) {
50656             loc = context.map().mouseCoordinates();
50657         }
50658
50659         context.replace(actionMoveNode(end.id, loc));
50660         end = context.entity(end.id);
50661     }
50662
50663
50664     function undone() {
50665         // Undo popped the history back to the initial annotated no-op edit.
50666         // Remove initial no-op edit and whatever edit happened immediately before it.
50667         context.pop(2);
50668         tempEdits = 0;
50669
50670         if (context.hasEntity(wayId)) {
50671             context.enter(mode);
50672         } else {
50673             context.enter(modeBrowse(context));
50674         }
50675     }
50676
50677
50678     function setActiveElements() {
50679         var active = isArea ? [wayId, end.id] : [segment.id, start.id, end.id];
50680         context.surface().selectAll(utilEntitySelector(active))
50681             .classed('active', true);
50682     }
50683
50684
50685     var drawWay = function(surface) {
50686         draw.on('move', move)
50687             .on('click', drawWay.add)
50688             .on('clickWay', drawWay.addWay)
50689             .on('clickNode', drawWay.addNode)
50690             .on('undo', context.undo)
50691             .on('cancel', drawWay.cancel)
50692             .on('finish', drawWay.finish);
50693
50694         context.map()
50695             .dblclickEnable(false)
50696             .on('drawn.draw', setActiveElements);
50697
50698         setActiveElements();
50699
50700         surface.call(draw);
50701
50702         context.history()
50703             .on('undone.draw', undone);
50704     };
50705
50706
50707     drawWay.off = function(surface) {
50708         // Drawing was interrupted unexpectedly.
50709         // This can happen if the user changes modes,
50710         // clicks geolocate button, a hashchange event occurs, etc.
50711         if (tempEdits) {
50712             context.pop(tempEdits);
50713             while (context.graph() !== startGraph) {
50714                 context.pop();
50715             }
50716         }
50717
50718         context.map()
50719             .on('drawn.draw', null);
50720
50721         surface.call(draw.off)
50722             .selectAll('.active')
50723             .classed('active', false);
50724
50725         context.history()
50726             .on('undone.draw', null);
50727     };
50728
50729
50730     function AddDrawEntities() {
50731         return function(graph) {
50732             if (isArea) {
50733                 // For area drawing, there is no need for a temporary node.
50734                 // `end` gets inserted into the way as the penultimate node.
50735                 return graph
50736                     .replace(end)
50737                     .replace(origWay.addNode(end.id));
50738             } else {
50739                 // For line drawing, add a temporary start, end, and segment to the graph.
50740                 // This allows us to class the new segment as `active`, but still
50741                 // connect it back to parts of the way that have already been drawn.
50742                 return graph
50743                     .replace(start)
50744                     .replace(end)
50745                     .replace(segment);
50746             }
50747         };
50748     }
50749
50750
50751     function ReplaceDrawEntities(newNode) {
50752         return function(graph) {
50753             if (isArea) {
50754                 // For area drawing, we didn't create a temporary node.
50755                 // `newNode` gets inserted into the _original_ way as the penultimate node.
50756                 return graph
50757                     .replace(origWay.addNode(newNode.id))
50758                     .remove(end);
50759             } else {
50760                 // For line drawing, add the `newNode` to the way at specified index,
50761                 // and remove the temporary start, end, and segment.
50762                 return graph
50763                     .replace(origWay.addNode(newNode.id, index))
50764                     .remove(end)
50765                     .remove(segment)
50766                     .remove(start);
50767             }
50768         };
50769     }
50770
50771
50772     // Accept the current position of the temporary node and continue drawing.
50773     drawWay.add = function(loc) {
50774         // prevent duplicate nodes
50775         var last = context.hasEntity(origWay.nodes[origWay.nodes.length - (isArea ? 2 : 1)]);
50776         if (last && last.loc[0] === loc[0] && last.loc[1] === loc[1]) return;
50777
50778         context.pop(tempEdits);
50779
50780         if (isArea) {
50781             context.perform(
50782                 AddDrawEntities(),
50783                 annotation
50784             );
50785         } else {
50786             var newNode = osmNode({loc: loc});
50787             context.perform(
50788                 actionAddEntity(newNode),
50789                 ReplaceDrawEntities(newNode),
50790                 annotation
50791             );
50792         }
50793
50794         tempEdits = 0;
50795         context.enter(mode);
50796     };
50797
50798
50799     // Connect the way to an existing way.
50800     drawWay.addWay = function(loc, edge) {
50801         if (isArea) {
50802             context.pop(tempEdits);
50803
50804             context.perform(
50805                 AddDrawEntities(),
50806                 actionAddMidpoint({ loc: loc, edge: edge}, end),
50807                 annotation
50808             );
50809         } else {
50810             var previousEdge = startIndex ?
50811                 [origWay.nodes[startIndex], origWay.nodes[startIndex - 1]] :
50812                 [origWay.nodes[0], origWay.nodes[1]];
50813
50814             // Avoid creating duplicate segments
50815             if (geoEdgeEqual(edge, previousEdge))
50816                 return;
50817
50818             context.pop(tempEdits);
50819
50820             var newNode = osmNode({ loc: loc });
50821             context.perform(
50822                 actionAddMidpoint({ loc: loc, edge: edge}, newNode),
50823                 ReplaceDrawEntities(newNode),
50824                 annotation
50825             );
50826         }
50827
50828         tempEdits = 0;
50829         context.enter(mode);
50830     };
50831
50832
50833     // Connect the way to an existing node and continue drawing.
50834     drawWay.addNode = function(node) {
50835         // Avoid creating duplicate segments
50836         if (origWay.areAdjacent(node.id, origWay.nodes[origWay.nodes.length - 1])) return;
50837
50838         // Clicks should not occur on the drawing node, however a space keypress can
50839         // sometimes grab that node's datum (before it gets classed as `active`?)  #4016
50840         if (node.id === end.id) {
50841             drawWay.add(node.loc);
50842             return;
50843         }
50844
50845         context.pop(tempEdits);
50846
50847         context.perform(
50848             ReplaceDrawEntities(node),
50849             annotation
50850         );
50851
50852         tempEdits = 0;
50853         context.enter(mode);
50854     };
50855
50856
50857     // Finish the draw operation, removing the temporary edits.
50858     // If the way has enough nodes to be valid, it's selected.
50859     // Otherwise, delete everything and return to browse mode.
50860     drawWay.finish = function() {
50861         context.pop(tempEdits);
50862         tempEdits = 0;
50863
50864         var way = context.hasEntity(wayId);
50865         if (!way || way.isDegenerate()) {
50866             drawWay.cancel();
50867             return;
50868         }
50869
50870         window.setTimeout(function() {
50871             context.map().dblclickEnable(true);
50872         }, 1000);
50873
50874         context.enter(modeSelect(context, [wayId]).newFeature(true));
50875     };
50876
50877
50878     // Cancel the draw operation, delete everything, and return to browse mode.
50879     drawWay.cancel = function() {
50880         context.pop(tempEdits);
50881         tempEdits = 0;
50882
50883         while (context.graph() !== startGraph) {
50884             context.pop();
50885         }
50886
50887         window.setTimeout(function() {
50888             context.map().dblclickEnable(true);
50889         }, 1000);
50890
50891         context.enter(modeBrowse(context));
50892     };
50893
50894
50895     drawWay.tail = function(text) {
50896         draw.tail(text);
50897         return drawWay;
50898     };
50899
50900
50901     return drawWay;
50902 }
50903
50904 function behaviorHash(context) {
50905     var s0 = null, // cached window.location.hash
50906         lat = 90 - 1e-8; // allowable latitude range
50907
50908
50909     var parser = function(map, s) {
50910         var q = utilStringQs(s);
50911         var args = (q.map || '').split('/').map(Number);
50912
50913         if (args.length < 3 || args.some(isNaN)) {
50914             return true; // replace bogus hash
50915
50916         } else if (s !== formatter(map).slice(1)) {   // hash has changed
50917             var mode = context.mode(),
50918                 dist = geoSphericalDistance(map.center(), [args[2], args[1]]),
50919                 maxdist = 500;
50920
50921             // Don't allow the hash location to change too much while drawing
50922             // This can happen if the user accidently hit the back button.  #3996
50923             if (mode && mode.id.match(/^draw/) !== null && dist > maxdist) {
50924                 context.enter(modeBrowse(context));
50925             }
50926
50927             map.centerZoom([args[2], Math.min(lat, Math.max(-lat, args[1]))], args[0]);
50928         }
50929     };
50930
50931
50932     var formatter = function(map) {
50933         var center = map.center(),
50934             zoom$$1 = map.zoom(),
50935             precision = Math.max(0, Math.ceil(Math.log(zoom$$1) / Math.LN2)),
50936             q = lodash.omit(utilStringQs(window.location.hash.substring(1)), 'comment'),
50937             newParams = {};
50938
50939         delete q.id;
50940         var selected = context.selectedIDs().filter(function(id) {
50941             return !context.entity(id).isNew();
50942         });
50943         if (selected.length) {
50944             newParams.id = selected.join(',');
50945         }
50946
50947         newParams.map = zoom$$1.toFixed(2) +
50948             '/' + center[1].toFixed(precision) +
50949             '/' + center[0].toFixed(precision);
50950
50951         return '#' + utilQsString(lodash.assign(q, newParams), true);
50952     };
50953
50954
50955     function update() {
50956         if (context.inIntro()) return;
50957         var s1 = formatter(context.map());
50958         if (s0 !== s1) {
50959             window.location.replace(s0 = s1);  // don't recenter the map!
50960         }
50961     }
50962
50963
50964     var throttledUpdate = lodash.throttle(update, 500);
50965
50966
50967     function hashchange() {
50968         if (window.location.hash === s0) return;  // ignore spurious hashchange events
50969         if (parser(context.map(), (s0 = window.location.hash).substring(1))) {
50970             update(); // replace bogus hash
50971         }
50972     }
50973
50974
50975     function hash() {
50976         context.map()
50977             .on('move.hash', throttledUpdate);
50978
50979         context
50980             .on('enter.hash', throttledUpdate);
50981
50982         select(window)
50983             .on('hashchange.hash', hashchange);
50984
50985         if (window.location.hash) {
50986             var q = utilStringQs(window.location.hash.substring(1));
50987             if (q.id) {
50988                 context.zoomToEntity(q.id.split(',')[0], !q.map);
50989             }
50990             if (q.comment) {
50991                 context.storage('comment', q.comment);
50992                 context.storage('commentDate', Date.now());
50993             }
50994             hashchange();
50995             if (q.map) hash.hadHash = true;
50996         }
50997     }
50998
50999
51000     hash.off = function() {
51001         throttledUpdate.cancel();
51002
51003         context.map()
51004             .on('move.hash', null);
51005
51006         context
51007             .on('enter.hash', null);
51008
51009         select(window)
51010             .on('hashchange.hash', null);
51011
51012         window.location.hash = '';
51013     };
51014
51015
51016     return hash;
51017 }
51018
51019 function behaviorLasso(context) {
51020
51021     var behavior = function(selection$$1) {
51022         var lasso;
51023
51024
51025         function mousedown() {
51026             var button = 0;  // left
51027             if (event.button === button && event.shiftKey === true) {
51028                 lasso = null;
51029
51030                 select(window)
51031                     .on('mousemove.lasso', mousemove)
51032                     .on('mouseup.lasso', mouseup);
51033
51034                 event.stopPropagation();
51035             }
51036         }
51037
51038
51039         function mousemove() {
51040             if (!lasso) {
51041                 lasso = uiLasso(context);
51042                 context.surface().call(lasso);
51043             }
51044
51045             lasso.p(context.mouse());
51046         }
51047
51048
51049         function normalize(a, b) {
51050             return [
51051                 [Math.min(a[0], b[0]), Math.min(a[1], b[1])],
51052                 [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
51053         }
51054
51055
51056         function lassoed() {
51057             if (!lasso) return [];
51058
51059             var graph = context.graph(),
51060                 bounds$$1 = lasso.extent().map(context.projection.invert),
51061                 extent$$1 = geoExtent$$1(normalize(bounds$$1[0], bounds$$1[1]));
51062
51063             return lodash.map(context.intersects(extent$$1).filter(function(entity) {
51064                 return entity.type === 'node' &&
51065                     geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) &&
51066                     !context.features().isHidden(entity, graph, entity.geometry(graph));
51067             }), 'id');
51068         }
51069
51070
51071         function mouseup() {
51072             select(window)
51073                 .on('mousemove.lasso', null)
51074                 .on('mouseup.lasso', null);
51075
51076             if (!lasso) return;
51077
51078             var ids = lassoed();
51079             lasso.close();
51080
51081             if (ids.length) {
51082                 context.enter(modeSelect(context, ids));
51083             }
51084         }
51085
51086         selection$$1
51087             .on('mousedown.lasso', mousedown);
51088     };
51089
51090
51091     behavior.off = function(selection$$1) {
51092         selection$$1.on('mousedown.lasso', null);
51093     };
51094
51095
51096     return behavior;
51097 }
51098
51099 /* Creates a keybinding behavior for an operation */
51100 function behaviorOperation() {
51101     var which, keybinding;
51102
51103
51104     function drawIcon(selection$$1) {
51105         var button = selection$$1
51106             .append('svg')
51107             .attr('class', 'operation-icon')
51108             .append('g')
51109             .attr('class', 'radial-menu-item radial-menu-item-' + which.id)
51110             .attr('transform', 'translate(10,10)')
51111             .classed('disabled', which.disabled());
51112
51113         button
51114             .append('circle')
51115             .attr('r', 9);
51116
51117         button
51118             .append('use')
51119             .attr('transform', 'translate(-7,-7)')
51120             .attr('width', '14')
51121             .attr('height', '14')
51122             .attr('xlink:href', '#operation-' + which.id);
51123
51124         return selection$$1;
51125     }
51126
51127
51128     var behavior = function () {
51129         if (which && which.available()) {
51130             keybinding = d3keybinding('behavior.key.' + which.id);
51131             keybinding.on(which.keys, function() {
51132                 event.preventDefault();
51133                 var disabled = which.disabled();
51134
51135                 if (disabled) {
51136                     uiFlash(3000)
51137                         .html('')
51138                         .call(drawIcon)
51139                         .append('div')
51140                         .attr('class', 'operation-tip')
51141                         .text(which.tooltip);
51142
51143                 } else {
51144                     uiFlash(1500)
51145                         .html('')
51146                         .call(drawIcon)
51147                         .append('div')
51148                         .attr('class', 'operation-tip')
51149                         .text(which.annotation() || which.title);
51150
51151                     which();
51152                 }
51153             });
51154             select(document).call(keybinding);
51155         }
51156         return behavior;
51157     };
51158
51159
51160     behavior.off = function() {
51161         if (keybinding) {
51162             select(document).call(keybinding.off);
51163         }
51164     };
51165
51166
51167     behavior.which = function (_) {
51168         if (!arguments.length) return which;
51169         which = _;
51170         return behavior;
51171     };
51172
51173
51174     return behavior;
51175 }
51176
51177 function behaviorPaste(context) {
51178     var keybinding = d3keybinding('paste');
51179
51180
51181     function doPaste() {
51182         event.preventDefault();
51183
51184         var baseGraph = context.graph(),
51185             mouse$$1 = context.mouse(),
51186             projection$$1 = context.projection,
51187             viewport = geoExtent$$1(projection$$1.clipExtent()).polygon();
51188
51189         if (!geoPointInPolygon(mouse$$1, viewport)) return;
51190
51191         var extent$$1 = geoExtent$$1(),
51192             oldIDs = context.copyIDs(),
51193             oldGraph = context.copyGraph(),
51194             newIDs = [];
51195
51196         if (!oldIDs.length) return;
51197
51198         var action = actionCopyEntities(oldIDs, oldGraph);
51199         context.perform(action);
51200
51201         var copies = action.copies();
51202         var originals = lodash.invert(lodash.mapValues(copies, 'id'));
51203         for (var id in copies) {
51204             var oldEntity = oldGraph.entity(id),
51205                 newEntity = copies[id];
51206
51207             extent$$1._extend(oldEntity.extent(oldGraph));
51208
51209             // Exclude child nodes from newIDs if their parent way was also copied.
51210             var parents = context.graph().parentWays(newEntity),
51211                 parentCopied = false;
51212             for (var i = 0; i < parents.length; i++) {
51213                 if (originals[parents[i].id]) {
51214                     parentCopied = true;
51215                     break;
51216                 }
51217             }
51218
51219             if (!parentCopied) {
51220                 newIDs.push(newEntity.id);
51221             }
51222         }
51223
51224         // Put pasted objects where mouse pointer is..
51225         var center = projection$$1(extent$$1.center()),
51226             delta = [ mouse$$1[0] - center[0], mouse$$1[1] - center[1] ];
51227
51228         context.perform(actionMove(newIDs, delta, projection$$1));
51229         context.enter(modeMove$$1(context, newIDs, baseGraph));
51230     }
51231
51232
51233     function paste() {
51234         keybinding.on(uiCmd('⌘V'), doPaste);
51235         select(document).call(keybinding);
51236         return paste;
51237     }
51238
51239
51240     paste.off = function() {
51241         select(document).call(keybinding.off);
51242     };
51243
51244
51245     return paste;
51246 }
51247
51248 function behaviorSelect(context) {
51249     var lastMouse = null,
51250         suppressMenu = true,
51251         tolerance = 4,
51252         p1 = null;
51253
51254
51255     function point() {
51256         return mouse(context.container().node());
51257     }
51258
51259
51260     function keydown() {
51261         var e = event;
51262         if (e && e.shiftKey) {
51263             context.surface()
51264                 .classed('behavior-multiselect', true);
51265         }
51266
51267         if (e && e.keyCode === 93) {  // context menu
51268             e.preventDefault();
51269             e.stopPropagation();
51270         }
51271     }
51272
51273
51274     function keyup() {
51275         var e = event;
51276         if (!e || !e.shiftKey) {
51277             context.surface()
51278                 .classed('behavior-multiselect', false);
51279         }
51280
51281
51282         if (e && e.keyCode === 93) {  // context menu
51283             e.preventDefault();
51284             e.stopPropagation();
51285             contextmenu();
51286         }
51287     }
51288
51289
51290     function mousedown() {
51291         if (!p1) p1 = point();
51292         select(window)
51293             .on('mouseup.select', mouseup, true);
51294
51295         var isShowAlways = +context.storage('edit-menu-show-always') === 1;
51296         suppressMenu = !isShowAlways;
51297     }
51298
51299
51300     function mousemove() {
51301         if (event) lastMouse = event;
51302     }
51303
51304
51305     function mouseup() {
51306         click();
51307     }
51308
51309
51310     function contextmenu() {
51311         var e = event;
51312         e.preventDefault();
51313         e.stopPropagation();
51314
51315         if (!+e.clientX && !+e.clientY) {
51316             if (lastMouse) {
51317                 e.sourceEvent = lastMouse;
51318             } else {
51319                 return;
51320             }
51321         }
51322
51323         if (!p1) p1 = point();
51324         suppressMenu = false;
51325         click();
51326     }
51327
51328
51329     function click() {
51330         select(window)
51331             .on('mouseup.select', null, true);
51332
51333         if (!p1) return;
51334         var p2 = point(),
51335             dist = geoEuclideanDistance(p1, p2);
51336
51337         p1 = null;
51338         if (dist > tolerance) {
51339             return;
51340         }
51341
51342         var isMultiselect = event.shiftKey || select('#surface .lasso').node(),
51343             isShowAlways = +context.storage('edit-menu-show-always') === 1,
51344             datum = event.target.__data__ || (lastMouse && lastMouse.target.__data__),
51345             mode = context.mode();
51346
51347
51348         if (datum && datum.type === 'midpoint') {
51349             datum = datum.parents[0];
51350         }
51351
51352         if (!(datum instanceof osmEntity$$1)) {
51353             // clicked nothing..
51354             if (!isMultiselect && mode.id !== 'browse') {
51355                 context.enter(modeBrowse(context));
51356             }
51357
51358         } else {
51359             // clicked an entity..
51360             var selectedIDs = context.selectedIDs();
51361
51362             if (!isMultiselect) {
51363                 if (selectedIDs.length > 1 && (!suppressMenu && !isShowAlways)) {
51364                     // multiple things already selected, just show the menu...
51365                     mode.suppressMenu(false).reselect();
51366                 } else {
51367                     // select a single thing..
51368                     context.enter(modeSelect(context, [datum.id]).suppressMenu(suppressMenu));
51369                 }
51370
51371             } else {
51372                 if (selectedIDs.indexOf(datum.id) !== -1) {
51373                     // clicked entity is already in the selectedIDs list..
51374                     if (!suppressMenu && !isShowAlways) {
51375                         // don't deselect clicked entity, just show the menu.
51376                         mode.suppressMenu(false).reselect();
51377                     } else {
51378                         // deselect clicked entity, then reenter select mode or return to browse mode..
51379                         selectedIDs = lodash.without(selectedIDs, datum.id);
51380                         context.enter(selectedIDs.length ? modeSelect(context, selectedIDs) : modeBrowse(context));
51381                     }
51382                 } else {
51383                     // clicked entity is not in the selected list, add it..
51384                     selectedIDs = selectedIDs.concat([datum.id]);
51385                     context.enter(modeSelect(context, selectedIDs).suppressMenu(suppressMenu));
51386                 }
51387             }
51388         }
51389
51390         // reset for next time..
51391         suppressMenu = true;
51392     }
51393
51394
51395     var behavior = function(selection$$1) {
51396         lastMouse = null;
51397         suppressMenu = true;
51398         p1 = null;
51399
51400         select(window)
51401             .on('keydown.select', keydown)
51402             .on('keyup.select', keyup)
51403             .on('contextmenu.select-window', function() {
51404                 // Edge and IE really like to show the contextmenu on the
51405                 // menubar when user presses a keyboard menu button
51406                 // even after we've already preventdefaulted the key event.
51407                 var e = event;
51408                 if (+e.clientX === 0 && +e.clientY === 0) {
51409                     event.preventDefault();
51410                     event.stopPropagation();
51411                 }
51412             });
51413
51414         selection$$1
51415             .on('mousedown.select', mousedown)
51416             .on('mousemove.select', mousemove)
51417             .on('contextmenu.select', contextmenu);
51418
51419         if (event && event.shiftKey) {
51420             context.surface()
51421                 .classed('behavior-multiselect', true);
51422         }
51423     };
51424
51425
51426     behavior.off = function(selection$$1) {
51427         select(window)
51428             .on('keydown.select', null)
51429             .on('keyup.select', null)
51430             .on('contextmenu.select-window', null)
51431             .on('mouseup.select', null, true);
51432
51433         selection$$1
51434             .on('mousedown.select', null)
51435             .on('mousemove.select', null)
51436             .on('contextmenu.select', null);
51437
51438         context.surface()
51439             .classed('behavior-multiselect', false);
51440     };
51441
51442
51443     return behavior;
51444 }
51445
51446 function modeAddArea$$1(context) {
51447     var mode = {
51448         id: 'add-area',
51449         button: 'area',
51450         title: t('modes.add_area.title'),
51451         description: t('modes.add_area.description'),
51452         key: '3'
51453     };
51454
51455     var behavior = behaviorAddWay(context)
51456             .tail(t('modes.add_area.tail'))
51457             .on('start', start)
51458             .on('startFromWay', startFromWay)
51459             .on('startFromNode', startFromNode),
51460         defaultTags = { area: 'yes' };
51461
51462
51463     function actionClose(wayId) {
51464         return function (graph) {
51465             return graph.replace(graph.entity(wayId).close());
51466         };
51467     }
51468
51469
51470     function start(loc) {
51471         var startGraph = context.graph(),
51472             node = osmNode({ loc: loc }),
51473             way = osmWay({ tags: defaultTags });
51474
51475         context.perform(
51476             actionAddEntity(node),
51477             actionAddEntity(way),
51478             actionAddVertex(way.id, node.id),
51479             actionClose(way.id)
51480         );
51481
51482         context.enter(modeDrawArea(context, way.id, startGraph));
51483     }
51484
51485
51486     function startFromWay(loc, edge) {
51487         var startGraph = context.graph(),
51488             node = osmNode({ loc: loc }),
51489             way = osmWay({ tags: defaultTags });
51490
51491         context.perform(
51492             actionAddEntity(node),
51493             actionAddEntity(way),
51494             actionAddVertex(way.id, node.id),
51495             actionClose(way.id),
51496             actionAddMidpoint({ loc: loc, edge: edge }, node)
51497         );
51498
51499         context.enter(modeDrawArea(context, way.id, startGraph));
51500     }
51501
51502
51503     function startFromNode(node) {
51504         var startGraph = context.graph(),
51505             way = osmWay({ tags: defaultTags });
51506
51507         context.perform(
51508             actionAddEntity(way),
51509             actionAddVertex(way.id, node.id),
51510             actionClose(way.id)
51511         );
51512
51513         context.enter(modeDrawArea(context, way.id, startGraph));
51514     }
51515
51516
51517     mode.enter = function() {
51518         context.install(behavior);
51519     };
51520
51521
51522     mode.exit = function() {
51523         context.uninstall(behavior);
51524     };
51525
51526
51527     return mode;
51528 }
51529
51530 function modeAddLine$$1(context) {
51531     var mode = {
51532         id: 'add-line',
51533         button: 'line',
51534         title: t('modes.add_line.title'),
51535         description: t('modes.add_line.description'),
51536         key: '2'
51537     };
51538
51539     var behavior = behaviorAddWay(context)
51540         .tail(t('modes.add_line.tail'))
51541         .on('start', start)
51542         .on('startFromWay', startFromWay)
51543         .on('startFromNode', startFromNode);
51544
51545
51546     function start(loc) {
51547         var startGraph = context.graph(),
51548             node = osmNode({ loc: loc }),
51549             way = osmWay();
51550
51551         context.perform(
51552             actionAddEntity(node),
51553             actionAddEntity(way),
51554             actionAddVertex(way.id, node.id)
51555         );
51556
51557         context.enter(modeDrawLine(context, way.id, startGraph));
51558     }
51559
51560
51561     function startFromWay(loc, edge) {
51562         var startGraph = context.graph(),
51563             node = osmNode({ loc: loc }),
51564             way = osmWay();
51565
51566         context.perform(
51567             actionAddEntity(node),
51568             actionAddEntity(way),
51569             actionAddVertex(way.id, node.id),
51570             actionAddMidpoint({ loc: loc, edge: edge }, node)
51571         );
51572
51573         context.enter(modeDrawLine(context, way.id, startGraph));
51574     }
51575
51576
51577     function startFromNode(node) {
51578         var startGraph = context.graph(),
51579             way = osmWay();
51580
51581         context.perform(
51582             actionAddEntity(way),
51583             actionAddVertex(way.id, node.id)
51584         );
51585
51586         context.enter(modeDrawLine(context, way.id, startGraph));
51587     }
51588
51589
51590     mode.enter = function() {
51591         context.install(behavior);
51592     };
51593
51594
51595     mode.exit = function() {
51596         context.uninstall(behavior);
51597     };
51598
51599     return mode;
51600 }
51601
51602 function modeAddPoint$$1(context) {
51603     var mode = {
51604         id: 'add-point',
51605         button: 'point',
51606         title: t('modes.add_point.title'),
51607         description: t('modes.add_point.description'),
51608         key: '1'
51609     };
51610
51611     var behavior = behaviorDraw(context)
51612         .tail(t('modes.add_point.tail'))
51613         .on('click', add)
51614         .on('clickWay', addWay)
51615         .on('clickNode', addNode)
51616         .on('cancel', cancel)
51617         .on('finish', cancel);
51618
51619
51620     function add(loc) {
51621         var node = osmNode({ loc: loc });
51622
51623         context.perform(
51624             actionAddEntity(node),
51625             t('operations.add.annotation.point')
51626         );
51627
51628         context.enter(
51629             modeSelect(context, [node.id]).newFeature(true)
51630         );
51631     }
51632
51633
51634     function addWay(loc) {
51635         add(loc);
51636     }
51637
51638
51639     function addNode(node) {
51640         add(node.loc);
51641     }
51642
51643
51644     function cancel() {
51645         context.enter(modeBrowse(context));
51646     }
51647
51648
51649     mode.enter = function() {
51650         context.install(behavior);
51651     };
51652
51653
51654     mode.exit = function() {
51655         context.uninstall(behavior);
51656     };
51657
51658
51659     return mode;
51660 }
51661
51662 function modeDragNode$$1(context) {
51663     var mode = {
51664         id: 'drag-node',
51665         button: 'browse'
51666     };
51667
51668     var nudgeInterval,
51669         activeIDs,
51670         wasMidpoint,
51671         isCancelled,
51672         lastLoc,
51673         selectedIDs = [],
51674         hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover),
51675         edit = behaviorEdit(context);
51676
51677
51678     function vecSub(a, b) {
51679         return [a[0] - b[0], a[1] - b[1]];
51680     }
51681
51682     function edge(point, size) {
51683         var pad = [80, 20, 50, 20],   // top, right, bottom, left
51684             x = 0,
51685             y = 0;
51686
51687         if (point[0] > size[0] - pad[1])
51688             x = -10;
51689         if (point[0] < pad[3])
51690             x = 10;
51691         if (point[1] > size[1] - pad[2])
51692             y = -10;
51693         if (point[1] < pad[0])
51694             y = 10;
51695
51696         if (x || y) {
51697             return [x, y];
51698         } else {
51699             return null;
51700         }
51701     }
51702
51703
51704     function startNudge(entity, nudge) {
51705         if (nudgeInterval) window.clearInterval(nudgeInterval);
51706         nudgeInterval = window.setInterval(function() {
51707             context.pan(nudge);
51708             doMove(entity, nudge);
51709         }, 50);
51710     }
51711
51712
51713     function stopNudge() {
51714         if (nudgeInterval) {
51715             window.clearInterval(nudgeInterval);
51716             nudgeInterval = null;
51717         }
51718     }
51719
51720
51721     function moveAnnotation(entity) {
51722         return t('operations.move.annotation.' + entity.geometry(context.graph()));
51723     }
51724
51725
51726     function connectAnnotation(entity) {
51727         return t('operations.connect.annotation.' + entity.geometry(context.graph()));
51728     }
51729
51730
51731     function origin(entity) {
51732         return context.projection(entity.loc);
51733     }
51734
51735
51736     function start(entity) {
51737         wasMidpoint = entity.type === 'midpoint';
51738
51739         isCancelled = event.sourceEvent.shiftKey ||
51740             context.features().hasHiddenConnections(entity, context.graph());
51741
51742         if (isCancelled) {
51743             return behavior.cancel();
51744         }
51745
51746         if (wasMidpoint) {
51747             var midpoint = entity;
51748             entity = osmNode();
51749             context.perform(actionAddMidpoint(midpoint, entity));
51750
51751             var vertex = context.surface().selectAll('.' + entity.id);
51752             behavior.target(vertex.node(), entity);
51753
51754         } else {
51755             context.perform(actionNoop());
51756         }
51757
51758         // activeIDs generate no pointer events.  This prevents the node or vertex
51759         // being dragged from trying to connect to itself or its parent element.
51760         activeIDs = lodash.map(context.graph().parentWays(entity), 'id');
51761         activeIDs.push(entity.id);
51762         setActiveElements();
51763
51764         context.enter(mode);
51765     }
51766
51767
51768     function datum() {
51769         var event$$1 = event && event.sourceEvent;
51770         if (!event$$1 || event$$1.altKey) {
51771             return {};
51772         } else {
51773             return event$$1.target.__data__ || {};
51774         }
51775     }
51776
51777
51778     function doMove(entity, nudge) {
51779         nudge = nudge || [0, 0];
51780
51781         var currPoint = (event && event.point) || context.projection(lastLoc),
51782             currMouse = vecSub(currPoint, nudge),
51783             loc = context.projection.invert(currMouse),
51784             d = datum();
51785
51786         if (!nudgeInterval) {
51787             if (d.type === 'node' && d.id !== entity.id) {
51788                 loc = d.loc;
51789             } else if (d.type === 'way' && !select(event.sourceEvent.target).classed('fill')) {
51790                 loc = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection).loc;
51791             }
51792         }
51793
51794         context.replace(
51795             actionMoveNode(entity.id, loc),
51796             moveAnnotation(entity)
51797         );
51798
51799         lastLoc = loc;
51800     }
51801
51802
51803     function move(entity) {
51804         if (isCancelled) return;
51805         event.sourceEvent.stopPropagation();
51806         lastLoc = context.projection.invert(event.point);
51807
51808         doMove(entity);
51809         var nudge = edge(event.point, context.map().dimensions());
51810         if (nudge) {
51811             startNudge(entity, nudge);
51812         } else {
51813             stopNudge();
51814         }
51815     }
51816
51817
51818     function end(entity) {
51819         if (isCancelled) return;
51820
51821         var d = datum();
51822
51823         if (d.type === 'way') {
51824             var choice = geoChooseEdge(context.childNodes(d), context.mouse(), context.projection);
51825             context.replace(
51826                 actionAddMidpoint({ loc: choice.loc, edge: [d.nodes[choice.index - 1], d.nodes[choice.index]] }, entity),
51827                 connectAnnotation(d)
51828             );
51829
51830         } else if (d.type === 'node' && d.id !== entity.id) {
51831             context.replace(
51832                 actionConnect([d.id, entity.id]),
51833                 connectAnnotation(d)
51834             );
51835
51836         } else if (wasMidpoint) {
51837             context.replace(
51838                 actionNoop(),
51839                 t('operations.add.annotation.vertex')
51840             );
51841
51842         } else {
51843             context.replace(
51844                 actionNoop(),
51845                 moveAnnotation(entity)
51846             );
51847         }
51848
51849         var reselection = selectedIDs.filter(function(id) {
51850             return context.graph().hasEntity(id);
51851         });
51852
51853         if (reselection.length) {
51854             context.enter(modeSelect(context, reselection));
51855         } else {
51856             context.enter(modeBrowse(context));
51857         }
51858     }
51859
51860
51861     function cancel() {
51862         behavior.cancel();
51863         context.enter(modeBrowse(context));
51864     }
51865
51866
51867     function setActiveElements() {
51868         context.surface().selectAll(utilEntitySelector(activeIDs))
51869             .classed('active', true);
51870     }
51871
51872
51873     var behavior = behaviorDrag()
51874         .selector('g.node, g.point, g.midpoint')
51875         .surface(select('#map').node())
51876         .origin(origin)
51877         .on('start', start)
51878         .on('move', move)
51879         .on('end', end);
51880
51881
51882     mode.enter = function() {
51883         context.install(hover);
51884         context.install(edit);
51885
51886         context.history()
51887             .on('undone.drag-node', cancel);
51888
51889         context.map()
51890             .on('drawn.drag-node', setActiveElements);
51891
51892         setActiveElements();
51893     };
51894
51895
51896     mode.exit = function() {
51897         context.ui().sidebar.hover.cancel();
51898         context.uninstall(hover);
51899         context.uninstall(edit);
51900
51901         context.history()
51902             .on('undone.drag-node', null);
51903
51904         context.map()
51905             .on('drawn.drag-node', null);
51906
51907         context.surface()
51908             .selectAll('.active')
51909             .classed('active', false);
51910
51911         stopNudge();
51912     };
51913
51914
51915     mode.selectedIDs = function(_) {
51916         if (!arguments.length) return selectedIDs;
51917         selectedIDs = _;
51918         return mode;
51919     };
51920
51921
51922     mode.behavior = behavior;
51923
51924
51925     return mode;
51926 }
51927
51928 function modeBrowse(context) {
51929     var mode = {
51930         button: 'browse',
51931         id: 'browse',
51932         title: t('modes.browse.title'),
51933         description: t('modes.browse.description')
51934     }, sidebar;
51935
51936     var behaviors = [
51937         behaviorPaste(context),
51938         behaviorHover(context).on('hover', context.ui().sidebar.hover),
51939         behaviorSelect(context),
51940         behaviorLasso(context),
51941         modeDragNode$$1(context).behavior
51942     ];
51943
51944
51945     mode.enter = function() {
51946         behaviors.forEach(function(behavior) {
51947             context.install(behavior);
51948         });
51949
51950         // Get focus on the body.
51951         if (document.activeElement && document.activeElement.blur) {
51952             document.activeElement.blur();
51953         }
51954
51955         if (sidebar) {
51956             context.ui().sidebar.show(sidebar);
51957         } else {
51958             context.ui().sidebar.select(null);
51959         }
51960     };
51961
51962
51963     mode.exit = function() {
51964         context.ui().sidebar.hover.cancel();
51965         behaviors.forEach(function(behavior) {
51966             context.uninstall(behavior);
51967         });
51968
51969         if (sidebar) {
51970             context.ui().sidebar.hide();
51971         }
51972     };
51973
51974
51975     mode.sidebar = function(_) {
51976         if (!arguments.length) return sidebar;
51977         sidebar = _;
51978         return mode;
51979     };
51980
51981
51982     return mode;
51983 }
51984
51985 function modeDrawArea(context, wayId, startGraph) {
51986     var mode = {
51987         button: 'area',
51988         id: 'draw-area'
51989     };
51990
51991     var behavior;
51992
51993
51994     mode.enter = function() {
51995         var way = context.entity(wayId);
51996
51997         behavior = behaviorDrawWay(context, wayId, undefined, mode, startGraph)
51998             .tail(t('modes.draw_area.tail'));
51999
52000         var addNode = behavior.addNode;
52001
52002         behavior.addNode = function(node) {
52003             var length = way.nodes.length,
52004                 penultimate = length > 2 ? way.nodes[length - 2] : null;
52005
52006             if (node.id === way.first() || node.id === penultimate) {
52007                 behavior.finish();
52008             } else {
52009                 addNode(node);
52010             }
52011         };
52012
52013         context.install(behavior);
52014     };
52015
52016
52017     mode.exit = function() {
52018         context.uninstall(behavior);
52019     };
52020
52021
52022     mode.selectedIDs = function() {
52023         return [wayId];
52024     };
52025
52026
52027     return mode;
52028 }
52029
52030 function modeDrawLine(context, wayId, startGraph, affix) {
52031     var mode = {
52032         button: 'line',
52033         id: 'draw-line'
52034     };
52035
52036     var behavior;
52037
52038
52039     mode.enter = function() {
52040         var way = context.entity(wayId),
52041             index = (affix === 'prefix') ? 0 : undefined,
52042             headId = (affix === 'prefix') ? way.first() : way.last();
52043
52044         behavior = behaviorDrawWay(context, wayId, index, mode, startGraph)
52045             .tail(t('modes.draw_line.tail'));
52046
52047         var addNode = behavior.addNode;
52048
52049         behavior.addNode = function(node) {
52050             if (node.id === headId) {
52051                 behavior.finish();
52052             } else {
52053                 addNode(node);
52054             }
52055         };
52056
52057         context.install(behavior);
52058     };
52059
52060
52061     mode.exit = function() {
52062         context.uninstall(behavior);
52063     };
52064
52065
52066     mode.selectedIDs = function() {
52067         return [wayId];
52068     };
52069
52070
52071     return mode;
52072 }
52073
52074 function operationCircularize(selectedIDs, context) {
52075     var entityId = selectedIDs[0],
52076         entity = context.entity(entityId),
52077         extent = entity.extent(context.graph()),
52078         geometry = context.geometry(entityId),
52079         action = actionCircularize(entityId, context.projection);
52080
52081
52082     var operation = function() {
52083         context.perform(action, operation.annotation());
52084     };
52085
52086
52087     operation.available = function() {
52088         return selectedIDs.length === 1 &&
52089             entity.type === 'way' &&
52090             lodash.uniq(entity.nodes).length > 1;
52091     };
52092
52093
52094     operation.disabled = function() {
52095         var reason;
52096         if (extent.percentContainedIn(context.extent()) < 0.8) {
52097             reason = 'too_large';
52098         } else if (context.hasHiddenConnections(entityId)) {
52099             reason = 'connected_to_hidden';
52100         }
52101         return action.disabled(context.graph()) || reason;
52102     };
52103
52104
52105     operation.tooltip = function() {
52106         var disable = operation.disabled();
52107         return disable ?
52108             t('operations.circularize.' + disable) :
52109             t('operations.circularize.description.' + geometry);
52110     };
52111
52112
52113     operation.annotation = function() {
52114         return t('operations.circularize.annotation.' + geometry);
52115     };
52116
52117
52118     operation.id = 'circularize';
52119     operation.keys = [t('operations.circularize.key')];
52120     operation.title = t('operations.circularize.title');
52121     operation.behavior = behaviorOperation(context).which(operation);
52122
52123     return operation;
52124 }
52125
52126 function operationContinue(selectedIDs, context) {
52127     var graph = context.graph(),
52128         entities = selectedIDs.map(function(id) { return graph.entity(id); }),
52129         geometries = lodash.extend({ line: [], vertex: [] },
52130             lodash.groupBy(entities, function(entity) { return entity.geometry(graph); })),
52131         vertex = geometries.vertex[0];
52132
52133
52134     function candidateWays() {
52135         return graph.parentWays(vertex).filter(function(parent) {
52136             return parent.geometry(graph) === 'line' &&
52137                 !parent.isClosed() &&
52138                 parent.affix(vertex.id) &&
52139                 (geometries.line.length === 0 || geometries.line[0] === parent);
52140         });
52141     }
52142
52143
52144     var operation = function() {
52145         var candidate = candidateWays()[0];
52146         context.enter(
52147             modeDrawLine(context, candidate.id, context.graph(), candidate.affix(vertex.id))
52148         );
52149     };
52150
52151
52152     operation.available = function() {
52153         return geometries.vertex.length === 1 && geometries.line.length <= 1 &&
52154             !context.features().hasHiddenConnections(vertex, context.graph());
52155     };
52156
52157
52158     operation.disabled = function() {
52159         var candidates = candidateWays();
52160         if (candidates.length === 0)
52161             return 'not_eligible';
52162         if (candidates.length > 1)
52163             return 'multiple';
52164     };
52165
52166
52167     operation.tooltip = function() {
52168         var disable = operation.disabled();
52169         return disable ?
52170             t('operations.continue.' + disable) :
52171             t('operations.continue.description');
52172     };
52173
52174
52175     operation.annotation = function() {
52176         return t('operations.continue.annotation.line');
52177     };
52178
52179
52180     operation.id = 'continue';
52181     operation.keys = [t('operations.continue.key')];
52182     operation.title = t('operations.continue.title');
52183     operation.behavior = behaviorOperation(context).which(operation);
52184
52185     return operation;
52186 }
52187
52188 function operationDelete(selectedIDs, context) {
52189     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
52190         action = actionDeleteMultiple(selectedIDs),
52191         extent = selectedIDs.reduce(function(extent, id) {
52192                 return extent.extend(context.entity(id).extent(context.graph()));
52193             }, geoExtent$$1());
52194
52195
52196     var operation = function() {
52197         var nextSelectedID;
52198
52199         if (selectedIDs.length === 1) {
52200             var id = selectedIDs[0],
52201                 entity = context.entity(id),
52202                 geometry = context.geometry(id),
52203                 parents = context.graph().parentWays(entity),
52204                 parent = parents[0];
52205
52206             // Select the next closest node in the way.
52207             if (geometry === 'vertex' && parent.nodes.length > 2) {
52208                 var nodes = parent.nodes,
52209                     i = nodes.indexOf(id);
52210
52211                 if (i === 0) {
52212                     i++;
52213                 } else if (i === nodes.length - 1) {
52214                     i--;
52215                 } else {
52216                     var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc),
52217                         b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
52218                     i = a < b ? i - 1 : i + 1;
52219                 }
52220
52221                 nextSelectedID = nodes[i];
52222             }
52223         }
52224
52225         context.perform(action, operation.annotation());
52226
52227         if (nextSelectedID && context.hasEntity(nextSelectedID)) {
52228             context.enter(modeSelect(context, [nextSelectedID]).follow(true));
52229         } else {
52230             context.enter(modeBrowse(context));
52231         }
52232
52233     };
52234
52235
52236     operation.available = function() {
52237         return true;
52238     };
52239
52240
52241     operation.disabled = function() {
52242         var reason;
52243         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
52244             reason = 'too_large';
52245         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52246             reason = 'connected_to_hidden';
52247         } else if (lodash.some(selectedIDs, protectedMember)) {
52248             reason = 'part_of_relation';
52249         } else if (lodash.some(selectedIDs, incompleteRelation)) {
52250             reason = 'incomplete_relation';
52251         }
52252         return reason;
52253
52254         function incompleteRelation(id) {
52255             var entity = context.entity(id);
52256             return entity.type === 'relation' && !entity.isComplete(context.graph());
52257         }
52258
52259         function protectedMember(id) {
52260             var entity = context.entity(id);
52261             if (entity.type !== 'way') return false;
52262
52263             var parents = context.graph().parentRelations(entity);
52264             for (var i = 0; i < parents.length; i++) {
52265                 var parent = parents[i],
52266                     type = parent.tags.type,
52267                     role = parent.memberById(id).role || 'outer';
52268                 if (type === 'route' || type === 'boundary' || (type === 'multipolygon' && role === 'outer')) {
52269                     return true;
52270                 }
52271             }
52272             return false;
52273         }
52274
52275     };
52276
52277
52278     operation.tooltip = function() {
52279         var disable = operation.disabled();
52280         return disable ?
52281             t('operations.delete.' + disable + '.' + multi) :
52282             t('operations.delete.description' + '.' + multi);
52283     };
52284
52285
52286     operation.annotation = function() {
52287         return selectedIDs.length === 1 ?
52288             t('operations.delete.annotation.' + context.geometry(selectedIDs[0])) :
52289             t('operations.delete.annotation.multiple', { n: selectedIDs.length });
52290     };
52291
52292
52293     operation.id = 'delete';
52294     operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
52295     operation.title = t('operations.delete.title');
52296     operation.behavior = behaviorOperation(context).which(operation);
52297
52298     return operation;
52299 }
52300
52301 function operationDisconnect(selectedIDs, context) {
52302     var vertices = lodash.filter(selectedIDs, function(entityId) {
52303         return context.geometry(entityId) === 'vertex';
52304     });
52305
52306     var entityId = vertices[0],
52307         action = actionDisconnect(entityId);
52308
52309     if (selectedIDs.length > 1) {
52310         action.limitWays(lodash.without(selectedIDs, entityId));
52311     }
52312
52313
52314     var operation = function() {
52315         context.perform(action, operation.annotation());
52316     };
52317
52318
52319     operation.available = function() {
52320         return vertices.length === 1;
52321     };
52322
52323
52324     operation.disabled = function() {
52325         var reason;
52326         if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52327             reason = 'connected_to_hidden';
52328         }
52329         return action.disabled(context.graph()) || reason;
52330     };
52331
52332
52333     operation.tooltip = function() {
52334         var disable = operation.disabled();
52335         return disable ?
52336             t('operations.disconnect.' + disable) :
52337             t('operations.disconnect.description');
52338     };
52339
52340
52341     operation.annotation = function() {
52342         return t('operations.disconnect.annotation');
52343     };
52344
52345
52346     operation.id = 'disconnect';
52347     operation.keys = [t('operations.disconnect.key')];
52348     operation.title = t('operations.disconnect.title');
52349     operation.behavior = behaviorOperation(context).which(operation);
52350
52351     return operation;
52352 }
52353
52354 function operationMerge(selectedIDs, context) {
52355
52356     function updatePresetTags(oldGraph, newGraph, ids) {
52357         var id = ids[0],
52358             oldEntity = oldGraph.hasEntity(id),
52359             newEntity = newGraph.hasEntity(id);
52360
52361         if (!oldEntity || !newEntity) return;
52362
52363         var oldPreset = context.presets().match(oldEntity, oldGraph),
52364             newPreset = context.presets().match(newEntity, newGraph);
52365
52366         context.replace(actionChangePreset(id, oldPreset, newPreset));
52367     }
52368
52369
52370     var join = actionJoin(selectedIDs),
52371         merge = actionMerge(selectedIDs),
52372         mergePolygon = actionMergePolygon(selectedIDs);
52373
52374
52375     var operation = function() {
52376         var origGraph = context.graph(),
52377             action;
52378
52379         if (!join.disabled(origGraph)) {
52380             action = join;
52381         } else if (!merge.disabled(origGraph)) {
52382             action = merge;
52383         } else {
52384             action = mergePolygon;
52385         }
52386
52387         context.perform(action, operation.annotation());
52388
52389         var ids = selectedIDs.filter(function(id) {
52390             var entity = context.hasEntity(id);
52391             return entity && entity.type !== 'node';
52392         });
52393
52394         // if we merged tags, rematch preset and update tags if necessary (#3851)
52395         if (action === merge) {
52396             updatePresetTags(origGraph, context.graph(), ids);
52397         }
52398
52399         context.enter(modeSelect(context, ids));
52400     };
52401
52402
52403     operation.available = function() {
52404         return selectedIDs.length >= 2;
52405     };
52406
52407
52408     operation.disabled = function() {
52409         return join.disabled(context.graph()) &&
52410             merge.disabled(context.graph()) &&
52411             mergePolygon.disabled(context.graph());
52412     };
52413
52414
52415     operation.tooltip = function() {
52416         var j = join.disabled(context.graph()),
52417             m = merge.disabled(context.graph()),
52418             p = mergePolygon.disabled(context.graph());
52419
52420         if (j === 'restriction' && m && p) {
52421             return t('operations.merge.restriction',
52422                 { relation: context.presets().item('type/restriction').name() });
52423         }
52424
52425         if (p === 'incomplete_relation' && j && m) {
52426             return t('operations.merge.incomplete_relation');
52427         }
52428
52429         if (j && m && p) {
52430             return t('operations.merge.' + j);
52431         }
52432
52433         return t('operations.merge.description');
52434     };
52435
52436
52437     operation.annotation = function() {
52438         return t('operations.merge.annotation', { n: selectedIDs.length });
52439     };
52440
52441
52442     operation.id = 'merge';
52443     operation.keys = [t('operations.merge.key')];
52444     operation.title = t('operations.merge.title');
52445     operation.behavior = behaviorOperation(context).which(operation);
52446
52447     return operation;
52448 }
52449
52450 function operationMove(selectedIDs, context) {
52451     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
52452         extent = selectedIDs.reduce(function(extent, id) {
52453             return extent.extend(context.entity(id).extent(context.graph()));
52454         }, geoExtent$$1());
52455
52456
52457     var operation = function() {
52458         context.enter(modeMove$$1(context, selectedIDs));
52459     };
52460
52461
52462     operation.available = function() {
52463         return selectedIDs.length > 1 ||
52464             context.entity(selectedIDs[0]).type !== 'node';
52465     };
52466
52467
52468     operation.disabled = function() {
52469         var reason;
52470         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
52471             reason = 'too_large';
52472         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52473             reason = 'connected_to_hidden';
52474         } else if (lodash.some(selectedIDs, incompleteRelation)) {
52475             reason = 'incomplete_relation';
52476         }
52477         return reason;
52478
52479         function incompleteRelation(id) {
52480             var entity = context.entity(id);
52481             return entity.type === 'relation' && !entity.isComplete(context.graph());
52482         }
52483     };
52484
52485
52486     operation.tooltip = function() {
52487         var disable = operation.disabled();
52488         return disable ?
52489             t('operations.move.' + disable + '.' + multi) :
52490             t('operations.move.description.' + multi);
52491     };
52492
52493
52494     operation.annotation = function() {
52495         return selectedIDs.length === 1 ?
52496             t('operations.move.annotation.' + context.geometry(selectedIDs[0])) :
52497             t('operations.move.annotation.multiple');
52498     };
52499
52500
52501     operation.id = 'move';
52502     operation.keys = [t('operations.move.key')];
52503     operation.title = t('operations.move.title');
52504     operation.behavior = behaviorOperation(context).which(operation);
52505
52506     return operation;
52507 }
52508
52509 function operationOrthogonalize(selectedIDs, context) {
52510     var entityId = selectedIDs[0],
52511         entity = context.entity(entityId),
52512         extent = entity.extent(context.graph()),
52513         geometry = context.geometry(entityId),
52514         action = actionOrthogonalize(entityId, context.projection);
52515
52516
52517     var operation = function() {
52518         context.perform(action, operation.annotation());
52519     };
52520
52521
52522     operation.available = function() {
52523         return selectedIDs.length === 1 &&
52524             entity.type === 'way' &&
52525             entity.isClosed() &&
52526             lodash.uniq(entity.nodes).length > 2;
52527     };
52528
52529
52530     operation.disabled = function() {
52531         var reason;
52532         if (extent.percentContainedIn(context.extent()) < 0.8) {
52533             reason = 'too_large';
52534         } else if (context.hasHiddenConnections(entityId)) {
52535             reason = 'connected_to_hidden';
52536         }
52537         return action.disabled(context.graph()) || reason;
52538     };
52539
52540
52541     operation.tooltip = function() {
52542         var disable = operation.disabled();
52543         return disable ?
52544             t('operations.orthogonalize.' + disable) :
52545             t('operations.orthogonalize.description.' + geometry);
52546     };
52547
52548
52549     operation.annotation = function() {
52550         return t('operations.orthogonalize.annotation.' + geometry);
52551     };
52552
52553
52554     operation.id = 'orthogonalize';
52555     operation.keys = [t('operations.orthogonalize.key')];
52556     operation.title = t('operations.orthogonalize.title');
52557     operation.behavior = behaviorOperation(context).which(operation);
52558
52559     return operation;
52560 }
52561
52562 function operationReflectShort(selectedIDs, context) {
52563     return operationReflect(selectedIDs, context, 'short');
52564 }
52565
52566
52567 function operationReflectLong(selectedIDs, context) {
52568     return operationReflect(selectedIDs, context, 'long');
52569 }
52570
52571
52572 function operationReflect(selectedIDs, context, axis) {
52573     axis = axis || 'long';
52574     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
52575         extent = selectedIDs.reduce(function(extent, id) {
52576             return extent.extend(context.entity(id).extent(context.graph()));
52577         }, geoExtent$$1());
52578
52579
52580     var operation = function() {
52581         var action = actionReflect(selectedIDs, context.projection)
52582             .useLongAxis(Boolean(axis === 'long'));
52583         context.perform(action, operation.annotation());
52584     };
52585
52586
52587     operation.available = function() {
52588         return lodash.some(selectedIDs, hasArea);
52589
52590         function hasArea(id) {
52591             var entity = context.entity(id);
52592             return (entity.type === 'way' && entity.isClosed()) ||
52593                 (entity.type ==='relation' && entity.isMultipolygon());
52594         }
52595     };
52596
52597
52598     operation.disabled = function() {
52599         var reason;
52600         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
52601             reason = 'too_large';
52602         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52603             reason = 'connected_to_hidden';
52604         } else if (lodash.some(selectedIDs, incompleteRelation)) {
52605             reason = 'incomplete_relation';
52606         }
52607         return reason;
52608
52609         function incompleteRelation(id) {
52610             var entity = context.entity(id);
52611             return entity.type === 'relation' && !entity.isComplete(context.graph());
52612         }
52613     };
52614
52615
52616     operation.tooltip = function() {
52617         var disable = operation.disabled();
52618         return disable ?
52619             t('operations.reflect.' + disable + '.' + multi) :
52620             t('operations.reflect.description.' + axis + '.' + multi);
52621     };
52622
52623
52624     operation.annotation = function() {
52625         return t('operations.reflect.annotation.' + axis + '.' + multi);
52626     };
52627
52628
52629     operation.id = 'reflect-' + axis;
52630     operation.keys = [t('operations.reflect.key.' + axis)];
52631     operation.title = t('operations.reflect.title.' + axis);
52632     operation.behavior = behaviorOperation(context).which(operation);
52633
52634     return operation;
52635 }
52636
52637 function operationReverse(selectedIDs, context) {
52638     var entityId = selectedIDs[0];
52639
52640     var operation = function() {
52641         context.perform(actionReverse(entityId), operation.annotation());
52642     };
52643
52644
52645     operation.available = function() {
52646         return selectedIDs.length === 1 && context.geometry(entityId) === 'line';
52647     };
52648
52649
52650     operation.disabled = function() {
52651         return false;
52652     };
52653
52654
52655     operation.tooltip = function() {
52656         return t('operations.reverse.description');
52657     };
52658
52659
52660     operation.annotation = function() {
52661         return t('operations.reverse.annotation');
52662     };
52663
52664
52665     operation.id = 'reverse';
52666     operation.keys = [t('operations.reverse.key')];
52667     operation.title = t('operations.reverse.title');
52668     operation.behavior = behaviorOperation(context).which(operation);
52669
52670     return operation;
52671 }
52672
52673 function operationRotate(selectedIDs, context) {
52674     var multi = (selectedIDs.length === 1 ? 'single' : 'multiple'),
52675         extent = selectedIDs.reduce(function(extent, id) {
52676             return extent.extend(context.entity(id).extent(context.graph()));
52677         }, geoExtent$$1());
52678
52679
52680     var operation = function() {
52681         context.enter(modeRotate$$1(context, selectedIDs));
52682     };
52683
52684
52685     operation.available = function() {
52686         return lodash.some(selectedIDs, hasArea);
52687
52688         function hasArea(id) {
52689             var entity = context.entity(id);
52690             return (entity.type === 'way' && entity.isClosed()) ||
52691                 (entity.type ==='relation' && entity.isMultipolygon());
52692         }
52693     };
52694
52695
52696     operation.disabled = function() {
52697         var reason;
52698         if (extent.area() && extent.percentContainedIn(context.extent()) < 0.8) {
52699             reason = 'too_large';
52700         } else if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52701             reason = 'connected_to_hidden';
52702         } else if (lodash.some(selectedIDs, incompleteRelation)) {
52703             reason = 'incomplete_relation';
52704         }
52705         return reason;
52706
52707         function incompleteRelation(id) {
52708             var entity = context.entity(id);
52709             return entity.type === 'relation' && !entity.isComplete(context.graph());
52710         }
52711     };
52712
52713
52714     operation.tooltip = function() {
52715         var disable = operation.disabled();
52716         return disable ?
52717             t('operations.rotate.' + disable + '.' + multi) :
52718             t('operations.rotate.description.' + multi);
52719     };
52720
52721
52722     operation.annotation = function() {
52723         return selectedIDs.length === 1 ?
52724             t('operations.rotate.annotation.' + context.geometry(selectedIDs[0])) :
52725             t('operations.rotate.annotation.multiple');
52726     };
52727
52728
52729     operation.id = 'rotate';
52730     operation.keys = [t('operations.rotate.key')];
52731     operation.title = t('operations.rotate.title');
52732     operation.behavior = behaviorOperation(context).which(operation);
52733
52734     return operation;
52735 }
52736
52737 function operationSplit(selectedIDs, context) {
52738     var vertices = lodash.filter(selectedIDs, function(entityId) {
52739         return context.geometry(entityId) === 'vertex';
52740     });
52741
52742     var entityId = vertices[0],
52743         action = actionSplit(entityId),
52744         ways = [];
52745
52746     if (vertices.length === 1) {
52747         if (selectedIDs.length > 1) {
52748             action.limitWays(lodash.without(selectedIDs, entityId));
52749         }
52750         ways = action.ways(context.graph());
52751     }
52752
52753
52754     var operation = function() {
52755         var difference = context.perform(action, operation.annotation());
52756         context.enter(modeSelect(context, difference.extantIDs()));
52757     };
52758
52759
52760     operation.available = function() {
52761         return vertices.length === 1;
52762     };
52763
52764
52765     operation.disabled = function() {
52766         var reason;
52767         if (lodash.some(selectedIDs, context.hasHiddenConnections)) {
52768             reason = 'connected_to_hidden';
52769         }
52770         return action.disabled(context.graph()) || reason;
52771     };
52772
52773
52774     operation.tooltip = function() {
52775         var disable = operation.disabled();
52776         if (disable) {
52777             return t('operations.split.' + disable);
52778         }
52779         if (ways.length === 1) {
52780             return t('operations.split.description.' + context.geometry(ways[0].id));
52781         } else {
52782             return t('operations.split.description.multiple');
52783         }
52784     };
52785
52786
52787     operation.annotation = function() {
52788         return ways.length === 1 ?
52789             t('operations.split.annotation.' + context.geometry(ways[0].id)) :
52790             t('operations.split.annotation.multiple', { n: ways.length });
52791     };
52792
52793
52794     operation.id = 'split';
52795     operation.keys = [t('operations.split.key')];
52796     operation.title = t('operations.split.title');
52797     operation.behavior = behaviorOperation(context).which(operation);
52798
52799     return operation;
52800 }
52801
52802 function operationStraighten(selectedIDs, context) {
52803     var entityId = selectedIDs[0],
52804         action = actionStraighten(entityId, context.projection);
52805
52806
52807     function operation() {
52808         context.perform(action, operation.annotation());
52809     }
52810
52811
52812     operation.available = function() {
52813         var entity = context.entity(entityId);
52814         return selectedIDs.length === 1 &&
52815             entity.type === 'way' &&
52816             !entity.isClosed() &&
52817             lodash.uniq(entity.nodes).length > 2;
52818     };
52819
52820
52821     operation.disabled = function() {
52822         var reason;
52823         if (context.hasHiddenConnections(entityId)) {
52824             reason = 'connected_to_hidden';
52825         }
52826         return action.disabled(context.graph()) || reason;
52827     };
52828
52829
52830     operation.tooltip = function() {
52831         var disable = operation.disabled();
52832         return disable ?
52833             t('operations.straighten.' + disable) :
52834             t('operations.straighten.description');
52835     };
52836
52837
52838     operation.annotation = function() {
52839         return t('operations.straighten.annotation');
52840     };
52841
52842
52843     operation.id = 'straighten';
52844     operation.keys = [t('operations.straighten.key')];
52845     operation.title = t('operations.straighten.title');
52846     operation.behavior = behaviorOperation(context).which(operation);
52847
52848     return operation;
52849 }
52850
52851
52852
52853 var Operations = Object.freeze({
52854         operationCircularize: operationCircularize,
52855         operationContinue: operationContinue,
52856         operationDelete: operationDelete,
52857         operationDisconnect: operationDisconnect,
52858         operationMerge: operationMerge,
52859         operationMove: operationMove,
52860         operationOrthogonalize: operationOrthogonalize,
52861         operationReflectShort: operationReflectShort,
52862         operationReflectLong: operationReflectLong,
52863         operationReverse: operationReverse,
52864         operationRotate: operationRotate,
52865         operationSplit: operationSplit,
52866         operationStraighten: operationStraighten
52867 });
52868
52869 function modeMove$$1(context, entityIDs, baseGraph) {
52870     var mode = {
52871         id: 'move',
52872         button: 'browse'
52873     };
52874
52875     var keybinding = d3keybinding('move'),
52876         behaviors = [
52877             behaviorEdit(context),
52878             operationCircularize(entityIDs, context).behavior,
52879             operationDelete(entityIDs, context).behavior,
52880             operationOrthogonalize(entityIDs, context).behavior,
52881             operationReflectLong(entityIDs, context).behavior,
52882             operationReflectShort(entityIDs, context).behavior,
52883             operationRotate(entityIDs, context).behavior
52884         ],
52885         annotation = entityIDs.length === 1 ?
52886             t('operations.move.annotation.' + context.geometry(entityIDs[0])) :
52887             t('operations.move.annotation.multiple'),
52888         prevGraph,
52889         cache,
52890         origin,
52891         nudgeInterval;
52892
52893
52894     function vecSub(a, b) {
52895         return [a[0] - b[0], a[1] - b[1]];
52896     }
52897
52898
52899     function edge(point, size) {
52900         var pad = [80, 20, 50, 20],   // top, right, bottom, left
52901             x = 0,
52902             y = 0;
52903
52904         if (point[0] > size[0] - pad[1])
52905             x = -10;
52906         if (point[0] < pad[3])
52907             x = 10;
52908         if (point[1] > size[1] - pad[2])
52909             y = -10;
52910         if (point[1] < pad[0])
52911             y = 10;
52912
52913         if (x || y) {
52914             return [x, y];
52915         } else {
52916             return null;
52917         }
52918     }
52919
52920
52921     function doMove(nudge) {
52922         nudge = nudge || [0, 0];
52923
52924         var fn;
52925         if (prevGraph !== context.graph()) {
52926             cache = {};
52927             origin = context.map().mouseCoordinates();
52928             fn = context.perform;
52929         } else {
52930             fn = context.overwrite;
52931         }
52932
52933         var currMouse = context.mouse(),
52934             origMouse = context.projection(origin),
52935             delta = vecSub(vecSub(currMouse, origMouse), nudge);
52936
52937         fn(actionMove(entityIDs, delta, context.projection, cache), annotation);
52938         prevGraph = context.graph();
52939     }
52940
52941
52942     function startNudge(nudge) {
52943         if (nudgeInterval) window.clearInterval(nudgeInterval);
52944         nudgeInterval = window.setInterval(function() {
52945             context.pan(nudge);
52946             doMove(nudge);
52947         }, 50);
52948     }
52949
52950
52951     function stopNudge() {
52952         if (nudgeInterval) {
52953             window.clearInterval(nudgeInterval);
52954             nudgeInterval = null;
52955         }
52956     }
52957
52958
52959     function move() {
52960         doMove();
52961         var nudge = edge(context.mouse(), context.map().dimensions());
52962         if (nudge) {
52963             startNudge(nudge);
52964         } else {
52965             stopNudge();
52966         }
52967     }
52968
52969
52970     function finish() {
52971         event.stopPropagation();
52972         context.enter(modeSelect(context, entityIDs));
52973         stopNudge();
52974     }
52975
52976
52977     function cancel() {
52978         if (baseGraph) {
52979             while (context.graph() !== baseGraph) context.pop();
52980             context.enter(modeBrowse(context));
52981         } else {
52982             context.pop();
52983             context.enter(modeSelect(context, entityIDs));
52984         }
52985         stopNudge();
52986     }
52987
52988
52989     function undone() {
52990         context.enter(modeBrowse(context));
52991     }
52992
52993
52994     mode.enter = function() {
52995         origin = context.map().mouseCoordinates();
52996         prevGraph = null;
52997         cache = {};
52998
52999         behaviors.forEach(function(behavior) {
53000             context.install(behavior);
53001         });
53002
53003         context.surface()
53004             .on('mousemove.move', move)
53005             .on('click.move', finish);
53006
53007         context.history()
53008             .on('undone.move', undone);
53009
53010         keybinding
53011             .on('⎋', cancel)
53012             .on('↩', finish);
53013
53014         select(document)
53015             .call(keybinding);
53016     };
53017
53018
53019     mode.exit = function() {
53020         stopNudge();
53021
53022         behaviors.forEach(function(behavior) {
53023             context.uninstall(behavior);
53024         });
53025
53026         context.surface()
53027             .on('mousemove.move', null)
53028             .on('click.move', null);
53029
53030         context.history()
53031             .on('undone.move', null);
53032
53033         keybinding.off();
53034     };
53035
53036
53037     return mode;
53038 }
53039
53040 function modeRotate$$1(context, entityIDs) {
53041     var mode = {
53042         id: 'rotate',
53043         button: 'browse'
53044     };
53045
53046     var keybinding = d3keybinding('rotate'),
53047         behaviors = [
53048             behaviorEdit(context),
53049             operationCircularize(entityIDs, context).behavior,
53050             operationDelete(entityIDs, context).behavior,
53051             operationMove(entityIDs, context).behavior,
53052             operationOrthogonalize(entityIDs, context).behavior,
53053             operationReflectLong(entityIDs, context).behavior,
53054             operationReflectShort(entityIDs, context).behavior
53055         ],
53056         annotation = entityIDs.length === 1 ?
53057             t('operations.rotate.annotation.' + context.geometry(entityIDs[0])) :
53058             t('operations.rotate.annotation.multiple'),
53059         prevGraph,
53060         prevAngle,
53061         prevTransform,
53062         pivot;
53063
53064
53065     function doRotate() {
53066         var fn;
53067         if (context.graph() !== prevGraph) {
53068             fn = context.perform;
53069         } else {
53070             fn = context.replace;
53071         }
53072
53073         // projection changed, recalculate pivot
53074         var projection$$1 = context.projection;
53075         var currTransform = projection$$1.transform();
53076         if (!prevTransform ||
53077             currTransform.k !== prevTransform.k ||
53078             currTransform.x !== prevTransform.x ||
53079             currTransform.y !== prevTransform.y) {
53080
53081             var nodes = utilGetAllNodes(entityIDs, context.graph()),
53082                 points = nodes.map(function(n) { return projection$$1(n.loc); });
53083
53084             pivot = d3polygonCentroid(d3polygonHull(points));
53085             prevAngle = undefined;
53086         }
53087
53088
53089         var currMouse = context.mouse(),
53090             currAngle = Math.atan2(currMouse[1] - pivot[1], currMouse[0] - pivot[0]);
53091
53092         if (typeof prevAngle === 'undefined') prevAngle = currAngle;
53093         var delta = currAngle - prevAngle;
53094
53095         fn(actionRotate(entityIDs, pivot, delta, projection$$1), annotation);
53096
53097         prevTransform = currTransform;
53098         prevAngle = currAngle;
53099         prevGraph = context.graph();
53100     }
53101
53102
53103     function finish() {
53104         event.stopPropagation();
53105         context.enter(modeSelect(context, entityIDs));
53106     }
53107
53108
53109     function cancel() {
53110         context.pop();
53111         context.enter(modeSelect(context, entityIDs));
53112     }
53113
53114
53115     function undone() {
53116         context.enter(modeBrowse(context));
53117     }
53118
53119
53120     mode.enter = function() {
53121         behaviors.forEach(function(behavior) {
53122             context.install(behavior);
53123         });
53124
53125         context.surface()
53126             .on('mousemove.rotate', doRotate)
53127             .on('click.rotate', finish);
53128
53129         context.history()
53130             .on('undone.rotate', undone);
53131
53132         keybinding
53133             .on('⎋', cancel)
53134             .on('↩', finish);
53135
53136         select(document)
53137             .call(keybinding);
53138     };
53139
53140
53141     mode.exit = function() {
53142         behaviors.forEach(function(behavior) {
53143             context.uninstall(behavior);
53144         });
53145
53146         context.surface()
53147             .on('mousemove.rotate', null)
53148             .on('click.rotate', null);
53149
53150         context.history()
53151             .on('undone.rotate', null);
53152
53153         keybinding.off();
53154     };
53155
53156
53157     return mode;
53158 }
53159
53160 function modeSave$$1(context) {
53161     var mode = {
53162         id: 'save'
53163     };
53164
53165     var commit = uiCommit(context)
53166             .on('cancel', cancel)
53167             .on('save', save);
53168
53169
53170     function cancel() {
53171         context.enter(modeBrowse(context));
53172     }
53173
53174
53175     function save(changeset, tryAgain) {
53176
53177         var loading = uiLoading(context).message(t('save.uploading')).blocking(true),
53178             history = context.history(),
53179             origChanges = history.changes(actionDiscardTags(history.difference())),
53180             localGraph = context.graph(),
53181             remoteGraph = coreGraph$$1(history.base(), true),
53182             modified = lodash.filter(history.difference().summary(), {changeType: 'modified'}),
53183             toCheck = lodash.map(lodash.map(modified, 'entity'), 'id'),
53184             toLoad = withChildNodes(toCheck, localGraph),
53185             conflicts = [],
53186             errors = [];
53187
53188         if (!tryAgain) {
53189             history.perform(actionNoop());  // checkpoint
53190         }
53191
53192         context.container().call(loading);
53193
53194         if (toCheck.length) {
53195             context.connection().loadMultiple(toLoad, loaded);
53196         } else {
53197             upload();
53198         }
53199
53200
53201         function withChildNodes(ids, graph) {
53202             return lodash.uniq(lodash.reduce(ids, function(result, id) {
53203                 var entity = graph.entity(id);
53204                 if (entity.type === 'way') {
53205                     try {
53206                         var cn = graph.childNodes(entity);
53207                         result.push.apply(result, lodash.map(lodash.filter(cn, 'version'), 'id'));
53208                     } catch (err) {
53209                         /* eslint-disable no-console */
53210                         if (typeof console !== 'undefined') console.error(err);
53211                         /* eslint-enable no-console */
53212                     }
53213                 }
53214                 return result;
53215             }, lodash.clone(ids)));
53216         }
53217
53218
53219         // Reload modified entities into an alternate graph and check for conflicts..
53220         function loaded(err, result) {
53221             if (errors.length) return;
53222
53223             if (err) {
53224                 errors.push({
53225                     msg: err.responseText,
53226                     details: [ t('save.status_code', { code: err.status }) ]
53227                 });
53228                 showErrors();
53229
53230             } else {
53231                 var loadMore = [];
53232                 lodash.each(result.data, function(entity) {
53233                     remoteGraph.replace(entity);
53234                     toLoad = lodash.without(toLoad, entity.id);
53235
53236                     // Because loadMultiple doesn't download /full like loadEntity,
53237                     // need to also load children that aren't already being checked..
53238                     if (!entity.visible) return;
53239                     if (entity.type === 'way') {
53240                         loadMore.push.apply(loadMore,
53241                             lodash.difference(entity.nodes, toCheck, toLoad, loadMore));
53242                     } else if (entity.type === 'relation' && entity.isMultipolygon()) {
53243                         loadMore.push.apply(loadMore,
53244                             lodash.difference(lodash.map(entity.members, 'id'), toCheck, toLoad, loadMore));
53245                     }
53246                 });
53247
53248                 if (loadMore.length) {
53249                     toLoad.push.apply(toLoad, loadMore);
53250                     context.connection().loadMultiple(loadMore, loaded);
53251                 }
53252
53253                 if (!toLoad.length) {
53254                     checkConflicts();
53255                 }
53256             }
53257         }
53258
53259
53260         function checkConflicts() {
53261             function choice(id, text$$1, action) {
53262                 return { id: id, text: text$$1, action: function() { history.replace(action); } };
53263             }
53264             function formatUser(d) {
53265                 return '<a href="' + context.connection().userURL(d) + '" target="_blank">' + d + '</a>';
53266             }
53267             function entityName(entity) {
53268                 return utilDisplayName(entity) || (utilDisplayType(entity.id) + ' ' + entity.id);
53269             }
53270
53271             function compareVersions(local, remote) {
53272                 if (local.version !== remote.version) return false;
53273
53274                 if (local.type === 'way') {
53275                     var children = lodash.union(local.nodes, remote.nodes);
53276
53277                     for (var i = 0; i < children.length; i++) {
53278                         var a = localGraph.hasEntity(children[i]),
53279                             b = remoteGraph.hasEntity(children[i]);
53280
53281                         if (a && b && a.version !== b.version) return false;
53282                     }
53283                 }
53284
53285                 return true;
53286             }
53287
53288             lodash.each(toCheck, function(id) {
53289                 var local = localGraph.entity(id),
53290                     remote = remoteGraph.entity(id);
53291
53292                 if (compareVersions(local, remote)) return;
53293
53294                 var action = actionMergeRemoteChanges,
53295                     merge$$1 = action(id, localGraph, remoteGraph, formatUser);
53296
53297                 history.replace(merge$$1);
53298
53299                 var mergeConflicts = merge$$1.conflicts();
53300                 if (!mergeConflicts.length) return;  // merged safely
53301
53302                 var forceLocal = action(id, localGraph, remoteGraph).withOption('force_local'),
53303                     forceRemote = action(id, localGraph, remoteGraph).withOption('force_remote'),
53304                     keepMine = t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore')),
53305                     keepTheirs = t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
53306
53307                 conflicts.push({
53308                     id: id,
53309                     name: entityName(local),
53310                     details: mergeConflicts,
53311                     chosen: 1,
53312                     choices: [
53313                         choice(id, keepMine, forceLocal),
53314                         choice(id, keepTheirs, forceRemote)
53315                     ]
53316                 });
53317             });
53318
53319             upload();
53320         }
53321
53322
53323         function upload() {
53324             if (conflicts.length) {
53325                 conflicts.sort(function(a,b) { return b.id.localeCompare(a.id); });
53326                 showConflicts();
53327             } else if (errors.length) {
53328                 showErrors();
53329             } else {
53330                 var changes = history.changes(actionDiscardTags(history.difference()));
53331                 if (changes.modified.length || changes.created.length || changes.deleted.length) {
53332                     context.connection().putChangeset(changeset, changes, uploadCallback);
53333                 } else {        // changes were insignificant or reverted by user
53334                     select('.inspector-wrap *').remove();
53335                     loading.close();
53336                     context.flush();
53337                     cancel();
53338                 }
53339             }
53340         }
53341
53342
53343         function uploadCallback(err, changeset) {
53344             if (err) {
53345                 errors.push({
53346                     msg: err.responseText,
53347                     details: [ t('save.status_code', { code: err.status }) ]
53348                 });
53349                 showErrors();
53350             } else {
53351                 history.clearSaved();
53352                 success(changeset);
53353                 // Add delay to allow for postgres replication #1646 #2678
53354                 window.setTimeout(function() {
53355                     select('.inspector-wrap *').remove();
53356                     loading.close();
53357                     context.flush();
53358                 }, 2500);
53359             }
53360         }
53361
53362
53363         function showConflicts() {
53364             var selection$$1 = context.container()
53365                 .select('#sidebar')
53366                 .append('div')
53367                 .attr('class','sidebar-component');
53368
53369             loading.close();
53370
53371             selection$$1.call(uiConflicts(context)
53372                 .list(conflicts)
53373                 .on('download', function() {
53374                     var data = JXON.stringify(changeset.update({ id: 'CHANGEME' }).osmChangeJXON(origChanges)),
53375                         win = window.open('data:text/xml,' + encodeURIComponent(data), '_blank');
53376                     win.focus();
53377                 })
53378                 .on('cancel', function() {
53379                     history.pop();
53380                     selection$$1.remove();
53381                 })
53382                 .on('save', function() {
53383                     for (var i = 0; i < conflicts.length; i++) {
53384                         if (conflicts[i].chosen === 1) {  // user chose "keep theirs"
53385                             var entity = context.hasEntity(conflicts[i].id);
53386                             if (entity && entity.type === 'way') {
53387                                 var children = lodash.uniq(entity.nodes);
53388                                 for (var j = 0; j < children.length; j++) {
53389                                     history.replace(actionRevert(children[j]));
53390                                 }
53391                             }
53392                             history.replace(actionRevert(conflicts[i].id));
53393                         }
53394                     }
53395
53396                     selection$$1.remove();
53397                     save(changeset, true);
53398                 })
53399             );
53400         }
53401
53402
53403         function showErrors() {
53404             var selection$$1 = uiConfirm(context.container());
53405
53406             history.pop();
53407             loading.close();
53408
53409             selection$$1
53410                 .select('.modal-section.header')
53411                 .append('h3')
53412                 .text(t('save.error'));
53413
53414             addErrors(selection$$1, errors);
53415             selection$$1.okButton();
53416         }
53417
53418
53419         function addErrors(selection$$1, data) {
53420             var message = selection$$1
53421                 .select('.modal-section.message-text');
53422
53423             var items = message
53424                 .selectAll('.error-container')
53425                 .data(data);
53426
53427             var enter = items.enter()
53428                 .append('div')
53429                 .attr('class', 'error-container');
53430
53431             enter
53432                 .append('a')
53433                 .attr('class', 'error-description')
53434                 .attr('href', '#')
53435                 .classed('hide-toggle', true)
53436                 .text(function(d) { return d.msg || t('save.unknown_error_details'); })
53437                 .on('click', function() {
53438                     var error = select(this),
53439                         detail = select(this.nextElementSibling),
53440                         exp = error.classed('expanded');
53441
53442                     detail.style('display', exp ? 'none' : 'block');
53443                     error.classed('expanded', !exp);
53444
53445                     event.preventDefault();
53446                 });
53447
53448             var details = enter
53449                 .append('div')
53450                 .attr('class', 'error-detail-container')
53451                 .style('display', 'none');
53452
53453             details
53454                 .append('ul')
53455                 .attr('class', 'error-detail-list')
53456                 .selectAll('li')
53457                 .data(function(d) { return d.details || []; })
53458                 .enter()
53459                 .append('li')
53460                 .attr('class', 'error-detail-item')
53461                 .text(function(d) { return d; });
53462
53463             items.exit()
53464                 .remove();
53465         }
53466
53467     }
53468
53469
53470     function success(changeset) {
53471         commit.reset();
53472         context.enter(modeBrowse(context)
53473             .sidebar(uiSuccess(context)
53474                 .changeset(changeset)
53475                 .on('cancel', function() {
53476                     context.ui().sidebar.hide();
53477                 })
53478             )
53479         );
53480     }
53481
53482
53483     mode.enter = function() {
53484         function done() {
53485             context.ui().sidebar.show(commit);
53486         }
53487
53488         context.container().selectAll('#content')
53489             .attr('class', 'inactive');
53490
53491         if (context.connection().authenticated()) {
53492             done();
53493         } else {
53494             context.connection().authenticate(function(err) {
53495                 if (err) {
53496                     cancel();
53497                 } else {
53498                     done();
53499                 }
53500             });
53501         }
53502     };
53503
53504
53505     mode.exit = function() {
53506         context.container().selectAll('#content')
53507             .attr('class', 'active');
53508
53509         context.ui().sidebar.hide();
53510     };
53511
53512     return mode;
53513 }
53514
53515 // Translate a MacOS key command into the appropriate Windows/Linux equivalent.
53516 // For example, ⌘Z -> Ctrl+Z
53517 var uiCmd = function (code) {
53518     var detected = utilDetect();
53519
53520     if (detected.os === 'mac') {
53521         return code;
53522     }
53523
53524     if (detected.os === 'win') {
53525         if (code === '⌘⇧Z') return 'Ctrl+Y';
53526     }
53527
53528     var result = '',
53529         replacements = {
53530             '⌘': 'Ctrl',
53531             '⇧': 'Shift',
53532             '⌥': 'Alt',
53533             '⌫': 'Backspace',
53534             '⌦': 'Delete'
53535         };
53536
53537     for (var i = 0; i < code.length; i++) {
53538         if (code[i] in replacements) {
53539             result += replacements[code[i]] + (i < code.length - 1 ? '+' : '');
53540         } else {
53541             result += code[i];
53542         }
53543     }
53544
53545     return result;
53546 };
53547
53548
53549 // return a display-focused string for a given keyboard code
53550 uiCmd.display = function(code) {
53551     if (code.length !== 1) return code;
53552
53553     var detected = utilDetect();
53554     var mac = (detected.os === 'mac');
53555     var replacements = {
53556         '⌘': mac ? '⌘ ' + t('shortcuts.key.cmd')    : t('shortcuts.key.ctrl'),
53557         '⇧': mac ? '⇧ ' + t('shortcuts.key.shift')  : t('shortcuts.key.shift'),
53558         '⌥': mac ? '⌥ ' + t('shortcuts.key.option') : t('shortcuts.key.alt'),
53559         '⌃': mac ? '⌃ ' + t('shortcuts.key.ctrl')   : t('shortcuts.key.ctrl'),
53560         '⌫': mac ? '⌫ ' + t('shortcuts.key.delete') : t('shortcuts.key.backspace'),
53561         '⌦': mac ? '⌦ ' + t('shortcuts.key.del')    : t('shortcuts.key.del'),
53562         '↖': mac ? '↖ ' + t('shortcuts.key.pgup')   : t('shortcuts.key.pgup'),
53563         '↘': mac ? '↘ ' + t('shortcuts.key.pgdn')   : t('shortcuts.key.pgdn'),
53564         '⇞': mac ? '⇞ ' + t('shortcuts.key.home')   : t('shortcuts.key.home'),
53565         '⇟': mac ? '⇟ ' + t('shortcuts.key.end')    : t('shortcuts.key.end'),
53566         '↵': mac ? '↵ ' + t('shortcuts.key.return') : t('shortcuts.key.enter'),
53567         '⎋': mac ? '⎋ ' + t('shortcuts.key.esc')    : t('shortcuts.key.esc'),
53568     };
53569
53570     return replacements[code] || code;
53571 };
53572
53573 // deprecation warning - Radial Menu to be removed in iD v3
53574 var relatedParent;
53575
53576
53577 function modeSelect(context, selectedIDs) {
53578     var mode = {
53579         id: 'select',
53580         button: 'browse'
53581     };
53582
53583     var keybinding = d3keybinding('select'),
53584         timeout = null,
53585         behaviors = [
53586             behaviorCopy(context),
53587             behaviorPaste(context),
53588             behaviorBreathe(context),
53589             behaviorHover(context),
53590             behaviorSelect(context),
53591             behaviorLasso(context),
53592             modeDragNode$$1(context).selectedIDs(selectedIDs).behavior
53593         ],
53594         inspector,
53595         editMenu,
53596         newFeature = false,
53597         suppressMenu = true,
53598         follow = false;
53599
53600
53601     var wrap = context.container()
53602         .select('.inspector-wrap');
53603
53604
53605     function singular() {
53606         if (selectedIDs.length === 1) {
53607             return context.hasEntity(selectedIDs[0]);
53608         }
53609     }
53610
53611
53612     function checkSelectedIDs() {
53613         var ids = [];
53614         if (Array.isArray(selectedIDs)) {
53615             ids = selectedIDs.filter(function(id) {
53616                 return context.hasEntity(id);
53617             });
53618         }
53619
53620         if (ids.length) {
53621             selectedIDs = ids;
53622         } else {
53623             context.enter(modeBrowse(context));
53624         }
53625         return !!ids.length;
53626     }
53627
53628
53629     // find the common parent ways for nextVertex, previousVertex
53630     function commonParents() {
53631         var graph = context.graph(),
53632             commonParents = [];
53633
53634         for (var i = 0; i < selectedIDs.length; i++) {
53635             var entity = context.hasEntity(selectedIDs[i]);
53636             if (!entity || entity.geometry(graph) !== 'vertex') {
53637                 return [];  // selection includes some not vertexes
53638             }
53639
53640             var currParents = lodash.map(graph.parentWays(entity), 'id');
53641             if (!commonParents.length) {
53642                 commonParents = currParents;
53643                 continue;
53644             }
53645
53646             commonParents = lodash.intersection(commonParents, currParents);
53647             if (!commonParents.length) {
53648                 return [];
53649             }
53650         }
53651
53652         return commonParents;
53653     }
53654
53655
53656     function singularParent() {
53657         var parents = commonParents();
53658         if (!parents || parents.length === 0) {
53659             relatedParent = null;
53660             return null;
53661         }
53662
53663         // relatedParent is used when we visit a vertex with multiple
53664         // parents, and we want to remember which parent line we started on.
53665
53666         if (parents.length === 1) {
53667             relatedParent = parents[0];  // remember this parent for later
53668             return relatedParent;
53669         }
53670
53671         if (parents.indexOf(relatedParent) !== -1) {
53672             return relatedParent;   // prefer the previously seen parent
53673         }
53674
53675         return parents[0];
53676     }
53677
53678
53679     function closeMenu() {
53680         if (editMenu) {
53681             context.surface().call(editMenu.close);
53682         }
53683     }
53684
53685
53686     function positionMenu() {
53687         if (!editMenu) { return; }
53688
53689         var entity = singular();
53690         if (entity && context.geometry(entity.id) === 'relation') {
53691             suppressMenu = true;
53692         } else {
53693             var point = context.mouse(),
53694                 viewport = geoExtent$$1(context.projection.clipExtent()).polygon();
53695
53696             if (point && geoPointInPolygon(point, viewport)) {
53697                 editMenu.center(point);
53698             } else {
53699                 suppressMenu = true;
53700             }
53701         }
53702     }
53703
53704
53705     function showMenu() {
53706         closeMenu();
53707         if (editMenu) {
53708             context.surface().call(editMenu);
53709         }
53710     }
53711
53712
53713     function toggleMenu() {
53714         // deprecation warning - Radial Menu to be removed in iD v3
53715         if (select('.edit-menu, .radial-menu').empty()) {
53716             positionMenu();
53717             showMenu();
53718         } else {
53719             closeMenu();
53720         }
53721     }
53722
53723
53724     mode.selectedIDs = function() {
53725         return selectedIDs;
53726     };
53727
53728
53729     mode.reselect = function() {
53730         if (!checkSelectedIDs()) return;
53731
53732         var surfaceNode = context.surface().node();
53733         if (surfaceNode.focus) {   // FF doesn't support it
53734             surfaceNode.focus();
53735         }
53736
53737         positionMenu();
53738         if (!suppressMenu) {
53739             showMenu();
53740         }
53741     };
53742
53743
53744     mode.newFeature = function(_) {
53745         if (!arguments.length) return newFeature;
53746         newFeature = _;
53747         return mode;
53748     };
53749
53750
53751     mode.suppressMenu = function(_) {
53752         if (!arguments.length) return suppressMenu;
53753         suppressMenu = _;
53754         return mode;
53755     };
53756
53757
53758     mode.follow = function(_) {
53759         if (!arguments.length) return follow;
53760         follow = _;
53761         return mode;
53762     };
53763
53764
53765     mode.enter = function() {
53766
53767         function update() {
53768             closeMenu();
53769             checkSelectedIDs();
53770         }
53771
53772
53773         function dblclick() {
53774             var target = select(event.target),
53775                 datum = target.datum();
53776
53777             if (datum instanceof osmWay && !target.classed('fill')) {
53778                 var choice = geoChooseEdge(context.childNodes(datum), context.mouse(), context.projection),
53779                     prev = datum.nodes[choice.index - 1],
53780                     next = datum.nodes[choice.index];
53781
53782                 context.perform(
53783                     actionAddMidpoint({loc: choice.loc, edge: [prev, next]}, osmNode()),
53784                     t('operations.add.annotation.vertex')
53785                 );
53786
53787                 event.preventDefault();
53788                 event.stopPropagation();
53789
53790             } else if (datum.type === 'midpoint') {
53791                 context.perform(
53792                     actionAddMidpoint({loc: datum.loc, edge: datum.edge}, osmNode()),
53793                     t('operations.add.annotation.vertex'));
53794
53795                 event.preventDefault();
53796                 event.stopPropagation();
53797             }
53798         }
53799
53800
53801         function selectElements(drawn) {
53802             if (!checkSelectedIDs()) return;
53803
53804             var surface = context.surface(),
53805                 entity = singular();
53806
53807             if (entity && context.geometry(entity.id) === 'relation') {
53808                 suppressMenu = true;
53809                 return;
53810             }
53811
53812             surface.selectAll('.related')
53813                 .classed('related', false);
53814
53815             singularParent();
53816             if (relatedParent) {
53817                 surface.selectAll(utilEntitySelector([relatedParent]))
53818                     .classed('related', true);
53819             }
53820
53821             var selection$$1 = context.surface()
53822                 .selectAll(utilEntityOrMemberSelector(selectedIDs, context.graph()));
53823
53824             if (selection$$1.empty()) {
53825                 // Return to browse mode if selected DOM elements have
53826                 // disappeared because the user moved them out of view..
53827                 var source = event && event.type === 'zoom' && event.sourceEvent;
53828                 if (drawn && source && (source.type === 'mousemove' || source.type === 'touchmove')) {
53829                     context.enter(modeBrowse(context));
53830                 }
53831             } else {
53832                 selection$$1
53833                     .classed('selected', true);
53834             }
53835         }
53836
53837
53838         function esc() {
53839             context.enter(modeBrowse(context));
53840         }
53841
53842
53843         function firstVertex() {
53844             event.preventDefault();
53845             var parent = singularParent();
53846             if (parent) {
53847                 var way = context.entity(parent);
53848                 context.enter(
53849                     modeSelect(context, [way.first()]).follow(true)
53850                 );
53851             }
53852         }
53853
53854
53855         function lastVertex() {
53856             event.preventDefault();
53857             var parent = singularParent();
53858             if (parent) {
53859                 var way = context.entity(parent);
53860                 context.enter(
53861                     modeSelect(context, [way.last()]).follow(true)
53862                 );
53863             }
53864         }
53865
53866
53867         function previousVertex() {
53868             event.preventDefault();
53869             var parent = singularParent();
53870             if (!parent) return;
53871
53872             var way = context.entity(parent),
53873                 length = way.nodes.length,
53874                 curr = way.nodes.indexOf(selectedIDs[0]),
53875                 index = -1;
53876
53877             if (curr > 0) {
53878                 index = curr - 1;
53879             } else if (way.isClosed()) {
53880                 index = length - 2;
53881             }
53882
53883             if (index !== -1) {
53884                 context.enter(
53885                     modeSelect(context, [way.nodes[index]]).follow(true)
53886                 );
53887             }
53888         }
53889
53890
53891         function nextVertex() {
53892             event.preventDefault();
53893             var parent = singularParent();
53894             if (!parent) return;
53895
53896             var way = context.entity(parent),
53897                 length = way.nodes.length,
53898                 curr = way.nodes.indexOf(selectedIDs[0]),
53899                 index = -1;
53900
53901             if (curr < length - 1) {
53902                 index = curr + 1;
53903             } else if (way.isClosed()) {
53904                 index = 0;
53905             }
53906
53907             if (index !== -1) {
53908                 context.enter(
53909                     modeSelect(context, [way.nodes[index]]).follow(true)
53910                 );
53911             }
53912         }
53913
53914
53915         function nextParent() {
53916             event.preventDefault();
53917             var parents = lodash.uniq(commonParents());
53918             if (!parents || parents.length < 2) return;
53919
53920             var index = parents.indexOf(relatedParent);
53921             if (index < 0 || index > parents.length - 2) {
53922                 relatedParent = parents[0];
53923             } else {
53924                 relatedParent = parents[index + 1];
53925             }
53926
53927             var surface = context.surface();
53928             surface.selectAll('.related')
53929                 .classed('related', false);
53930
53931             if (relatedParent) {
53932                 surface.selectAll(utilEntitySelector([relatedParent]))
53933                     .classed('related', true);
53934             }
53935         }
53936
53937
53938         if (!checkSelectedIDs()) return;
53939
53940         var operations = lodash.without(values(Operations), operationDelete)
53941                 .map(function(o) { return o(selectedIDs, context); })
53942                 .filter(function(o) { return o.available(); });
53943
53944         // deprecation warning - Radial Menu to be removed in iD v3
53945         var isRadialMenu = context.storage('edit-menu-style') === 'radial';
53946         if (isRadialMenu) {
53947             operations = operations.slice(0,7);
53948             operations.unshift(operationDelete(selectedIDs, context));
53949         } else {
53950             operations.push(operationDelete(selectedIDs, context));
53951         }
53952
53953         operations.forEach(function(operation) {
53954             if (operation.behavior) {
53955                 behaviors.push(operation.behavior);
53956             }
53957         });
53958
53959         behaviors.forEach(function(behavior) {
53960             context.install(behavior);
53961         });
53962
53963         keybinding
53964             .on(['[', 'pgup'], previousVertex)
53965             .on([']', 'pgdown'], nextVertex)
53966             .on(['{', uiCmd('⌘['), 'home'], firstVertex)
53967             .on(['}', uiCmd('⌘]'), 'end'], lastVertex)
53968             .on(['\\', 'pause'], nextParent)
53969             .on('⎋', esc, true)
53970             .on('space', toggleMenu);
53971
53972         select(document)
53973             .call(keybinding);
53974
53975
53976         // deprecation warning - Radial Menu to be removed in iD v3
53977         editMenu = isRadialMenu
53978             ? uiRadialMenu(context, operations)
53979             : uiEditMenu(context, operations);
53980
53981         context.ui().sidebar
53982             .select(singular() ? singular().id : null, newFeature);
53983
53984         context.history()
53985             .on('undone.select', update)
53986             .on('redone.select', update);
53987
53988         context.map()
53989             .on('move.select', closeMenu)
53990             .on('drawn.select', selectElements);
53991
53992         context.surface()
53993             .on('dblclick.select', dblclick);
53994
53995
53996         selectElements();
53997
53998         if (selectedIDs.length > 1) {
53999             var entities = uiSelectionList(context, selectedIDs);
54000             context.ui().sidebar.show(entities);
54001         }
54002
54003         if (follow) {
54004             var extent$$1 = geoExtent$$1(),
54005                 graph = context.graph();
54006             selectedIDs.forEach(function(id) {
54007                 var entity = context.entity(id);
54008                 extent$$1._extend(entity.extent(graph));
54009             });
54010
54011             var loc = extent$$1.center();
54012             context.map().centerEase(loc);
54013         } else if (singular() && singular().type === 'way') {
54014             context.map().pan([0,0]);  // full redraw, to adjust z-sorting #2914
54015         }
54016
54017         timeout = window.setTimeout(function() {
54018             positionMenu();
54019             if (!suppressMenu) {
54020                 showMenu();
54021             }
54022         }, 270);  /* after any centerEase completes */
54023
54024     };
54025
54026
54027     mode.exit = function() {
54028         if (timeout) window.clearTimeout(timeout);
54029
54030         if (inspector) wrap.call(inspector.close);
54031
54032         behaviors.forEach(function(behavior) {
54033             context.uninstall(behavior);
54034         });
54035
54036         keybinding.off();
54037         closeMenu();
54038         editMenu = undefined;
54039
54040         context.history()
54041             .on('undone.select', null)
54042             .on('redone.select', null);
54043
54044         var surface = context.surface();
54045
54046         surface
54047             .on('dblclick.select', null);
54048
54049         surface
54050             .selectAll('.selected')
54051             .classed('selected', false);
54052
54053         surface
54054             .selectAll('.related')
54055             .classed('related', false);
54056
54057         context.map().on('drawn.select', null);
54058         context.ui().sidebar.hide();
54059     };
54060
54061
54062     return mode;
54063 }
54064
54065 function uiAccount(context) {
54066     var connection = context.connection();
54067
54068
54069     function update(selection$$1) {
54070         if (!connection.authenticated()) {
54071             selection$$1.selectAll('#userLink, #logoutLink')
54072                 .classed('hide', true);
54073             return;
54074         }
54075
54076         connection.userDetails(function(err, details) {
54077             var userLink = selection$$1.select('#userLink'),
54078                 logoutLink = selection$$1.select('#logoutLink');
54079
54080             userLink.html('');
54081             logoutLink.html('');
54082
54083             if (err) return;
54084
54085             selection$$1.selectAll('#userLink, #logoutLink')
54086                 .classed('hide', false);
54087
54088             // Link
54089             userLink.append('a')
54090                 .attr('href', connection.userURL(details.display_name))
54091                 .attr('target', '_blank');
54092
54093             // Add thumbnail or dont
54094             if (details.image_url) {
54095                 userLink.append('img')
54096                     .attr('class', 'icon pre-text user-icon')
54097                     .attr('src', details.image_url);
54098             } else {
54099                 userLink
54100                     .call(svgIcon('#icon-avatar', 'pre-text light'));
54101             }
54102
54103             // Add user name
54104             userLink.append('span')
54105                 .attr('class', 'label')
54106                 .text(details.display_name);
54107
54108             logoutLink.append('a')
54109                 .attr('class', 'logout')
54110                 .attr('href', '#')
54111                 .text(t('logout'))
54112                 .on('click.logout', function() {
54113                     event.preventDefault();
54114                     connection.logout();
54115                 });
54116         });
54117     }
54118
54119
54120     return function(selection$$1) {
54121         selection$$1.append('li')
54122             .attr('id', 'logoutLink')
54123             .classed('hide', true);
54124
54125         selection$$1.append('li')
54126             .attr('id', 'userLink')
54127             .classed('hide', true);
54128
54129         connection
54130             .on('change.account', function() { update(selection$$1); });
54131
54132         update(selection$$1);
54133     };
54134 }
54135
54136 function uiAttribution(context) {
54137     var selection$$1;
54138
54139
54140     function attribution(data, klass) {
54141         var div = selection$$1.selectAll('.' + klass)
54142             .data([0]);
54143
54144         div = div.enter()
54145             .append('div')
54146             .attr('class', klass)
54147             .merge(div);
54148
54149
54150         var background = div.selectAll('.attribution')
54151             .data(data, function(d) { return d.name(); });
54152
54153         background.exit()
54154             .remove();
54155
54156         background = background.enter()
54157             .append('span')
54158             .attr('class', 'attribution')
54159             .each(function(d) {
54160                 if (d.terms_html) {
54161                     select(this)
54162                         .html(d.terms_html);
54163                     return;
54164                 }
54165
54166                 var source = d.terms_text || d.id || d.name();
54167
54168                 if (d.logo) {
54169                     source = '<img class="source-image" src="' + context.imagePath(d.logo) + '">';
54170                 }
54171
54172                 if (d.terms_url) {
54173                     select(this)
54174                         .append('a')
54175                         .attr('href', d.terms_url)
54176                         .attr('target', '_blank')
54177                         .html(source);
54178                 } else {
54179                     select(this)
54180                         .text(source);
54181                 }
54182             })
54183             .merge(background);
54184
54185
54186         var copyright = background.selectAll('.copyright-notice')
54187             .data(function(d) {
54188                 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
54189                 return notice ? [notice] : [];
54190             });
54191
54192         copyright.exit()
54193             .remove();
54194
54195         copyright = copyright.enter()
54196             .append('span')
54197             .attr('class', 'copyright-notice')
54198             .merge(copyright);
54199
54200         copyright
54201             .text(String);
54202     }
54203
54204
54205     function update() {
54206         attribution([context.background().baseLayerSource()], 'base-layer-attribution');
54207         attribution(context.background().overlayLayerSources().filter(function (s) {
54208             return s.validZoom(context.map().zoom());
54209         }), 'overlay-layer-attribution');
54210     }
54211
54212
54213     return function(select$$1) {
54214         selection$$1 = select$$1;
54215
54216         context.background()
54217             .on('change.attribution', update);
54218
54219         context.map()
54220             .on('move.attribution', lodash.throttle(update, 400, {leading: false}));
54221
54222         update();
54223     };
54224 }
54225
54226 function rendererBackgroundSource(data) {
54227     var source = lodash.clone(data),
54228         offset = [0, 0],
54229         name = source.name,
54230         best = !!source.best;
54231
54232     source.scaleExtent = data.scaleExtent || [0, 20];
54233     source.overzoom = data.overzoom !== false;
54234
54235
54236     source.offset = function(_) {
54237         if (!arguments.length) return offset;
54238         offset = _;
54239         return source;
54240     };
54241
54242
54243     source.nudge = function(_, zoomlevel) {
54244         offset[0] += _[0] / Math.pow(2, zoomlevel);
54245         offset[1] += _[1] / Math.pow(2, zoomlevel);
54246         return source;
54247     };
54248
54249
54250     source.name = function() {
54251         return name;
54252     };
54253
54254
54255     source.best = function() {
54256         return best;
54257     };
54258
54259
54260     source.area = function() {
54261         if (!data.polygon) return Number.MAX_VALUE;  // worldwide
54262         var area$$1 = area({ type: 'MultiPolygon', coordinates: [ data.polygon ] });
54263         return isNaN(area$$1) ? 0 : area$$1;
54264     };
54265
54266
54267     source.imageryUsed = function() {
54268         return name || source.id;
54269     };
54270
54271
54272     source.url = function(coord) {
54273         return data.template
54274             .replace('{x}', coord[0])
54275             .replace('{y}', coord[1])
54276             // TMS-flipped y coordinate
54277             .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1)
54278             .replace(/\{z(oom)?\}/, coord[2])
54279             .replace(/\{switch:([^}]+)\}/, function(s, r) {
54280                 var subdomains = r.split(',');
54281                 return subdomains[(coord[0] + coord[1]) % subdomains.length];
54282             })
54283             .replace('{u}', function() {
54284                 var u = '';
54285                 for (var zoom$$1 = coord[2]; zoom$$1 > 0; zoom$$1--) {
54286                     var b = 0;
54287                     var mask = 1 << (zoom$$1 - 1);
54288                     if ((coord[0] & mask) !== 0) b++;
54289                     if ((coord[1] & mask) !== 0) b += 2;
54290                     u += b.toString();
54291                 }
54292                 return u;
54293             });
54294     };
54295
54296
54297     source.intersects = function(extent$$1) {
54298         extent$$1 = extent$$1.polygon();
54299         return !data.polygon || data.polygon.some(function(polygon) {
54300             return geoPolygonIntersectsPolygon(polygon, extent$$1, true);
54301         });
54302     };
54303
54304
54305     source.validZoom = function(z) {
54306         return source.scaleExtent[0] <= z &&
54307             (source.overzoom || source.scaleExtent[1] > z);
54308     };
54309
54310
54311     source.isLocatorOverlay = function() {
54312         return source.id === 'mapbox_locator_overlay';
54313     };
54314
54315
54316     source.copyrightNotices = function() {};
54317
54318
54319     return source;
54320 }
54321
54322
54323 rendererBackgroundSource.Bing = function(data, dispatch$$1) {
54324     // http://msdn.microsoft.com/en-us/library/ff701716.aspx
54325     // http://msdn.microsoft.com/en-us/library/ff701701.aspx
54326
54327     data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z';
54328
54329     var bing = rendererBackgroundSource(data),
54330         key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU', // Same as P2 and JOSM
54331         url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&key=' +
54332             key + '&jsonp={callback}',
54333         providers = [];
54334
54335     jsonpRequest(url, function(json$$1) {
54336         providers = json$$1.resourceSets[0].resources[0].imageryProviders.map(function(provider) {
54337             return {
54338                 attribution: provider.attribution,
54339                 areas: provider.coverageAreas.map(function(area$$1) {
54340                     return {
54341                         zoom: [area$$1.zoomMin, area$$1.zoomMax],
54342                         extent: geoExtent$$1([area$$1.bbox[1], area$$1.bbox[0]], [area$$1.bbox[3], area$$1.bbox[2]])
54343                     };
54344                 })
54345             };
54346         });
54347         dispatch$$1.call('change');
54348     });
54349
54350     bing.copyrightNotices = function(zoom$$1, extent$$1) {
54351         zoom$$1 = Math.min(zoom$$1, 21);
54352         return providers.filter(function(provider) {
54353             return lodash.some(provider.areas, function(area$$1) {
54354                 return extent$$1.intersects(area$$1.extent) &&
54355                     area$$1.zoom[0] <= zoom$$1 &&
54356                     area$$1.zoom[1] >= zoom$$1;
54357             });
54358         }).map(function(provider) {
54359             return provider.attribution;
54360         }).join(', ');
54361     };
54362
54363     bing.logo = 'bing_maps.png';
54364     bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
54365
54366     return bing;
54367 };
54368
54369
54370 rendererBackgroundSource.None = function() {
54371     var source = rendererBackgroundSource({ id: 'none', template: '' });
54372
54373     source.name = function() {
54374         return t('background.none');
54375     };
54376
54377     source.imageryUsed = function() {
54378         return 'None';
54379     };
54380
54381     source.area = function() {
54382         return -1;  // sources in background pane are sorted by area
54383     };
54384
54385     return source;
54386 };
54387
54388
54389 rendererBackgroundSource.Custom = function(template) {
54390     var source = rendererBackgroundSource({ id: 'custom', template: template });
54391
54392     source.name = function() {
54393         return t('background.custom');
54394     };
54395
54396     source.imageryUsed = function() {
54397         return 'Custom (' + template + ')';
54398     };
54399
54400     source.area = function() {
54401         return -2;  // sources in background pane are sorted by area
54402     };
54403
54404     return source;
54405 };
54406
54407 function rendererTileLayer(context) {
54408     var tileSize = 256,
54409         tile = d3geoTile(),
54410         projection$$1,
54411         cache = {},
54412         tileOrigin,
54413         z,
54414         transformProp = utilPrefixCSSProperty('Transform'),
54415         source = rendererBackgroundSource.None();
54416
54417
54418     // blacklist overlay tiles around Null Island..
54419     function nearNullIsland(x, y, z) {
54420         if (z >= 7) {
54421             var center = Math.pow(2, z - 1),
54422                 width = Math.pow(2, z - 6),
54423                 min$$1 = center - (width / 2),
54424                 max$$1 = center + (width / 2) - 1;
54425             return x >= min$$1 && x <= max$$1 && y >= min$$1 && y <= max$$1;
54426         }
54427         return false;
54428     }
54429
54430
54431     function tileSizeAtZoom(d, z) {
54432         var epsilon = 0.002;
54433         return ((tileSize * Math.pow(2, z - d[2])) / tileSize) + epsilon;
54434     }
54435
54436
54437     function atZoom(t, distance$$1) {
54438         var power = Math.pow(2, distance$$1);
54439         return [
54440             Math.floor(t[0] * power),
54441             Math.floor(t[1] * power),
54442             t[2] + distance$$1];
54443     }
54444
54445
54446     function lookUp(d) {
54447         for (var up = -1; up > -d[2]; up--) {
54448             var tile = atZoom(d, up);
54449             if (cache[source.url(tile)] !== false) {
54450                 return tile;
54451             }
54452         }
54453     }
54454
54455
54456     function uniqueBy(a, n) {
54457         var o = [], seen = {};
54458         for (var i = 0; i < a.length; i++) {
54459             if (seen[a[i][n]] === undefined) {
54460                 o.push(a[i]);
54461                 seen[a[i][n]] = true;
54462             }
54463         }
54464         return o;
54465     }
54466
54467
54468     function addSource(d) {
54469         d.push(source.url(d));
54470         return d;
54471     }
54472
54473
54474     // Update tiles based on current state of `projection`.
54475     function background(selection$$1) {
54476         tile.scale(projection$$1.scale() * 2 * Math.PI)
54477             .translate(projection$$1.translate());
54478
54479         tileOrigin = [
54480             projection$$1.scale() * Math.PI - projection$$1.translate()[0],
54481             projection$$1.scale() * Math.PI - projection$$1.translate()[1]];
54482
54483         z = Math.max(Math.log(projection$$1.scale() * 2 * Math.PI) / Math.log(2) - 8, 0);
54484
54485         render(selection$$1);
54486     }
54487
54488
54489     // Derive the tiles onscreen, remove those offscreen and position them.
54490     // Important that this part not depend on `projection` because it's
54491     // rentered when tiles load/error (see #644).
54492     function render(selection$$1) {
54493         var requests = [];
54494         var showDebug = context.getDebug('tile') && !source.overlay;
54495
54496         if (source.validZoom(z)) {
54497             tile().forEach(function(d) {
54498                 addSource(d);
54499                 if (d[3] === '') return;
54500                 if (typeof d[3] !== 'string') return; // Workaround for chrome crash https://github.com/openstreetmap/iD/issues/2295
54501                 requests.push(d);
54502                 if (cache[d[3]] === false && lookUp(d)) {
54503                     requests.push(addSource(lookUp(d)));
54504                 }
54505             });
54506
54507             requests = uniqueBy(requests, 3).filter(function(r) {
54508                 if (!!source.overlay && nearNullIsland(r[0], r[1], r[2])) {
54509                     return false;
54510                 }
54511                 // don't re-request tiles which have failed in the past
54512                 return cache[r[3]] !== false;
54513             });
54514         }
54515
54516         var pixelOffset = [
54517             source.offset()[0] * Math.pow(2, z),
54518             source.offset()[1] * Math.pow(2, z)
54519         ];
54520
54521         function load(d) {
54522             cache[d[3]] = true;
54523             select(this)
54524                 .on('error', null)
54525                 .on('load', null)
54526                 .classed('tile-loaded', true);
54527             render(selection$$1);
54528         }
54529
54530         function error(d) {
54531             cache[d[3]] = false;
54532             select(this)
54533                 .on('error', null)
54534                 .on('load', null)
54535                 .remove();
54536             render(selection$$1);
54537         }
54538
54539         function imageTransform(d) {
54540             var _ts = tileSize * Math.pow(2, z - d[2]);
54541             var scale = tileSizeAtZoom(d, z);
54542             return 'translate(' +
54543                 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0]) + 'px,' +
54544                 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1]) + 'px)' +
54545                 'scale(' + scale + ',' + scale + ')';
54546         }
54547
54548         function debugTransform(d) {
54549             var _ts = tileSize * Math.pow(2, z - d[2]);
54550             var scale = tileSizeAtZoom(d, z);
54551             return 'translate(' +
54552                 ((d[0] * _ts) - tileOrigin[0] + pixelOffset[0] + scale * (tileSize / 4)) + 'px,' +
54553                 ((d[1] * _ts) - tileOrigin[1] + pixelOffset[1] + scale * (tileSize / 2)) + 'px)';
54554         }
54555
54556
54557         var image = selection$$1.selectAll('img')
54558             .data(requests, function(d) { return d[3]; });
54559
54560         image.exit()
54561             .style(transformProp, imageTransform)
54562             .classed('tile-removing', true)
54563             .each(function() {
54564                 var tile = select(this);
54565                 window.setTimeout(function() {
54566                     if (tile.classed('tile-removing')) {
54567                         tile.remove();
54568                     }
54569                 }, 300);
54570             });
54571
54572         image.enter()
54573           .append('img')
54574             .attr('class', 'tile')
54575             .attr('src', function(d) { return d[3]; })
54576             .on('error', error)
54577             .on('load', load)
54578           .merge(image)
54579             .style(transformProp, imageTransform)
54580             .classed('tile-debug', showDebug)
54581             .classed('tile-removing', false);
54582
54583
54584         var debug = selection$$1.selectAll('.tile-label-debug')
54585             .data(showDebug ? requests : [], function(d) { return d[3]; });
54586
54587         debug.exit()
54588             .remove();
54589
54590         debug.enter()
54591           .append('div')
54592             .attr('class', 'tile-label-debug')
54593           .merge(debug)
54594             .text(function(d) { return d[2] + ' / ' + d[0] + ' / ' + d[1]; })
54595             .style(transformProp, debugTransform);
54596     }
54597
54598
54599     background.projection = function(_) {
54600         if (!arguments.length) return projection$$1;
54601         projection$$1 = _;
54602         return background;
54603     };
54604
54605
54606     background.dimensions = function(_) {
54607         if (!arguments.length) return tile.size();
54608         tile.size(_);
54609         return background;
54610     };
54611
54612
54613     background.source = function(_) {
54614         if (!arguments.length) return source;
54615         source = _;
54616         cache = {};
54617         tile.scaleExtent(source.scaleExtent);
54618         return background;
54619     };
54620
54621
54622     return background;
54623 }
54624
54625 function rendererBackground(context) {
54626     var dispatch$$1 = dispatch('change'),
54627         baseLayer = rendererTileLayer(context).projection(context.projection),
54628         overlayLayers = [],
54629         backgroundSources;
54630
54631
54632     function findSource(id) {
54633         return lodash.find(backgroundSources, function(d) {
54634             return d.id && d.id === id;
54635         });
54636     }
54637
54638
54639     function background(selection$$1) {
54640         var base = selection$$1.selectAll('.layer-background')
54641             .data([0]);
54642
54643         base.enter()
54644             .insert('div', '.layer-data')
54645             .attr('class', 'layer layer-background')
54646             .merge(base)
54647             .call(baseLayer);
54648
54649         var overlays = selection$$1.selectAll('.layer-overlay')
54650             .data(overlayLayers, function(d) { return d.source().name(); });
54651
54652         overlays.exit()
54653             .remove();
54654
54655         overlays.enter()
54656             .insert('div', '.layer-data')
54657             .attr('class', 'layer layer-overlay')
54658             .merge(overlays)
54659             .each(function(layer) { select(this).call(layer); });
54660     }
54661
54662
54663     background.updateImagery = function() {
54664         if (context.inIntro()) return;
54665
54666         var b = background.baseLayerSource(),
54667             o = overlayLayers
54668                 .filter(function (d) { return !d.source().isLocatorOverlay(); })
54669                 .map(function (d) { return d.source().id; })
54670                 .join(','),
54671             meters = geoOffsetToMeters(b.offset()),
54672             epsilon = 0.01,
54673             x = +meters[0].toFixed(2),
54674             y = +meters[1].toFixed(2),
54675             q = utilStringQs(window.location.hash.substring(1));
54676
54677         var id = b.id;
54678         if (id === 'custom') {
54679             id = 'custom:' + b.template;
54680         }
54681
54682         if (id) {
54683             q.background = id;
54684         } else {
54685             delete q.background;
54686         }
54687
54688         if (o) {
54689             q.overlays = o;
54690         } else {
54691             delete q.overlays;
54692         }
54693
54694         if (Math.abs(x) > epsilon || Math.abs(y) > epsilon) {
54695             q.offset = x + ',' + y;
54696         } else {
54697             delete q.offset;
54698         }
54699
54700         window.location.replace('#' + utilQsString(q, true));
54701
54702         var imageryUsed = [b.imageryUsed()];
54703
54704         overlayLayers
54705             .filter(function (d) { return !d.source().isLocatorOverlay(); })
54706             .forEach(function (d) { imageryUsed.push(d.source().imageryUsed()); });
54707
54708         var gpx = context.layers().layer('gpx');
54709         if (gpx && gpx.enabled() && gpx.hasGpx()) {
54710             imageryUsed.push('Local GPX');
54711         }
54712
54713         var mapillary_images = context.layers().layer('mapillary-images');
54714         if (mapillary_images && mapillary_images.enabled()) {
54715             imageryUsed.push('Mapillary Images');
54716         }
54717
54718         var mapillary_signs = context.layers().layer('mapillary-signs');
54719         if (mapillary_signs && mapillary_signs.enabled()) {
54720             imageryUsed.push('Mapillary Signs');
54721         }
54722
54723         context.history().imageryUsed(imageryUsed);
54724     };
54725
54726
54727     background.sources = function(extent$$1) {
54728         return backgroundSources.filter(function(source) {
54729             return source.intersects(extent$$1);
54730         });
54731     };
54732
54733
54734     background.dimensions = function(_) {
54735         if (!_) return;
54736         baseLayer.dimensions(_);
54737
54738         overlayLayers.forEach(function(layer) {
54739             layer.dimensions(_);
54740         });
54741     };
54742
54743
54744     background.baseLayerSource = function(d) {
54745         if (!arguments.length) return baseLayer.source();
54746
54747         // test source against OSM imagery blacklists..
54748         var blacklists = context.connection().imageryBlacklists();
54749
54750         var fail = false,
54751             tested = 0,
54752             regex, i;
54753
54754         for (i = 0; i < blacklists.length; i++) {
54755             try {
54756                 regex = new RegExp(blacklists[i]);
54757                 fail = regex.test(d.template);
54758                 tested++;
54759                 if (fail) break;
54760             } catch (e) {
54761                 /* noop */
54762             }
54763         }
54764
54765         // ensure at least one test was run.
54766         if (!tested) {
54767             regex = new RegExp('.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*');
54768             fail = regex.test(d.template);
54769         }
54770
54771         baseLayer.source(!fail ? d : rendererBackgroundSource.None());
54772         dispatch$$1.call('change');
54773         background.updateImagery();
54774         return background;
54775     };
54776
54777
54778     background.bing = function() {
54779         background.baseLayerSource(findSource('Bing'));
54780     };
54781
54782
54783     background.showsLayer = function(d) {
54784         return d.id === baseLayer.source().id ||
54785             overlayLayers.some(function(layer) { return d.id === layer.source().id; });
54786     };
54787
54788
54789     background.overlayLayerSources = function() {
54790         return overlayLayers.map(function (l) { return l.source(); });
54791     };
54792
54793
54794     background.toggleOverlayLayer = function(d) {
54795         var layer;
54796
54797         for (var i = 0; i < overlayLayers.length; i++) {
54798             layer = overlayLayers[i];
54799             if (layer.source() === d) {
54800                 overlayLayers.splice(i, 1);
54801                 dispatch$$1.call('change');
54802                 background.updateImagery();
54803                 return;
54804             }
54805         }
54806
54807         layer = rendererTileLayer(context)
54808             .source(d)
54809             .projection(context.projection)
54810             .dimensions(baseLayer.dimensions());
54811
54812         overlayLayers.push(layer);
54813         dispatch$$1.call('change');
54814         background.updateImagery();
54815     };
54816
54817
54818     background.nudge = function(d, zoom$$1) {
54819         baseLayer.source().nudge(d, zoom$$1);
54820         dispatch$$1.call('change');
54821         background.updateImagery();
54822         return background;
54823     };
54824
54825
54826     background.offset = function(d) {
54827         if (!arguments.length) return baseLayer.source().offset();
54828         baseLayer.source().offset(d);
54829         dispatch$$1.call('change');
54830         background.updateImagery();
54831         return background;
54832     };
54833
54834
54835     background.init = function() {
54836         function parseMap(qmap) {
54837             if (!qmap) return false;
54838             var args = qmap.split('/').map(Number);
54839             if (args.length < 3 || args.some(isNaN)) return false;
54840             return geoExtent$$1([args[2], args[1]]);
54841         }
54842
54843         var dataImagery = data.imagery || [],
54844             q = utilStringQs(window.location.hash.substring(1)),
54845             chosen = q.background || q.layer,
54846             extent$$1 = parseMap(q.map),
54847             best;
54848
54849         backgroundSources = dataImagery.map(function(source) {
54850             if (source.type === 'bing') {
54851                 return rendererBackgroundSource.Bing(source, dispatch$$1);
54852             } else {
54853                 return rendererBackgroundSource(source);
54854             }
54855         });
54856
54857         backgroundSources.unshift(rendererBackgroundSource.None());
54858
54859         if (!chosen && extent$$1) {
54860             best = lodash.find(this.sources(extent$$1), function(s) { return s.best(); });
54861         }
54862
54863         if (chosen && chosen.indexOf('custom:') === 0) {
54864             background.baseLayerSource(rendererBackgroundSource.Custom(chosen.replace(/^custom:/, '')));
54865         } else {
54866             background.baseLayerSource(findSource(chosen) || best || findSource('Bing') || backgroundSources[1] || backgroundSources[0]);
54867         }
54868
54869         var locator = lodash.find(backgroundSources, function(d) {
54870             return d.overlay && d.default;
54871         });
54872
54873         if (locator) {
54874             background.toggleOverlayLayer(locator);
54875         }
54876
54877         var overlays = (q.overlays || '').split(',');
54878         overlays.forEach(function(overlay) {
54879             overlay = findSource(overlay);
54880             if (overlay) {
54881                 background.toggleOverlayLayer(overlay);
54882             }
54883         });
54884
54885         if (q.gpx) {
54886             var gpx = context.layers().layer('gpx');
54887             if (gpx) {
54888                 gpx.url(q.gpx);
54889             }
54890         }
54891
54892         if (q.offset) {
54893             var offset = q.offset.replace(/;/g, ',').split(',').map(function(n) {
54894                 return !isNaN(n) && n;
54895             });
54896
54897             if (offset.length === 2) {
54898                 background.offset(geoMetersToOffset(offset));
54899             }
54900         }
54901     };
54902
54903
54904     return utilRebind(background, dispatch$$1, 'on');
54905 }
54906
54907 function rendererFeatures(context) {
54908     var traffic_roads = {
54909         'motorway': true,
54910         'motorway_link': true,
54911         'trunk': true,
54912         'trunk_link': true,
54913         'primary': true,
54914         'primary_link': true,
54915         'secondary': true,
54916         'secondary_link': true,
54917         'tertiary': true,
54918         'tertiary_link': true,
54919         'residential': true,
54920         'unclassified': true,
54921         'living_street': true
54922     };
54923
54924     var service_roads = {
54925         'service': true,
54926         'road': true,
54927         'track': true
54928     };
54929
54930     var paths = {
54931         'path': true,
54932         'footway': true,
54933         'cycleway': true,
54934         'bridleway': true,
54935         'steps': true,
54936         'pedestrian': true,
54937         'corridor': true
54938     };
54939
54940     var past_futures = {
54941         'proposed': true,
54942         'construction': true,
54943         'abandoned': true,
54944         'dismantled': true,
54945         'disused': true,
54946         'razed': true,
54947         'demolished': true,
54948         'obliterated': true
54949     };
54950
54951     var dispatch$$1 = dispatch('change', 'redraw'),
54952         _cullFactor = 1,
54953         _cache = {},
54954         _features = {},
54955         _stats = {},
54956         _keys = [],
54957         _hidden = [];
54958
54959
54960     function update() {
54961         _hidden = features.hidden();
54962         dispatch$$1.call('change');
54963         dispatch$$1.call('redraw');
54964     }
54965
54966
54967     function defineFeature(k, filter, max$$1) {
54968         _keys.push(k);
54969         _features[k] = {
54970             filter: filter,
54971             enabled: true,   // whether the user wants it enabled..
54972             count: 0,
54973             currentMax: (max$$1 || Infinity),
54974             defaultMax: (max$$1 || Infinity),
54975             enable: function() { this.enabled = true; this.currentMax = this.defaultMax; },
54976             disable: function() { this.enabled = false; this.currentMax = 0; },
54977             hidden: function() { return !context.editable() || this.count > this.currentMax * _cullFactor; },
54978             autoHidden: function() { return this.hidden() && this.currentMax > 0; }
54979         };
54980     }
54981
54982
54983     defineFeature('points', function isPoint(entity, resolver, geometry) {
54984         return geometry === 'point';
54985     }, 200);
54986
54987     defineFeature('traffic_roads', function isTrafficRoad(entity) {
54988         return traffic_roads[entity.tags.highway];
54989     });
54990
54991     defineFeature('service_roads', function isServiceRoad(entity) {
54992         return service_roads[entity.tags.highway];
54993     });
54994
54995     defineFeature('paths', function isPath(entity) {
54996         return paths[entity.tags.highway];
54997     });
54998
54999     defineFeature('buildings', function isBuilding(entity) {
55000         return (
55001             !!entity.tags['building:part'] ||
55002             (!!entity.tags.building && entity.tags.building !== 'no') ||
55003             entity.tags.amenity === 'shelter' ||
55004             entity.tags.parking === 'multi-storey' ||
55005             entity.tags.parking === 'sheds' ||
55006             entity.tags.parking === 'carports' ||
55007             entity.tags.parking === 'garage_boxes'
55008         );
55009     }, 250);
55010
55011     defineFeature('landuse', function isLanduse(entity, resolver, geometry) {
55012         return geometry === 'area' &&
55013             !_features.buildings.filter(entity) &&
55014             !_features.water.filter(entity);
55015     });
55016
55017     defineFeature('boundaries', function isBoundary(entity) {
55018         return !!entity.tags.boundary;
55019     });
55020
55021     defineFeature('water', function isWater(entity) {
55022         return (
55023             !!entity.tags.waterway ||
55024             entity.tags.natural === 'water' ||
55025             entity.tags.natural === 'coastline' ||
55026             entity.tags.natural === 'bay' ||
55027             entity.tags.landuse === 'pond' ||
55028             entity.tags.landuse === 'basin' ||
55029             entity.tags.landuse === 'reservoir' ||
55030             entity.tags.landuse === 'salt_pond'
55031         );
55032     });
55033
55034     defineFeature('rail', function isRail(entity) {
55035         return (
55036             !!entity.tags.railway ||
55037             entity.tags.landuse === 'railway'
55038         ) && !(
55039             traffic_roads[entity.tags.highway] ||
55040             service_roads[entity.tags.highway] ||
55041             paths[entity.tags.highway]
55042         );
55043     });
55044
55045     defineFeature('power', function isPower(entity) {
55046         return !!entity.tags.power;
55047     });
55048
55049     // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
55050     defineFeature('past_future', function isPastFuture(entity) {
55051         if (
55052             traffic_roads[entity.tags.highway] ||
55053             service_roads[entity.tags.highway] ||
55054             paths[entity.tags.highway]
55055         ) { return false; }
55056
55057         var strings = Object.keys(entity.tags);
55058
55059         for (var i = 0; i < strings.length; i++) {
55060             var s = strings[i];
55061             if (past_futures[s] || past_futures[entity.tags[s]]) { return true; }
55062         }
55063         return false;
55064     });
55065
55066     // Lines or areas that don't match another feature filter.
55067     // IMPORTANT: The 'others' feature must be the last one defined,
55068     //   so that code in getMatches can skip this test if `hasMatch = true`
55069     defineFeature('others', function isOther(entity, resolver, geometry) {
55070         return (geometry === 'line' || geometry === 'area');
55071     });
55072
55073
55074     function features() {}
55075
55076
55077     features.features = function() {
55078         return _features;
55079     };
55080
55081
55082     features.keys = function() {
55083         return _keys;
55084     };
55085
55086
55087     features.enabled = function(k) {
55088         if (!arguments.length) {
55089             return _keys.filter(function(k) { return _features[k].enabled; });
55090         }
55091         return _features[k] && _features[k].enabled;
55092     };
55093
55094
55095     features.disabled = function(k) {
55096         if (!arguments.length) {
55097             return _keys.filter(function(k) { return !_features[k].enabled; });
55098         }
55099         return _features[k] && !_features[k].enabled;
55100     };
55101
55102
55103     features.hidden = function(k) {
55104         if (!arguments.length) {
55105             return _keys.filter(function(k) { return _features[k].hidden(); });
55106         }
55107         return _features[k] && _features[k].hidden();
55108     };
55109
55110
55111     features.autoHidden = function(k) {
55112         if (!arguments.length) {
55113             return _keys.filter(function(k) { return _features[k].autoHidden(); });
55114         }
55115         return _features[k] && _features[k].autoHidden();
55116     };
55117
55118
55119     features.enable = function(k) {
55120         if (_features[k] && !_features[k].enabled) {
55121             _features[k].enable();
55122             update();
55123         }
55124     };
55125
55126
55127     features.disable = function(k) {
55128         if (_features[k] && _features[k].enabled) {
55129             _features[k].disable();
55130             update();
55131         }
55132     };
55133
55134
55135     features.toggle = function(k) {
55136         if (_features[k]) {
55137             (function(f) { return f.enabled ? f.disable() : f.enable(); }(_features[k]));
55138             update();
55139         }
55140     };
55141
55142
55143     features.resetStats = function() {
55144         for (var i = 0; i < _keys.length; i++) {
55145             _features[_keys[i]].count = 0;
55146         }
55147         dispatch$$1.call('change');
55148     };
55149
55150
55151     features.gatherStats = function(d, resolver, dimensions) {
55152         var needsRedraw = false,
55153             type = lodash.groupBy(d, function(ent) { return ent.type; }),
55154             entities = [].concat(type.relation || [], type.way || [], type.node || []),
55155             currHidden, geometry, matches, i, j;
55156
55157         for (i = 0; i < _keys.length; i++) {
55158             _features[_keys[i]].count = 0;
55159         }
55160
55161         // adjust the threshold for point/building culling based on viewport size..
55162         // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
55163         _cullFactor = dimensions[0] * dimensions[1] / 1000000;
55164
55165         for (i = 0; i < entities.length; i++) {
55166             geometry = entities[i].geometry(resolver);
55167             if (!(geometry === 'vertex' || geometry === 'relation')) {
55168                 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
55169                 for (j = 0; j < matches.length; j++) {
55170                     _features[matches[j]].count++;
55171                 }
55172             }
55173         }
55174
55175         currHidden = features.hidden();
55176         if (currHidden !== _hidden) {
55177             _hidden = currHidden;
55178             needsRedraw = true;
55179             dispatch$$1.call('change');
55180         }
55181
55182         return needsRedraw;
55183     };
55184
55185
55186     features.stats = function() {
55187         for (var i = 0; i < _keys.length; i++) {
55188             _stats[_keys[i]] = _features[_keys[i]].count;
55189         }
55190
55191         return _stats;
55192     };
55193
55194
55195     features.clear = function(d) {
55196         for (var i = 0; i < d.length; i++) {
55197             features.clearEntity(d[i]);
55198         }
55199     };
55200
55201
55202     features.clearEntity = function(entity) {
55203         delete _cache[osmEntity$$1.key(entity)];
55204     };
55205
55206
55207     features.reset = function() {
55208         _cache = {};
55209     };
55210
55211
55212     features.getMatches = function(entity, resolver, geometry) {
55213         if (geometry === 'vertex' || geometry === 'relation') return {};
55214
55215         var ent = osmEntity$$1.key(entity);
55216         if (!_cache[ent]) {
55217             _cache[ent] = {};
55218         }
55219
55220         if (!_cache[ent].matches) {
55221             var matches = {},
55222                 hasMatch = false;
55223
55224             for (var i = 0; i < _keys.length; i++) {
55225                 if (_keys[i] === 'others') {
55226                     if (hasMatch) continue;
55227
55228                     // Multipolygon members:
55229                     // If an entity...
55230                     //   1. is a way that hasn't matched other 'interesting' feature rules,
55231                     //   2. and it belongs to a single parent multipolygon relation
55232                     // ...then match whatever feature rules the parent multipolygon has matched.
55233                     // see #2548, #2887
55234                     //
55235                     // IMPORTANT:
55236                     // For this to work, getMatches must be called on relations before ways.
55237                     //
55238                     if (entity.type === 'way') {
55239                         var parents = features.getParents(entity, resolver, geometry);
55240                         if (parents.length === 1 && parents[0].isMultipolygon()) {
55241                             var pkey = osmEntity$$1.key(parents[0]);
55242                             if (_cache[pkey] && _cache[pkey].matches) {
55243                                 matches = lodash.clone(_cache[pkey].matches);
55244                                 continue;
55245                             }
55246                         }
55247                     }
55248                 }
55249
55250                 if (_features[_keys[i]].filter(entity, resolver, geometry)) {
55251                     matches[_keys[i]] = hasMatch = true;
55252                 }
55253             }
55254             _cache[ent].matches = matches;
55255         }
55256
55257         return _cache[ent].matches;
55258     };
55259
55260
55261     features.getParents = function(entity, resolver, geometry) {
55262         if (geometry === 'point') return [];
55263
55264         var ent = osmEntity$$1.key(entity);
55265         if (!_cache[ent]) {
55266             _cache[ent] = {};
55267         }
55268
55269         if (!_cache[ent].parents) {
55270             var parents = [];
55271             if (geometry === 'vertex') {
55272                 parents = resolver.parentWays(entity);
55273             } else {   // 'line', 'area', 'relation'
55274                 parents = resolver.parentRelations(entity);
55275             }
55276             _cache[ent].parents = parents;
55277         }
55278         return _cache[ent].parents;
55279     };
55280
55281
55282     features.isHiddenFeature = function(entity, resolver, geometry) {
55283         if (!_hidden.length) return false;
55284         if (!entity.version) return false;
55285
55286         var matches = features.getMatches(entity, resolver, geometry);
55287
55288         for (var i = 0; i < _hidden.length; i++) {
55289             if (matches[_hidden[i]]) return true;
55290         }
55291         return false;
55292     };
55293
55294
55295     features.isHiddenChild = function(entity, resolver, geometry) {
55296         if (!_hidden.length) return false;
55297         if (!entity.version || geometry === 'point') return false;
55298
55299         var parents = features.getParents(entity, resolver, geometry);
55300         if (!parents.length) return false;
55301
55302         for (var i = 0; i < parents.length; i++) {
55303             if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
55304                 return false;
55305             }
55306         }
55307         return true;
55308     };
55309
55310
55311     features.hasHiddenConnections = function(entity, resolver) {
55312         if (!_hidden.length) return false;
55313         var childNodes, connections;
55314
55315         if (entity.type === 'midpoint') {
55316             childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
55317             connections = [];
55318         } else {
55319             childNodes = entity.nodes ? resolver.childNodes(entity) : [];
55320             connections = features.getParents(entity, resolver, entity.geometry(resolver));
55321         }
55322
55323         // gather ways connected to child nodes..
55324         connections = lodash.reduce(childNodes, function(result, e) {
55325             return resolver.isShared(e) ? lodash.union(result, resolver.parentWays(e)) : result;
55326         }, connections);
55327
55328         return connections.length ? lodash.some(connections, function(e) {
55329             return features.isHidden(e, resolver, e.geometry(resolver));
55330         }) : false;
55331     };
55332
55333
55334     features.isHidden = function(entity, resolver, geometry) {
55335         if (!_hidden.length) return false;
55336         if (!entity.version) return false;
55337
55338         var fn = (geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature);
55339         return fn(entity, resolver, geometry);
55340     };
55341
55342
55343     features.filter = function(d, resolver) {
55344         if (!_hidden.length) return d;
55345
55346         var result = [];
55347         for (var i = 0; i < d.length; i++) {
55348             var entity = d[i];
55349             if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
55350                 result.push(entity);
55351             }
55352         }
55353         return result;
55354     };
55355
55356
55357     return utilRebind(features, dispatch$$1, 'on');
55358 }
55359
55360 function utilBindOnce(target, type, listener, capture) {
55361     var typeOnce = type + '.once';
55362     function one() {
55363         target.on(typeOnce, null);
55364         listener.apply(this, arguments);
55365     }
55366     target.on(typeOnce, one, capture);
55367     return this;
55368 }
55369
55370 function rendererMap(context) {
55371
55372     var dimensions = [1, 1],
55373         dispatch$$1 = dispatch('move', 'drawn'),
55374         projection$$1 = context.projection,
55375         curtainProjection = context.curtainProjection,
55376         dblclickEnabled = true,
55377         redrawEnabled = true,
55378         transformStart = projection$$1.transform(),
55379         transformLast,
55380         transformed = false,
55381         minzoom = 0,
55382         drawLayers = svgLayers(projection$$1, context),
55383         drawPoints = svgPoints$$1(projection$$1, context),
55384         drawVertices = svgVertices$$1(projection$$1, context),
55385         drawLines = svgLines$$1(projection$$1, context),
55386         drawAreas = svgAreas$$1(projection$$1, context),
55387         drawMidpoints = svgMidpoints$$1(projection$$1, context),
55388         drawLabels = svgLabels(projection$$1, context),
55389         supersurface = select(null),
55390         wrapper = select(null),
55391         surface = select(null),
55392         mouse$$1,
55393         mousemove;
55394
55395     var zoom$$1 = zoom()
55396             .scaleExtent([ztok(2), ztok(24)])
55397             .interpolate(interpolateValue)
55398             .filter(zoomEventFilter)
55399             .on('zoom', zoomPan);
55400
55401     var _selection = select(null);
55402
55403
55404     function map(selection$$1) {
55405
55406         _selection = selection$$1;
55407
55408         context
55409             .on('change.map', immediateRedraw);
55410
55411         context.connection()
55412             .on('change.map', immediateRedraw);
55413
55414         context.history()
55415             .on('change.map', immediateRedraw)
55416             .on('undone.map redone.map', function(stack$$1) {
55417                 var mode = context.mode().id;
55418                 if (mode !== 'browse' && mode !== 'select') return;
55419
55420                 var followSelected = false;
55421                 if (Array.isArray(stack$$1.selectedIDs)) {
55422                     followSelected = (stack$$1.selectedIDs.length === 1 && stack$$1.selectedIDs[0][0] === 'n');
55423                     context.enter(
55424                         modeSelect(context, stack$$1.selectedIDs).follow(followSelected)
55425                     );
55426                 }
55427                 if (!followSelected && stack$$1.transform) {
55428                     map.transformEase(stack$$1.transform);
55429                 }
55430             });
55431
55432         context.background()
55433             .on('change.map', immediateRedraw);
55434
55435         context.features()
55436             .on('redraw.map', immediateRedraw);
55437
55438         drawLayers
55439             .on('change.map', function() {
55440                 context.background().updateImagery();
55441                 immediateRedraw();
55442             });
55443
55444         selection$$1
55445             .on('dblclick.map', dblClick)
55446             .call(zoom$$1)
55447             .call(zoom$$1.transform, projection$$1.transform());
55448
55449         supersurface = selection$$1.append('div')
55450             .attr('id', 'supersurface')
55451             .call(utilSetTransform, 0, 0);
55452
55453         // Need a wrapper div because Opera can't cope with an absolutely positioned
55454         // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
55455         wrapper = supersurface
55456             .append('div')
55457             .attr('class', 'layer layer-data');
55458
55459         map.surface = surface = wrapper
55460             .call(drawLayers)
55461             .selectAll('.surface')
55462             .attr('id', 'surface');
55463
55464         surface
55465             .call(drawLabels.observe)
55466             .on('mousedown.zoom', function() {
55467                 if (event.button === 2) {
55468                     event.stopPropagation();
55469                 }
55470             }, true)
55471             .on('mouseup.zoom', function() {
55472                 if (resetTransform()) immediateRedraw();
55473             })
55474             .on('mousemove.map', function() {
55475                 mousemove = event;
55476             })
55477             .on('mouseover.vertices', function() {
55478                 if (map.editable() && !transformed) {
55479                     var hover = event.target.__data__;
55480                     surface.selectAll('.data-layer-osm')
55481                         .call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
55482                     dispatch$$1.call('drawn', this, {full: false});
55483                 }
55484             })
55485             .on('mouseout.vertices', function() {
55486                 if (map.editable() && !transformed) {
55487                     var hover = event.relatedTarget && event.relatedTarget.__data__;
55488                     surface.selectAll('.data-layer-osm')
55489                         .call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
55490                     dispatch$$1.call('drawn', this, {full: false});
55491                 }
55492             });
55493
55494         supersurface
55495             .call(context.background());
55496
55497         context.on('enter.map', function() {
55498             if (map.editable() && !transformed) {
55499                 var all = context.intersects(map.extent()),
55500                     filter = utilFunctor(true),
55501                     graph = context.graph();
55502
55503                 all = context.features().filter(all, graph);
55504                 surface.selectAll('.data-layer-osm')
55505                     .call(drawVertices, graph, all, filter, map.extent(), map.zoom())
55506                     .call(drawMidpoints, graph, all, filter, map.trimmedExtent());
55507                 dispatch$$1.call('drawn', this, {full: false});
55508             }
55509         });
55510
55511         map.dimensions(utilGetDimensions(selection$$1));
55512     }
55513
55514
55515     function zoomEventFilter() {
55516         // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
55517         // Intercept `mousedown` and check if there is an orphaned zoom gesture.
55518         // This can happen if a previous `mousedown` occurred without a `mouseup`.
55519         // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
55520         // so that d3-zoom won't stop propagation of new `mousedown` events.
55521         if (event.type === 'mousedown') {
55522             var hasOrphan = false;
55523             var listeners = window.__on;
55524             for (var i = 0; i < listeners.length; i++) {
55525                 var listener = listeners[i];
55526                 if (listener.name === 'zoom' && listener.type === 'mouseup') {
55527                     hasOrphan = true;
55528                     break;
55529                 }
55530             }
55531             if (hasOrphan) {
55532                 var event$$1 = window.CustomEvent;
55533                 if (event$$1) {
55534                     event$$1 = new event$$1('mouseup');
55535                 } else {
55536                     event$$1 = window.document.createEvent('Event');
55537                     event$$1.initEvent('mouseup', false, false);
55538                 }
55539                 // Event needs to be dispatched with an event.view property.
55540                 event$$1.view = window;
55541                 window.dispatchEvent(event$$1);
55542             }
55543         }
55544
55545         return event.button !== 2;   // ignore right clicks
55546     }
55547
55548
55549     function ztok(z) {
55550         return 256 * Math.pow(2, z);
55551     }
55552
55553     function ktoz(k) {
55554         return Math.max(Math.log(k) / Math.LN2 - 8, 0);
55555     }
55556
55557     function pxCenter() {
55558         return [dimensions[0] / 2, dimensions[1] / 2];
55559     }
55560
55561
55562     function drawVector(difference, extent$$1) {
55563         var graph = context.graph(),
55564             features = context.features(),
55565             all = context.intersects(map.extent()),
55566             data, filter;
55567
55568         if (difference) {
55569             var complete = difference.complete(map.extent());
55570             data = lodash.compact(lodash.values(complete));
55571             filter = function(d) { return d.id in complete; };
55572             features.clear(data);
55573
55574         } else {
55575             // force a full redraw if gatherStats detects that a feature
55576             // should be auto-hidden (e.g. points or buildings)..
55577             if (features.gatherStats(all, graph, dimensions)) {
55578                 extent$$1 = undefined;
55579             }
55580
55581             if (extent$$1) {
55582                 data = context.intersects(map.extent().intersection(extent$$1));
55583                 var set = set$2(lodash.map(data, 'id'));
55584                 filter = function(d) { return set.has(d.id); };
55585
55586             } else {
55587                 data = all;
55588                 filter = utilFunctor(true);
55589             }
55590         }
55591
55592         data = features.filter(data, graph);
55593
55594         surface.selectAll('.data-layer-osm')
55595             .call(drawVertices, graph, data, filter, map.extent(), map.zoom())
55596             .call(drawLines, graph, data, filter)
55597             .call(drawAreas, graph, data, filter)
55598             .call(drawMidpoints, graph, data, filter, map.trimmedExtent())
55599             .call(drawLabels, graph, data, filter, dimensions, !difference && !extent$$1)
55600             .call(drawPoints, graph, data, filter);
55601
55602         dispatch$$1.call('drawn', this, {full: true});
55603     }
55604
55605
55606     function editOff() {
55607         context.features().resetStats();
55608         surface.selectAll('.layer-osm *').remove();
55609         dispatch$$1.call('drawn', this, {full: true});
55610     }
55611
55612
55613     function dblClick() {
55614         if (!dblclickEnabled) {
55615             event.preventDefault();
55616             event.stopImmediatePropagation();
55617         }
55618     }
55619
55620
55621     function zoomPan(manualEvent) {
55622         var event$$1 = (manualEvent || event),
55623             source = event$$1.sourceEvent,
55624             eventTransform = event$$1.transform;
55625
55626         if (transformStart.x === eventTransform.x &&
55627             transformStart.y === eventTransform.y &&
55628             transformStart.k === eventTransform.k) {
55629             return;  // no change
55630         }
55631
55632         // Normalize mousewheel - #3029
55633         // If wheel delta is provided in LINE units, recalculate it in PIXEL units
55634         // We are essentially redoing the calculations that occur here:
55635         //   https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
55636         // See this for more info:
55637         //   https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
55638         if (source && source.type === 'wheel' && source.deltaMode === 1 /* LINE */) {
55639             // pick sensible scroll amount if user scrolling fast or slow..
55640             var lines = Math.abs(source.deltaY),
55641                 scroll = lines > 2 ? 40 : lines * 10;
55642
55643             var t0 = transformed ? transformLast : transformStart,
55644                 p0 = mouse$$1(source),
55645                 p1 = t0.invert(p0),
55646                 k2 = t0.k * Math.pow(2, -source.deltaY * scroll / 500),
55647                 x2 = p0[0] - p1[0] * k2,
55648                 y2 = p0[1] - p1[1] * k2;
55649
55650             eventTransform = identity$8.translate(x2,y2).scale(k2);
55651             _selection.node().__zoom = eventTransform;
55652         }
55653
55654         if (ktoz(eventTransform.k * 2 * Math.PI) < minzoom) {
55655             surface.interrupt();
55656             uiFlash().text(t('cannot_zoom'));
55657             setZoom(context.minEditableZoom(), true);
55658             queueRedraw();
55659             dispatch$$1.call('move', this, map);
55660             return;
55661         }
55662
55663         projection$$1.transform(eventTransform);
55664
55665         var scale = eventTransform.k / transformStart.k,
55666             tX = (eventTransform.x / scale - transformStart.x) * scale,
55667             tY = (eventTransform.y / scale - transformStart.y) * scale;
55668
55669         if (context.inIntro()) {
55670             curtainProjection.transform({
55671                 x: eventTransform.x - tX,
55672                 y: eventTransform.y - tY,
55673                 k: eventTransform.k
55674             });
55675         }
55676
55677         transformed = true;
55678         transformLast = eventTransform;
55679         utilSetTransform(supersurface, tX, tY, scale);
55680         queueRedraw();
55681
55682         dispatch$$1.call('move', this, map);
55683     }
55684
55685
55686     function resetTransform() {
55687         if (!transformed) return false;
55688
55689         // deprecation warning - Radial Menu to be removed in iD v3
55690         surface.selectAll('.edit-menu, .radial-menu').interrupt().remove();
55691         utilSetTransform(supersurface, 0, 0);
55692         transformed = false;
55693         if (context.inIntro()) {
55694             curtainProjection.transform(projection$$1.transform());
55695         }
55696         return true;
55697     }
55698
55699
55700     function redraw(difference, extent$$1) {
55701         if (surface.empty() || !redrawEnabled) return;
55702
55703         // If we are in the middle of a zoom/pan, we can't do differenced redraws.
55704         // It would result in artifacts where differenced entities are redrawn with
55705         // one transform and unchanged entities with another.
55706         if (resetTransform()) {
55707             difference = extent$$1 = undefined;
55708         }
55709
55710         var z = String(~~map.zoom());
55711         if (surface.attr('data-zoom') !== z) {
55712             surface.attr('data-zoom', z)
55713                 .classed('low-zoom', z <= 16);
55714         }
55715
55716         if (!difference) {
55717             supersurface.call(context.background());
55718         }
55719
55720         wrapper
55721             .call(drawLayers);
55722
55723         // OSM
55724         if (map.editable()) {
55725             context.loadTiles(projection$$1, dimensions);
55726             drawVector(difference, extent$$1);
55727         } else {
55728             editOff();
55729         }
55730
55731         transformStart = projection$$1.transform();
55732
55733         return map;
55734     }
55735
55736
55737     var queueRedraw = lodash.throttle(redraw, 750);
55738
55739
55740     var immediateRedraw = function(difference, extent$$1) {
55741         if (!difference && !extent$$1) queueRedraw.cancel();
55742         redraw(difference, extent$$1);
55743     };
55744
55745
55746     function pointLocation(p) {
55747         var translate = projection$$1.translate(),
55748             scale = projection$$1.scale() * 2 * Math.PI;
55749         return [(p[0] - translate[0]) / scale, (p[1] - translate[1]) / scale];
55750     }
55751
55752
55753     function locationPoint(l) {
55754         var translate = projection$$1.translate(),
55755             scale = projection$$1.scale() * 2 * Math.PI;
55756         return [l[0] * scale + translate[0], l[1] * scale + translate[1]];
55757     }
55758
55759
55760     map.mouse = function() {
55761         var event$$1 = mousemove || event;
55762         if (event$$1) {
55763             var s;
55764             while ((s = event$$1.sourceEvent)) { event$$1 = s; }
55765             return mouse$$1(event$$1);
55766         }
55767         return null;
55768     };
55769
55770
55771     map.mouseCoordinates = function() {
55772         return projection$$1.invert(map.mouse());
55773     };
55774
55775
55776     map.dblclickEnable = function(_) {
55777         if (!arguments.length) return dblclickEnabled;
55778         dblclickEnabled = _;
55779         return map;
55780     };
55781
55782
55783     map.redrawEnable = function(_) {
55784         if (!arguments.length) return redrawEnabled;
55785         redrawEnabled = _;
55786         return map;
55787     };
55788
55789
55790     function setTransform(t2, duration, force) {
55791         var t$$1 = projection$$1.transform();
55792         if (!force && t2.k === t$$1.k && t2.x === t$$1.x && t2.y === t$$1.y) {
55793             return false;
55794         }
55795
55796         if (duration) {
55797             _selection
55798                 .transition()
55799                 .duration(duration)
55800                 .on('start', function() { map.startEase(); })
55801                 .call(zoom$$1.transform, identity$8.translate(t2.x, t2.y).scale(t2.k));
55802         } else {
55803             projection$$1.transform(t2);
55804             transformStart = t2;
55805             _selection.call(zoom$$1.transform, transformStart);
55806         }
55807     }
55808
55809
55810     function setZoom(z2, force, duration) {
55811         if (z2 === map.zoom() && !force) {
55812             return false;
55813         }
55814
55815         var k = projection$$1.scale(),
55816             k2 = Math.max(ztok(2), Math.min(ztok(24), ztok(z2))) / (2 * Math.PI),
55817             center = pxCenter(),
55818             l = pointLocation(center);
55819
55820         projection$$1.scale(k2);
55821
55822         var t$$1 = projection$$1.translate();
55823         l = locationPoint(l);
55824
55825         t$$1[0] += center[0] - l[0];
55826         t$$1[1] += center[1] - l[1];
55827
55828         if (duration) {
55829             projection$$1.scale(k);  // reset scale
55830             _selection
55831                 .transition()
55832                 .duration(duration)
55833                 .on('start', function() { map.startEase(); })
55834                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k2));
55835         } else {
55836             projection$$1.translate(t$$1);
55837             transformStart = projection$$1.transform();
55838             _selection.call(zoom$$1.transform, transformStart);
55839         }
55840
55841         return true;
55842     }
55843
55844
55845     function setCenter(loc2, duration) {
55846         var c = map.center();
55847         if (loc2[0] === c[0] && loc2[1] === c[1]) {
55848             return false;
55849         }
55850
55851         var t$$1 = projection$$1.translate(),
55852             k = projection$$1.scale(),
55853             pxC = pxCenter(),
55854             ll = projection$$1(loc2);
55855
55856         t$$1[0] = t$$1[0] - ll[0] + pxC[0];
55857         t$$1[1] = t$$1[1] - ll[1] + pxC[1];
55858
55859         if (duration) {
55860             _selection
55861                 .transition()
55862                 .duration(duration)
55863                 .on('start', function() { map.startEase(); })
55864                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k));
55865         } else {
55866             projection$$1.translate(t$$1);
55867             transformStart = projection$$1.transform();
55868             _selection.call(zoom$$1.transform, transformStart);
55869         }
55870
55871         return true;
55872     }
55873
55874
55875     map.pan = function(delta, duration) {
55876         var t$$1 = projection$$1.translate(),
55877             k = projection$$1.scale();
55878
55879         t$$1[0] += delta[0];
55880         t$$1[1] += delta[1];
55881
55882         if (duration) {
55883             _selection
55884                 .transition()
55885                 .duration(duration)
55886                 .on('start', function() { map.startEase(); })
55887                 .call(zoom$$1.transform, identity$8.translate(t$$1[0], t$$1[1]).scale(k));
55888         } else {
55889             projection$$1.translate(t$$1);
55890             transformStart = projection$$1.transform();
55891             _selection.call(zoom$$1.transform, transformStart);
55892             dispatch$$1.call('move', this, map);
55893             immediateRedraw();
55894         }
55895
55896         return map;
55897     };
55898
55899
55900     map.dimensions = function(_) {
55901         if (!arguments.length) return dimensions;
55902         var center = map.center();
55903         dimensions = _;
55904         drawLayers.dimensions(dimensions);
55905         context.background().dimensions(dimensions);
55906         projection$$1.clipExtent([[0, 0], dimensions]);
55907         mouse$$1 = utilFastMouse(supersurface.node());
55908         setCenter(center);
55909
55910         queueRedraw();
55911         return map;
55912     };
55913
55914
55915     function zoomIn(delta) {
55916         setZoom(~~map.zoom() + delta, true, 250);
55917     }
55918
55919     function zoomOut(delta) {
55920         setZoom(~~map.zoom() - delta, true, 250);
55921     }
55922
55923     map.zoomIn = function() { zoomIn(1); };
55924     map.zoomInFurther = function() { zoomIn(4); };
55925
55926     map.zoomOut = function() { zoomOut(1); };
55927     map.zoomOutFurther = function() { zoomOut(4); };
55928
55929
55930     map.center = function(loc2) {
55931         if (!arguments.length) {
55932             return projection$$1.invert(pxCenter());
55933         }
55934
55935         if (setCenter(loc2)) {
55936             dispatch$$1.call('move', this, map);
55937         }
55938
55939         queueRedraw();
55940         return map;
55941     };
55942
55943
55944     map.zoom = function(z2) {
55945         if (!arguments.length) {
55946             return Math.max(ktoz(projection$$1.scale() * 2 * Math.PI), 0);
55947         }
55948
55949         if (z2 < minzoom) {
55950             surface.interrupt();
55951             uiFlash().text(t('cannot_zoom'));
55952             z2 = context.minEditableZoom();
55953         }
55954
55955         if (setZoom(z2)) {
55956             dispatch$$1.call('move', this, map);
55957         }
55958
55959         queueRedraw();
55960         return map;
55961     };
55962
55963
55964     map.zoomTo = function(entity, zoomLimits) {
55965         var extent$$1 = entity.extent(context.graph());
55966         if (!isFinite(extent$$1.area())) return;
55967
55968         var z2 = map.trimmedExtentZoom(extent$$1);
55969         zoomLimits = zoomLimits || [context.minEditableZoom(), 20];
55970         map.centerZoom(extent$$1.center(), Math.min(Math.max(z2, zoomLimits[0]), zoomLimits[1]));
55971     };
55972
55973
55974     map.centerZoom = function(loc2, z2) {
55975         var centered = setCenter(loc2),
55976             zoomed   = setZoom(z2);
55977
55978         if (centered || zoomed) {
55979             dispatch$$1.call('move', this, map);
55980         }
55981
55982         queueRedraw();
55983         return map;
55984     };
55985
55986
55987     map.centerEase = function(loc2, duration) {
55988         duration = duration || 250;
55989         setCenter(loc2, duration);
55990         return map;
55991     };
55992
55993
55994     map.zoomEase = function(z2, duration) {
55995         duration = duration || 250;
55996         setZoom(z2, false, duration);
55997         return map;
55998     };
55999
56000
56001     map.transformEase = function(t2, duration) {
56002         duration = duration || 250;
56003         setTransform(t2, duration, false);
56004         return map;
56005     };
56006
56007
56008     map.startEase = function() {
56009         utilBindOnce(surface, 'mousedown.ease', function() {
56010             map.cancelEase();
56011         });
56012         return map;
56013     };
56014
56015
56016     map.cancelEase = function() {
56017         _selection.interrupt();
56018         return map;
56019     };
56020
56021
56022     map.extent = function(_) {
56023         if (!arguments.length) {
56024             return new geoExtent$$1(projection$$1.invert([0, dimensions[1]]),
56025                                  projection$$1.invert([dimensions[0], 0]));
56026         } else {
56027             var extent$$1 = geoExtent$$1(_);
56028             map.centerZoom(extent$$1.center(), map.extentZoom(extent$$1));
56029         }
56030     };
56031
56032
56033     map.trimmedExtent = function(_) {
56034         if (!arguments.length) {
56035             var headerY = 60, footerY = 30, pad = 10;
56036             return new geoExtent$$1(projection$$1.invert([pad, dimensions[1] - footerY - pad]),
56037                                  projection$$1.invert([dimensions[0] - pad, headerY + pad]));
56038         } else {
56039             var extent$$1 = geoExtent$$1(_);
56040             map.centerZoom(extent$$1.center(), map.trimmedExtentZoom(extent$$1));
56041         }
56042     };
56043
56044
56045     function calcZoom(extent$$1, dim) {
56046         var tl = projection$$1([extent$$1[0][0], extent$$1[1][1]]),
56047             br = projection$$1([extent$$1[1][0], extent$$1[0][1]]);
56048
56049         // Calculate maximum zoom that fits extent
56050         var hFactor = (br[0] - tl[0]) / dim[0],
56051             vFactor = (br[1] - tl[1]) / dim[1],
56052             hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
56053             vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
56054             newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
56055
56056         return newZoom;
56057     }
56058
56059
56060     map.extentZoom = function(_) {
56061         return calcZoom(geoExtent$$1(_), dimensions);
56062     };
56063
56064
56065     map.trimmedExtentZoom = function(_) {
56066         var trimY = 120, trimX = 40,
56067             trimmed = [dimensions[0] - trimX, dimensions[1] - trimY];
56068         return calcZoom(geoExtent$$1(_), trimmed);
56069     };
56070
56071
56072     map.editable = function() {
56073         return map.zoom() >= context.minEditableZoom();
56074     };
56075
56076
56077     map.minzoom = function(_) {
56078         if (!arguments.length) return minzoom;
56079         minzoom = _;
56080         return map;
56081     };
56082
56083
56084     map.layers = drawLayers;
56085
56086
56087     return utilRebind(map, dispatch$$1, 'on');
56088 }
56089
56090 var TAU = 2 * Math.PI;
56091 function ztok(z) { return 256 * Math.pow(2, z) / TAU; }
56092 function ktoz(k) { return Math.log(k * TAU) / Math.LN2 - 8; }
56093 function vecSub(a, b) { return [ a[0] - b[0], a[1] - b[1] ]; }
56094 function vecScale(a, b) { return [ a[0] * b, a[1] * b ]; }
56095
56096
56097 function uiMapInMap(context) {
56098     var key = '/';
56099
56100
56101     function map_in_map(selection$$1) {
56102         var backgroundLayer = rendererTileLayer(context),
56103             overlayLayers = {},
56104             projection$$1 = geoRawMercator(),
56105             gpxLayer = svgGpx(projection$$1, context).showLabels(false),
56106             debugLayer = svgDebug(projection$$1, context),
56107             zoom$$1 = zoom()
56108                 .scaleExtent([ztok(0.5), ztok(24)])
56109                 .on('start', zoomStarted)
56110                 .on('zoom', zoomed)
56111                 .on('end', zoomEnded),
56112             isTransformed = false,
56113             isHidden = true,
56114             skipEvents = false,
56115             gesture = null,
56116             zDiff = 6,    // by default, minimap renders at (main zoom - 6)
56117             wrap = select(null),
56118             tiles = select(null),
56119             viewport = select(null),
56120             tStart,  // transform at start of gesture
56121             tCurr,   // transform at most recent event
56122             timeoutId;
56123
56124
56125         function zoomStarted() {
56126             if (skipEvents) return;
56127             tStart = tCurr = projection$$1.transform();
56128             gesture = null;
56129         }
56130
56131
56132         function zoomed() {
56133             if (skipEvents) return;
56134
56135             var x = event.transform.x,
56136                 y = event.transform.y,
56137                 k = event.transform.k,
56138                 isZooming = (k !== tStart.k),
56139                 isPanning = (x !== tStart.x || y !== tStart.y);
56140
56141             if (!isZooming && !isPanning) {
56142                 return;  // no change
56143             }
56144
56145             // lock in either zooming or panning, don't allow both in minimap.
56146             if (!gesture) {
56147                 gesture = isZooming ? 'zoom' : 'pan';
56148             }
56149
56150             var tMini = projection$$1.transform(),
56151                 tX, tY, scale;
56152
56153             if (gesture === 'zoom') {
56154                 var dMini = utilGetDimensions(wrap),
56155                     cMini = vecScale(dMini, 0.5);
56156                 scale = k / tMini.k;
56157                 tX = (cMini[0] / scale - cMini[0]) * scale;
56158                 tY = (cMini[1] / scale - cMini[1]) * scale;
56159             } else {
56160                 k = tMini.k;
56161                 scale = 1;
56162                 tX = x - tMini.x;
56163                 tY = y - tMini.y;
56164             }
56165
56166             utilSetTransform(tiles, tX, tY, scale);
56167             utilSetTransform(viewport, 0, 0, scale);
56168             isTransformed = true;
56169             tCurr = identity$8.translate(x, y).scale(k);
56170
56171             var zMain = ktoz(context.projection.scale()),
56172                 zMini = ktoz(k);
56173
56174             zDiff = zMain - zMini;
56175
56176             queueRedraw();
56177         }
56178
56179
56180         function zoomEnded() {
56181             if (skipEvents) return;
56182             if (gesture !== 'pan') return;
56183
56184             updateProjection();
56185             gesture = null;
56186             var dMini = utilGetDimensions(wrap),
56187                 cMini = vecScale(dMini, 0.5);
56188             context.map().center(projection$$1.invert(cMini));   // recenter main map..
56189         }
56190
56191
56192         function updateProjection() {
56193             var loc = context.map().center(),
56194                 dMini = utilGetDimensions(wrap),
56195                 cMini = vecScale(dMini, 0.5),
56196                 tMain = context.projection.transform(),
56197                 zMain = ktoz(tMain.k),
56198                 zMini = Math.max(zMain - zDiff, 0.5),
56199                 kMini = ztok(zMini);
56200
56201             projection$$1
56202                 .translate([tMain.x, tMain.y])
56203                 .scale(kMini);
56204
56205             var point = projection$$1(loc),
56206                 mouse$$1 = (gesture === 'pan') ? vecSub([tCurr.x, tCurr.y], [tStart.x, tStart.y]) : [0, 0],
56207                 xMini = cMini[0] - point[0] + tMain.x + mouse$$1[0],
56208                 yMini = cMini[1] - point[1] + tMain.y + mouse$$1[1];
56209
56210             projection$$1
56211                 .translate([xMini, yMini])
56212                 .clipExtent([[0, 0], dMini]);
56213
56214             tCurr = projection$$1.transform();
56215
56216             if (isTransformed) {
56217                 utilSetTransform(tiles, 0, 0);
56218                 utilSetTransform(viewport, 0, 0);
56219                 isTransformed = false;
56220             }
56221
56222             zoom$$1
56223                 .scaleExtent([ztok(0.5), ztok(zMain - 3)]);
56224
56225             skipEvents = true;
56226             wrap.call(zoom$$1.transform, tCurr);
56227             skipEvents = false;
56228         }
56229
56230
56231         function redraw() {
56232             clearTimeout(timeoutId);
56233             if (isHidden) return;
56234
56235             updateProjection();
56236
56237             var dMini = utilGetDimensions(wrap),
56238                 zMini = ktoz(projection$$1.scale());
56239
56240             // setup tile container
56241             tiles = wrap
56242                 .selectAll('.map-in-map-tiles')
56243                 .data([0]);
56244
56245             tiles = tiles.enter()
56246                 .append('div')
56247                 .attr('class', 'map-in-map-tiles')
56248                 .merge(tiles);
56249
56250             // redraw background
56251             backgroundLayer
56252                 .source(context.background().baseLayerSource())
56253                 .projection(projection$$1)
56254                 .dimensions(dMini);
56255
56256             var background = tiles
56257                 .selectAll('.map-in-map-background')
56258                 .data([0]);
56259
56260             background.enter()
56261                 .append('div')
56262                 .attr('class', 'map-in-map-background')
56263                 .merge(background)
56264                 .call(backgroundLayer);
56265
56266
56267             // redraw overlay
56268             var overlaySources = context.background().overlayLayerSources();
56269             var activeOverlayLayers = [];
56270             for (var i = 0; i < overlaySources.length; i++) {
56271                 if (overlaySources[i].validZoom(zMini)) {
56272                     if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
56273                     activeOverlayLayers.push(overlayLayers[i]
56274                         .source(overlaySources[i])
56275                         .projection(projection$$1)
56276                         .dimensions(dMini));
56277                 }
56278             }
56279
56280             var overlay = tiles
56281                 .selectAll('.map-in-map-overlay')
56282                 .data([0]);
56283
56284             overlay = overlay.enter()
56285                 .append('div')
56286                 .attr('class', 'map-in-map-overlay')
56287                 .merge(overlay);
56288
56289
56290             var overlays = overlay
56291                 .selectAll('div')
56292                 .data(activeOverlayLayers, function(d) { return d.source().name(); });
56293
56294             overlays.exit()
56295                 .remove();
56296
56297             overlays = overlays.enter()
56298                 .append('div')
56299                 .merge(overlays)
56300                 .each(function(layer) { select(this).call(layer); });
56301
56302
56303             var dataLayers = tiles
56304                 .selectAll('.map-in-map-data')
56305                 .data([0]);
56306
56307             dataLayers.exit()
56308                 .remove();
56309
56310             dataLayers = dataLayers.enter()
56311                 .append('svg')
56312                 .attr('class', 'map-in-map-data')
56313                 .merge(dataLayers)
56314                 .call(gpxLayer)
56315                 .call(debugLayer);
56316
56317
56318             // redraw viewport bounding box
56319             if (gesture !== 'pan') {
56320                 var getPath = index$4(projection$$1),
56321                     bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
56322
56323                 viewport = wrap.selectAll('.map-in-map-viewport')
56324                     .data([0]);
56325
56326                 viewport = viewport.enter()
56327                     .append('svg')
56328                     .attr('class', 'map-in-map-viewport')
56329                     .merge(viewport);
56330
56331
56332                 var path$$1 = viewport.selectAll('.map-in-map-bbox')
56333                     .data([bbox]);
56334
56335                 path$$1.enter()
56336                     .append('path')
56337                     .attr('class', 'map-in-map-bbox')
56338                     .merge(path$$1)
56339                     .attr('d', getPath)
56340                     .classed('thick', function(d) { return getPath.area(d) < 30; });
56341             }
56342         }
56343
56344
56345         function queueRedraw() {
56346             clearTimeout(timeoutId);
56347             timeoutId = setTimeout(function() { redraw(); }, 750);
56348         }
56349
56350
56351         function toggle() {
56352             if (event) event.preventDefault();
56353
56354             isHidden = !isHidden;
56355
56356             var label = select('.minimap-toggle');
56357             label.classed('active', !isHidden)
56358                 .select('input').property('checked', !isHidden);
56359
56360             if (isHidden) {
56361                 wrap
56362                     .style('display', 'block')
56363                     .style('opacity', '1')
56364                     .transition()
56365                     .duration(200)
56366                     .style('opacity', '0')
56367                     .on('end', function() {
56368                         selection$$1.selectAll('.map-in-map')
56369                             .style('display', 'none');
56370                     });
56371             } else {
56372                 wrap
56373                     .style('display', 'block')
56374                     .style('opacity', '0')
56375                     .transition()
56376                     .duration(200)
56377                     .style('opacity', '1')
56378                     .on('end', function() {
56379                         redraw();
56380                     });
56381             }
56382         }
56383
56384
56385         uiMapInMap.toggle = toggle;
56386
56387         wrap = selection$$1.selectAll('.map-in-map')
56388             .data([0]);
56389
56390         wrap = wrap.enter()
56391             .append('div')
56392             .attr('class', 'map-in-map')
56393             .style('display', (isHidden ? 'none' : 'block'))
56394             .call(zoom$$1)
56395             .on('dblclick.zoom', null)
56396             .merge(wrap);
56397
56398         context.map()
56399             .on('drawn.map-in-map', function(drawn) {
56400                 if (drawn.full === true) {
56401                     redraw();
56402                 }
56403             });
56404
56405         redraw();
56406
56407         var keybinding = d3keybinding('map-in-map')
56408             .on([key], toggle);
56409
56410         select(document)
56411             .call(keybinding);
56412     }
56413
56414     return map_in_map;
56415 }
56416
56417 function uiTooltipHtml(text, key, heading) {
56418     var s = '';
56419
56420     if (heading) {
56421         s += '<div class="tooltip-heading"><span>' + heading + '</span></div>';
56422     }
56423     if (text) {
56424         s += '<div class="tooltip-text"><span>' + text + '</span></div>';
56425     }
56426     if (key) {
56427         s += '<div class="keyhint-wrap"><span>' + t('tooltip_keyhint') + '</span>' +
56428             '<span class="keyhint">' + key + '</span></div>';
56429     }
56430
56431     return s;
56432 }
56433
56434 function uiBackground(context) {
56435     var key = 'B',
56436         detected = utilDetect(),
56437         opacities = [1, 0.75, 0.5, 0.25],
56438         directions = [
56439             ['right', [0.5, 0]],
56440             ['top', [0, -0.5]],
56441             ['left', [-0.5, 0]],
56442             ['bottom', [0, 0.5]]],
56443         opacityDefault = (context.storage('background-opacity') !== null) ?
56444             (+context.storage('background-opacity')) : 1.0,
56445         customTemplate = context.storage('background-custom-template') || '',
56446         previous;
56447
56448     // Can be 0 from <1.3.0 use or due to issue #1923.
56449     if (opacityDefault === 0) opacityDefault = 1.0;
56450
56451
56452     function background(selection$$1) {
56453
56454         function sortSources(a, b) {
56455             return a.best() && !b.best() ? -1
56456                 : b.best() && !a.best() ? 1
56457                 : descending(a.area(), b.area()) || ascending(a.name(), b.name()) || 0;
56458         }
56459
56460
56461         function setOpacity(d) {
56462             var bg = context.container().selectAll('.layer-background')
56463                 .transition()
56464                 .style('opacity', d)
56465                 .attr('data-opacity', d);
56466
56467             if (!detected.opera) {
56468                 utilSetTransform(bg, 0, 0);
56469             }
56470
56471             opacityList.selectAll('li')
56472                 .classed('active', function(_) { return _ === d; });
56473
56474             context.storage('background-opacity', d);
56475         }
56476
56477
56478         function setTooltips(selection$$1) {
56479             selection$$1.each(function(d, i, nodes) {
56480                 var item = select(this).select('label'),
56481                     span = item.select('span'),
56482                     placement = (i < nodes.length / 2) ? 'bottom' : 'top',
56483                     isOverflowing = (span.property('clientWidth') !== span.property('scrollWidth'));
56484
56485                 if (d === previous) {
56486                     item.call(tooltip()
56487                         .placement(placement)
56488                         .html(true)
56489                         .title(function() {
56490                             var tip = '<div>' + t('background.switch') + '</div>';
56491                             return uiTooltipHtml(tip, uiCmd('⌘B'));
56492                         })
56493                     );
56494                 } else if (d.description || isOverflowing) {
56495                     item.call(tooltip()
56496                         .placement(placement)
56497                         .title(d.description || d.name())
56498                     );
56499                 } else {
56500                     item.call(tooltip().destroy);
56501                 }
56502             });
56503         }
56504
56505
56506         function selectLayer() {
56507             function active$$1(d) {
56508                 return context.background().showsLayer(d);
56509             }
56510
56511             content.selectAll('.layer, .custom_layer')
56512                 .classed('active', active$$1)
56513                 .classed('switch', function(d) { return d === previous; })
56514                 .call(setTooltips)
56515                 .selectAll('input')
56516                 .property('checked', active$$1);
56517         }
56518
56519
56520         function clickSetSource(d) {
56521             event.preventDefault();
56522             previous = context.background().baseLayerSource();
56523             context.background().baseLayerSource(d);
56524             selectLayer();
56525             document.activeElement.blur();
56526         }
56527
56528
56529         function editCustom() {
56530             event.preventDefault();
56531             var template = window.prompt(t('background.custom_prompt'), customTemplate);
56532             if (template) {
56533                 setCustom(template);
56534             } else {
56535                 selectLayer();
56536             }
56537         }
56538
56539
56540         function setCustom(template) {
56541             context.storage('background-custom-template', template);
56542             var d = rendererBackgroundSource.Custom(template);
56543             content.selectAll('.custom_layer').datum(d);
56544             clickSetSource(d);
56545         }
56546
56547
56548         function clickSetOverlay(d) {
56549             event.preventDefault();
56550             context.background().toggleOverlayLayer(d);
56551             selectLayer();
56552             document.activeElement.blur();
56553         }
56554
56555
56556         function drawList(layerList, type, change, filter) {
56557             var sources = context.background()
56558                 .sources(context.map().extent())
56559                 .filter(filter);
56560
56561             var layerLinks = layerList.selectAll('li.layer')
56562                 .data(sources, function(d) { return d.name(); });
56563
56564             layerLinks.exit()
56565                 .remove();
56566
56567             var enter = layerLinks.enter()
56568                 .insert('li', '.custom_layer')
56569                 .attr('class', 'layer')
56570                 .classed('best', function(d) { return d.best(); });
56571
56572             enter.filter(function(d) { return d.best(); })
56573                 .append('div')
56574                 .attr('class', 'best')
56575                 .call(tooltip()
56576                     .title(t('background.best_imagery'))
56577                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
56578                 .append('span')
56579                 .html('&#9733;');
56580
56581             var label = enter
56582                 .append('label');
56583
56584             label
56585                 .append('input')
56586                 .attr('type', type)
56587                 .attr('name', 'layers')
56588                 .on('change', change);
56589
56590             label
56591                 .append('span')
56592                 .text(function(d) { return d.name(); });
56593
56594
56595             layerList.selectAll('li.layer')
56596                 .sort(sortSources)
56597                 .style('display', layerList.selectAll('li.layer').data().length > 0 ? 'block' : 'none');
56598         }
56599
56600
56601         function update() {
56602             backgroundList.call(drawList, 'radio', clickSetSource, function(d) { return !d.overlay; });
56603             overlayList.call(drawList, 'checkbox', clickSetOverlay, function(d) { return d.overlay; });
56604
56605             selectLayer();
56606
56607             var source = context.background().baseLayerSource();
56608             if (source.id === 'custom') {
56609                 customTemplate = source.template;
56610             }
56611
56612             updateOffsetVal();
56613         }
56614
56615
56616         function updateOffsetVal() {
56617             var meters = geoOffsetToMeters(context.background().offset()),
56618                 x = +meters[0].toFixed(2),
56619                 y = +meters[1].toFixed(2);
56620
56621             selectAll('.nudge-inner-rect')
56622                 .select('input')
56623                 .classed('error', false)
56624                 .property('value', x + ', ' + y);
56625
56626             selectAll('.nudge-reset')
56627                 .classed('disabled', function() {
56628                     return (x === 0 && y === 0);
56629                 });
56630         }
56631
56632
56633         function resetOffset() {
56634             if (event.button !== 0) return;
56635             context.background().offset([0, 0]);
56636             updateOffsetVal();
56637         }
56638
56639
56640         function nudge(d) {
56641             context.background().nudge(d, context.map().zoom());
56642             updateOffsetVal();
56643         }
56644
56645
56646         function buttonOffset(d) {
56647             if (event.button !== 0) return;
56648             var timeout = window.setTimeout(function() {
56649                     interval = window.setInterval(nudge.bind(null, d), 100);
56650                 }, 500),
56651                 interval;
56652
56653             function doneNudge() {
56654                 window.clearTimeout(timeout);
56655                 window.clearInterval(interval);
56656                 select(window)
56657                     .on('mouseup.buttonoffset', null, true)
56658                     .on('mousedown.buttonoffset', null, true);
56659             }
56660
56661             select(window)
56662                 .on('mouseup.buttonoffset', doneNudge, true)
56663                 .on('mousedown.buttonoffset', doneNudge, true);
56664
56665             nudge(d);
56666         }
56667
56668
56669         function inputOffset() {
56670             if (event.button !== 0) return;
56671             var input = select(this);
56672             var d = input.node().value;
56673
56674             if (d === '') return resetOffset();
56675
56676             d = d.replace(/;/g, ',').split(',').map(function(n) {
56677                 // if n is NaN, it will always get mapped to false.
56678                 return !isNaN(n) && n;
56679             });
56680
56681             if (d.length !== 2 || !d[0] || !d[1]) {
56682                 input.classed('error', true);
56683                 return;
56684             }
56685
56686             context.background().offset(geoMetersToOffset(d));
56687             updateOffsetVal();
56688         }
56689
56690
56691         function dragOffset() {
56692             if (event.button !== 0) return;
56693             var origin = [event.clientX, event.clientY];
56694
56695             context.container()
56696                 .append('div')
56697                 .attr('class', 'nudge-surface');
56698
56699             select(window)
56700                 .on('mousemove.offset', function() {
56701                     var latest = [event.clientX, event.clientY];
56702                     var d = [
56703                         -(origin[0] - latest[0]) / 4,
56704                         -(origin[1] - latest[1]) / 4
56705                     ];
56706
56707                     origin = latest;
56708                     nudge(d);
56709                 })
56710                 .on('mouseup.offset', function() {
56711                     if (event.button !== 0) return;
56712                     selectAll('.nudge-surface')
56713                         .remove();
56714
56715                     select(window)
56716                         .on('mousemove.offset', null)
56717                         .on('mouseup.offset', null);
56718                 });
56719
56720             event.preventDefault();
56721         }
56722
56723
56724         function hide() {
56725             setVisible(false);
56726         }
56727
56728
56729         function toggle() {
56730             if (event) event.preventDefault();
56731             tooltipBehavior.hide(button);
56732             setVisible(!button.classed('active'));
56733         }
56734
56735
56736         function quickSwitch() {
56737             if (previous) {
56738                 clickSetSource(previous);
56739             }
56740         }
56741
56742
56743         function setVisible(show) {
56744             if (show !== shown) {
56745                 button.classed('active', show);
56746                 shown = show;
56747
56748                 if (show) {
56749                     selection$$1
56750                         .on('mousedown.background-inside', function() {
56751                             event.stopPropagation();
56752                         });
56753
56754                     content
56755                         .style('display', 'block')
56756                         .style('right', '-300px')
56757                         .transition()
56758                         .duration(200)
56759                         .style('right', '0px');
56760
56761                     content.selectAll('.layer, .custom_layer')
56762                         .call(setTooltips);
56763
56764                 } else {
56765                     content
56766                         .style('display', 'block')
56767                         .style('right', '0px')
56768                         .transition()
56769                         .duration(200)
56770                         .style('right', '-300px')
56771                         .on('end', function() {
56772                             select(this).style('display', 'none');
56773                         });
56774
56775                     selection$$1
56776                         .on('mousedown.background-inside', null);
56777                 }
56778             }
56779         }
56780
56781
56782         var content = selection$$1
56783                 .append('div')
56784                 .attr('class', 'fillL map-overlay col3 content hide'),
56785             tooltipBehavior = tooltip()
56786                 .placement((textDirection === 'rtl') ? 'right' : 'left')
56787                 .html(true)
56788                 .title(uiTooltipHtml(t('background.description'), key)),
56789             button = selection$$1
56790                 .append('button')
56791                 .attr('tabindex', -1)
56792                 .on('click', toggle)
56793                 .call(svgIcon('#icon-layers', 'light'))
56794                 .call(tooltipBehavior),
56795             shown = false;
56796
56797
56798         /* opacity switcher */
56799
56800         var opawrap = content
56801                 .append('div')
56802                 .attr('class', 'opacity-options-wrapper');
56803
56804         opawrap
56805             .append('h4')
56806             .text(t('background.title'));
56807
56808         var opacityList = opawrap
56809             .append('ul')
56810             .attr('class', 'opacity-options');
56811
56812         opacityList.selectAll('div.opacity')
56813             .data(opacities)
56814             .enter()
56815             .append('li')
56816             .attr('data-original-title', function(d) {
56817                 return t('background.percent_brightness', { opacity: (d * 100) });
56818             })
56819             .on('click.set-opacity', setOpacity)
56820             .html('<div class="select-box"></div>')
56821             .call(tooltip()
56822                 .placement((textDirection === 'rtl') ? 'right' : 'left'))
56823             .append('div')
56824             .attr('class', 'opacity')
56825             .style('opacity', function(d) { return 1.25 - d; });
56826
56827
56828         /* background switcher */
56829
56830         var backgroundList = content
56831             .append('ul')
56832             .attr('class', 'layer-list')
56833             .attr('dir', 'auto');
56834
56835         var custom = backgroundList
56836             .append('li')
56837             .attr('class', 'custom_layer')
56838             .datum(rendererBackgroundSource.Custom());
56839
56840         custom
56841             .append('button')
56842             .attr('class', 'layer-browse')
56843             .call(tooltip()
56844                 .title(t('background.custom_button'))
56845                 .placement((textDirection === 'rtl') ? 'right' : 'left'))
56846             .on('click', editCustom)
56847             .call(svgIcon('#icon-search'));
56848
56849         var label = custom
56850             .append('label');
56851
56852         label
56853             .append('input')
56854             .attr('type', 'radio')
56855             .attr('name', 'layers')
56856             .on('change', function () {
56857                 if (customTemplate) {
56858                     setCustom(customTemplate);
56859                 } else {
56860                     editCustom();
56861                 }
56862             });
56863
56864         label
56865             .append('span')
56866             .text(t('background.custom'));
56867
56868         content
56869             .append('div')
56870             .attr('class', 'imagery-faq')
56871             .append('a')
56872             .attr('target', '_blank')
56873             .attr('tabindex', -1)
56874             .call(svgIcon('#icon-out-link', 'inline'))
56875             .attr('href', 'https://github.com/openstreetmap/iD/blob/master/FAQ.md#how-can-i-report-an-issue-with-background-imagery')
56876             .append('span')
56877             .text(t('background.imagery_source_faq'));
56878
56879         var overlayList = content
56880             .append('ul')
56881             .attr('class', 'layer-list');
56882
56883         var controls = content
56884             .append('div')
56885             .attr('class', 'controls-list');
56886
56887
56888         /* minimap toggle */
56889
56890         var minimapLabel = controls
56891             .append('label')
56892             .call(tooltip()
56893                 .html(true)
56894                 .title(uiTooltipHtml(t('background.minimap.tooltip'), '/'))
56895                 .placement('top')
56896             );
56897
56898         minimapLabel
56899             .classed('minimap-toggle', true)
56900             .append('input')
56901             .attr('type', 'checkbox')
56902             .on('change', function() {
56903                 uiMapInMap.toggle();
56904                 event.preventDefault();
56905             });
56906
56907         minimapLabel
56908             .append('span')
56909             .text(t('background.minimap.description'));
56910
56911
56912         /* imagery offset controls */
56913
56914         var adjustments = content
56915             .append('div')
56916             .attr('class', 'adjustments');
56917
56918         adjustments
56919             .append('a')
56920             .text(t('background.fix_misalignment'))
56921             .attr('href', '#')
56922             .classed('hide-toggle', true)
56923             .classed('expanded', false)
56924             .on('click', function() {
56925                 if (event.button !== 0) return;
56926                 var exp = select(this).classed('expanded');
56927                 nudgeContainer.style('display', exp ? 'none' : 'block');
56928                 select(this).classed('expanded', !exp);
56929                 event.preventDefault();
56930             });
56931
56932         var nudgeContainer = adjustments
56933             .append('div')
56934             .attr('class', 'nudge-container cf')
56935             .style('display', 'none');
56936
56937         nudgeContainer
56938             .append('div')
56939             .attr('class', 'nudge-instructions')
56940             .text(t('background.offset'));
56941
56942         var nudgeRect = nudgeContainer
56943             .append('div')
56944             .attr('class', 'nudge-outer-rect')
56945             .on('mousedown', dragOffset);
56946
56947         nudgeRect
56948             .append('div')
56949             .attr('class', 'nudge-inner-rect')
56950             .append('input')
56951             .on('change', inputOffset)
56952             .on('mousedown', function() {
56953                 if (event.button !== 0) return;
56954                 event.stopPropagation();
56955             });
56956
56957         nudgeContainer
56958             .append('div')
56959             .selectAll('button')
56960             .data(directions).enter()
56961             .append('button')
56962             .attr('class', function(d) { return d[0] + ' nudge'; })
56963             .on('mousedown', function(d) {
56964                 if (event.button !== 0) return;
56965                 buttonOffset(d[1]);
56966             });
56967
56968         nudgeContainer
56969             .append('button')
56970             .attr('title', t('background.reset'))
56971             .attr('class', 'nudge-reset disabled')
56972             .on('click', resetOffset)
56973             .call(
56974                 (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
56975             );
56976
56977         context.map()
56978             .on('move.background-update', lodash.debounce(update, 1000));
56979
56980         context.background()
56981             .on('change.background-update', update);
56982
56983
56984         update();
56985         setOpacity(opacityDefault);
56986
56987         var keybinding = d3keybinding('background')
56988             .on(key, toggle)
56989             .on(uiCmd('⌘B'), quickSwitch)
56990             .on('F', hide)
56991             .on('H', hide);
56992
56993         select(document)
56994             .call(keybinding);
56995
56996         context.surface().on('mousedown.background-outside', hide);
56997         context.container().on('mousedown.background-outside', hide);
56998     }
56999
57000     return background;
57001 }
57002
57003 function uiContributors(context) {
57004     var debouncedUpdate = lodash.debounce(function() { update(); }, 1000),
57005         limit = 4,
57006         hidden = false,
57007         wrap = select(null);
57008
57009
57010     function update() {
57011         var users = {},
57012             entities = context.intersects(context.map().extent());
57013
57014         entities.forEach(function(entity) {
57015             if (entity && entity.user) users[entity.user] = true;
57016         });
57017
57018         var u = Object.keys(users),
57019             subset = u.slice(0, u.length > limit ? limit - 1 : limit);
57020
57021         wrap.html('')
57022             .call(svgIcon('#icon-nearby', 'pre-text light'));
57023
57024         var userList = select(document.createElement('span'));
57025
57026         userList.selectAll()
57027             .data(subset)
57028             .enter()
57029             .append('a')
57030             .attr('class', 'user-link')
57031             .attr('href', function(d) { return context.connection().userURL(d); })
57032             .attr('target', '_blank')
57033             .attr('tabindex', -1)
57034             .text(String);
57035
57036         if (u.length > limit) {
57037             var count = select(document.createElement('span'));
57038
57039             count.append('a')
57040                 .attr('target', '_blank')
57041                 .attr('tabindex', -1)
57042                 .attr('href', function() {
57043                     return context.connection().changesetsURL(context.map().center(), context.map().zoom());
57044                 })
57045                 .text(u.length - limit + 1);
57046
57047             wrap.append('span')
57048                 .html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
57049
57050         } else {
57051             wrap.append('span')
57052                 .html(t('contributors.list', { users: userList.html() }));
57053         }
57054
57055         if (!u.length) {
57056             hidden = true;
57057             wrap
57058                 .transition()
57059                 .style('opacity', 0);
57060
57061         } else if (hidden) {
57062             wrap
57063                 .transition()
57064                 .style('opacity', 1);
57065         }
57066     }
57067
57068
57069     return function(selection$$1) {
57070         wrap = selection$$1;
57071         update();
57072
57073         context.connection().on('loaded.contributors', debouncedUpdate);
57074         context.map().on('move.contributors', debouncedUpdate);
57075     };
57076 }
57077
57078 function uiFeatureInfo(context) {
57079     function update(selection$$1) {
57080         var features = context.features(),
57081             stats = features.stats(),
57082             count = 0,
57083             hiddenList = lodash.compact(lodash.map(features.hidden(), function(k) {
57084                 if (stats[k]) {
57085                     count += stats[k];
57086                     return String(stats[k]) + ' ' + t('feature.' + k + '.description');
57087                 }
57088             }));
57089
57090         selection$$1.html('');
57091
57092         if (hiddenList.length) {
57093             var tooltipBehavior = tooltip()
57094                     .placement('top')
57095                     .html(true)
57096                     .title(function() {
57097                         return uiTooltipHtml(hiddenList.join('<br/>'));
57098                     });
57099
57100             var warning = selection$$1.append('a')
57101                 .attr('href', '#')
57102                 .attr('tabindex', -1)
57103                 .html(t('feature_info.hidden_warning', { count: count }))
57104                 .call(tooltipBehavior)
57105                 .on('click', function() {
57106                     tooltipBehavior.hide(warning);
57107                     // open map data panel?
57108                     event.preventDefault();
57109                 });
57110         }
57111
57112         selection$$1
57113             .classed('hide', !hiddenList.length);
57114     }
57115
57116
57117     return function(selection$$1) {
57118         update(selection$$1);
57119
57120         context.features().on('change.feature_info', function() {
57121             update(selection$$1);
57122         });
57123     };
57124 }
57125
57126 function uiFullScreen(context) {
57127     var element = context.container().node(),
57128         keybinding = d3keybinding('full-screen');
57129         // button;
57130
57131
57132     function getFullScreenFn() {
57133         if (element.requestFullscreen) {
57134             return element.requestFullscreen;
57135         } else if (element.msRequestFullscreen) {
57136             return element.msRequestFullscreen;
57137         } else if (element.mozRequestFullScreen) {
57138             return element.mozRequestFullScreen;
57139         } else if (element.webkitRequestFullscreen) {
57140             return element.webkitRequestFullscreen;
57141         }
57142     }
57143
57144
57145     function getExitFullScreenFn() {
57146         if (document.exitFullscreen) {
57147             return document.exitFullscreen;
57148         } else if (document.msExitFullscreen) {
57149             return document.msExitFullscreen;
57150         } else if (document.mozCancelFullScreen) {
57151             return document.mozCancelFullScreen;
57152         } else if (document.webkitExitFullscreen) {
57153             return document.webkitExitFullscreen;
57154         }
57155     }
57156
57157
57158     function isFullScreen() {
57159         return document.fullscreenElement ||
57160             document.mozFullScreenElement ||
57161             document.webkitFullscreenElement ||
57162             document.msFullscreenElement;
57163     }
57164
57165
57166     function isSupported() {
57167         return !!getFullScreenFn();
57168     }
57169
57170
57171     function fullScreen() {
57172         event.preventDefault();
57173         if (!isFullScreen()) {
57174             // button.classed('active', true);
57175             getFullScreenFn().apply(element);
57176         } else {
57177             // button.classed('active', false);
57178             getExitFullScreenFn().apply(document);
57179         }
57180     }
57181
57182
57183     return function() { // selection) {
57184         if (!isSupported())
57185             return;
57186
57187         // button = selection.append('button')
57188         //     .attr('title', t('full_screen'))
57189         //     .attr('tabindex', -1)
57190         //     .on('click', fullScreen)
57191         //     .call(tooltip);
57192
57193         // button.append('span')
57194         //     .attr('class', 'icon full-screen');
57195
57196         var detected = utilDetect();
57197         var keys$$1 = detected.os === 'mac' ? [uiCmd('⌃⌘F'), 'f11'] : ['f11'];
57198         keybinding.on(keys$$1, fullScreen);
57199
57200         select(document)
57201             .call(keybinding);
57202     };
57203 }
57204
57205 function uiModal(selection$$1, blocking) {
57206     var keybinding = d3keybinding('modal');
57207     var previous = selection$$1.select('div.modal');
57208     var animate = previous.empty();
57209
57210     previous.transition()
57211         .duration(200)
57212         .style('opacity', 0)
57213         .remove();
57214
57215     var shaded = selection$$1
57216         .append('div')
57217         .attr('class', 'shaded')
57218         .style('opacity', 0);
57219
57220     shaded.close = function() {
57221         shaded
57222             .transition()
57223             .duration(200)
57224             .style('opacity',0)
57225             .remove();
57226
57227         modal
57228             .transition()
57229             .duration(200)
57230             .style('top','0px');
57231
57232         keybinding.off();
57233     };
57234
57235
57236     var modal = shaded
57237         .append('div')
57238         .attr('class', 'modal fillL col6');
57239
57240     if (!blocking) {
57241         shaded.on('click.remove-modal', function() {
57242             if (event.target === this) {
57243                 shaded.close();
57244             }
57245         });
57246
57247         modal.append('button')
57248             .attr('class', 'close')
57249             .on('click', shaded.close)
57250             .call(svgIcon('#icon-close'));
57251
57252         keybinding
57253             .on('⌫', shaded.close)
57254             .on('⎋', shaded.close);
57255
57256         select(document)
57257             .call(keybinding);
57258     }
57259
57260     modal
57261         .append('div')
57262         .attr('class', 'content');
57263
57264     if (animate) {
57265         shaded.transition().style('opacity', 1);
57266     } else {
57267         shaded.style('opacity', 1);
57268     }
57269
57270
57271     return shaded;
57272 }
57273
57274 function uiLoading(context) {
57275     var message = '',
57276         blocking = false,
57277         modalSelection;
57278
57279
57280     var loading = function(selection) {
57281         modalSelection = uiModal(selection, blocking);
57282
57283         var loadertext = modalSelection.select('.content')
57284             .classed('loading-modal', true)
57285             .append('div')
57286             .attr('class', 'modal-section fillL');
57287
57288         loadertext
57289             .append('img')
57290             .attr('class', 'loader')
57291             .attr('src', context.imagePath('loader-white.gif'));
57292
57293         loadertext
57294             .append('h3')
57295             .text(message);
57296
57297         modalSelection.select('button.close')
57298             .attr('class', 'hide');
57299
57300         return loading;
57301     };
57302
57303
57304     loading.message = function(_) {
57305         if (!arguments.length) return message;
57306         message = _;
57307         return loading;
57308     };
57309
57310
57311     loading.blocking = function(_) {
57312         if (!arguments.length) return blocking;
57313         blocking = _;
57314         return loading;
57315     };
57316
57317
57318     loading.close = function() {
57319         modalSelection.remove();
57320     };
57321
57322
57323     return loading;
57324 }
57325
57326 function uiGeolocate(context) {
57327     var geoOptions = { enableHighAccuracy: false, timeout: 6000 /* 6sec */ },
57328         locating = uiLoading(context).message(t('geolocate.locating')).blocking(true),
57329         timeoutId;
57330
57331
57332     function click() {
57333         if (context.inIntro()) return;
57334         context.enter(modeBrowse(context));
57335         context.container().call(locating);
57336         navigator.geolocation.getCurrentPosition(success, error, geoOptions);
57337
57338         // This timeout ensures that we still call finish() even if
57339         // the user declines to share their location in Firefox
57340         timeoutId = setTimeout(finish, 10000 /* 10sec */ );
57341     }
57342
57343
57344     function success(position) {
57345         var map = context.map(),
57346             extent = geoExtent$$1([position.coords.longitude, position.coords.latitude])
57347                 .padByMeters(position.coords.accuracy);
57348
57349         map.centerZoom(extent.center(), Math.min(20, map.extentZoom(extent)));
57350         finish();
57351     }
57352
57353
57354     function error() {
57355         finish();
57356     }
57357
57358
57359     function finish() {
57360         locating.close();  // unblock ui
57361         if (timeoutId) { clearTimeout(timeoutId); }
57362         timeoutId = undefined;
57363     }
57364
57365
57366     return function(selection) {
57367         if (!navigator.geolocation) return;
57368
57369         selection
57370             .append('button')
57371             .attr('tabindex', -1)
57372             .attr('title', t('geolocate.title'))
57373             .on('click', click)
57374             .call(svgIcon('#icon-geolocate', 'light'))
57375             .call(tooltip()
57376                 .placement((textDirection === 'rtl') ? 'right' : 'left'));
57377     };
57378 }
57379
57380 var marked = createCommonjsModule(function (module, exports) {
57381 /**
57382  * marked - a markdown parser
57383  * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
57384  * https://github.com/chjj/marked
57385  */
57386
57387 (function() {
57388
57389 /**
57390  * Block-Level Grammar
57391  */
57392
57393 var block = {
57394   newline: /^\n+/,
57395   code: /^( {4}[^\n]+\n*)+/,
57396   fences: noop,
57397   hr: /^( *[-*_]){3,} *(?:\n+|$)/,
57398   heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
57399   nptable: noop,
57400   lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
57401   blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
57402   list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
57403   html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
57404   def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
57405   table: noop,
57406   paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
57407   text: /^[^\n]+/
57408 };
57409
57410 block.bullet = /(?:[*+-]|\d+\.)/;
57411 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
57412 block.item = replace(block.item, 'gm')
57413   (/bull/g, block.bullet)
57414   ();
57415
57416 block.list = replace(block.list)
57417   (/bull/g, block.bullet)
57418   ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
57419   ('def', '\\n+(?=' + block.def.source + ')')
57420   ();
57421
57422 block.blockquote = replace(block.blockquote)
57423   ('def', block.def)
57424   ();
57425
57426 block._tag = '(?!(?:'
57427   + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
57428   + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
57429   + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
57430
57431 block.html = replace(block.html)
57432   ('comment', /<!--[\s\S]*?-->/)
57433   ('closed', /<(tag)[\s\S]+?<\/\1>/)
57434   ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
57435   (/tag/g, block._tag)
57436   ();
57437
57438 block.paragraph = replace(block.paragraph)
57439   ('hr', block.hr)
57440   ('heading', block.heading)
57441   ('lheading', block.lheading)
57442   ('blockquote', block.blockquote)
57443   ('tag', '<' + block._tag)
57444   ('def', block.def)
57445   ();
57446
57447 /**
57448  * Normal Block Grammar
57449  */
57450
57451 block.normal = merge({}, block);
57452
57453 /**
57454  * GFM Block Grammar
57455  */
57456
57457 block.gfm = merge({}, block.normal, {
57458   fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
57459   paragraph: /^/,
57460   heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
57461 });
57462
57463 block.gfm.paragraph = replace(block.paragraph)
57464   ('(?!', '(?!'
57465     + block.gfm.fences.source.replace('\\1', '\\2') + '|'
57466     + block.list.source.replace('\\1', '\\3') + '|')
57467   ();
57468
57469 /**
57470  * GFM + Tables Block Grammar
57471  */
57472
57473 block.tables = merge({}, block.gfm, {
57474   nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
57475   table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
57476 });
57477
57478 /**
57479  * Block Lexer
57480  */
57481
57482 function Lexer(options) {
57483   this.tokens = [];
57484   this.tokens.links = {};
57485   this.options = options || marked.defaults;
57486   this.rules = block.normal;
57487
57488   if (this.options.gfm) {
57489     if (this.options.tables) {
57490       this.rules = block.tables;
57491     } else {
57492       this.rules = block.gfm;
57493     }
57494   }
57495 }
57496
57497 /**
57498  * Expose Block Rules
57499  */
57500
57501 Lexer.rules = block;
57502
57503 /**
57504  * Static Lex Method
57505  */
57506
57507 Lexer.lex = function(src, options) {
57508   var lexer = new Lexer(options);
57509   return lexer.lex(src);
57510 };
57511
57512 /**
57513  * Preprocessing
57514  */
57515
57516 Lexer.prototype.lex = function(src) {
57517   src = src
57518     .replace(/\r\n|\r/g, '\n')
57519     .replace(/\t/g, '    ')
57520     .replace(/\u00a0/g, ' ')
57521     .replace(/\u2424/g, '\n');
57522
57523   return this.token(src, true);
57524 };
57525
57526 /**
57527  * Lexing
57528  */
57529
57530 Lexer.prototype.token = function(src, top, bq) {
57531   var src = src.replace(/^ +$/gm, '')
57532     , next
57533     , loose
57534     , cap
57535     , bull
57536     , b
57537     , item
57538     , space
57539     , i
57540     , l;
57541
57542   while (src) {
57543     // newline
57544     if (cap = this.rules.newline.exec(src)) {
57545       src = src.substring(cap[0].length);
57546       if (cap[0].length > 1) {
57547         this.tokens.push({
57548           type: 'space'
57549         });
57550       }
57551     }
57552
57553     // code
57554     if (cap = this.rules.code.exec(src)) {
57555       src = src.substring(cap[0].length);
57556       cap = cap[0].replace(/^ {4}/gm, '');
57557       this.tokens.push({
57558         type: 'code',
57559         text: !this.options.pedantic
57560           ? cap.replace(/\n+$/, '')
57561           : cap
57562       });
57563       continue;
57564     }
57565
57566     // fences (gfm)
57567     if (cap = this.rules.fences.exec(src)) {
57568       src = src.substring(cap[0].length);
57569       this.tokens.push({
57570         type: 'code',
57571         lang: cap[2],
57572         text: cap[3] || ''
57573       });
57574       continue;
57575     }
57576
57577     // heading
57578     if (cap = this.rules.heading.exec(src)) {
57579       src = src.substring(cap[0].length);
57580       this.tokens.push({
57581         type: 'heading',
57582         depth: cap[1].length,
57583         text: cap[2]
57584       });
57585       continue;
57586     }
57587
57588     // table no leading pipe (gfm)
57589     if (top && (cap = this.rules.nptable.exec(src))) {
57590       src = src.substring(cap[0].length);
57591
57592       item = {
57593         type: 'table',
57594         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
57595         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
57596         cells: cap[3].replace(/\n$/, '').split('\n')
57597       };
57598
57599       for (i = 0; i < item.align.length; i++) {
57600         if (/^ *-+: *$/.test(item.align[i])) {
57601           item.align[i] = 'right';
57602         } else if (/^ *:-+: *$/.test(item.align[i])) {
57603           item.align[i] = 'center';
57604         } else if (/^ *:-+ *$/.test(item.align[i])) {
57605           item.align[i] = 'left';
57606         } else {
57607           item.align[i] = null;
57608         }
57609       }
57610
57611       for (i = 0; i < item.cells.length; i++) {
57612         item.cells[i] = item.cells[i].split(/ *\| */);
57613       }
57614
57615       this.tokens.push(item);
57616
57617       continue;
57618     }
57619
57620     // lheading
57621     if (cap = this.rules.lheading.exec(src)) {
57622       src = src.substring(cap[0].length);
57623       this.tokens.push({
57624         type: 'heading',
57625         depth: cap[2] === '=' ? 1 : 2,
57626         text: cap[1]
57627       });
57628       continue;
57629     }
57630
57631     // hr
57632     if (cap = this.rules.hr.exec(src)) {
57633       src = src.substring(cap[0].length);
57634       this.tokens.push({
57635         type: 'hr'
57636       });
57637       continue;
57638     }
57639
57640     // blockquote
57641     if (cap = this.rules.blockquote.exec(src)) {
57642       src = src.substring(cap[0].length);
57643
57644       this.tokens.push({
57645         type: 'blockquote_start'
57646       });
57647
57648       cap = cap[0].replace(/^ *> ?/gm, '');
57649
57650       // Pass `top` to keep the current
57651       // "toplevel" state. This is exactly
57652       // how markdown.pl works.
57653       this.token(cap, top, true);
57654
57655       this.tokens.push({
57656         type: 'blockquote_end'
57657       });
57658
57659       continue;
57660     }
57661
57662     // list
57663     if (cap = this.rules.list.exec(src)) {
57664       src = src.substring(cap[0].length);
57665       bull = cap[2];
57666
57667       this.tokens.push({
57668         type: 'list_start',
57669         ordered: bull.length > 1
57670       });
57671
57672       // Get each top-level item.
57673       cap = cap[0].match(this.rules.item);
57674
57675       next = false;
57676       l = cap.length;
57677       i = 0;
57678
57679       for (; i < l; i++) {
57680         item = cap[i];
57681
57682         // Remove the list item's bullet
57683         // so it is seen as the next token.
57684         space = item.length;
57685         item = item.replace(/^ *([*+-]|\d+\.) +/, '');
57686
57687         // Outdent whatever the
57688         // list item contains. Hacky.
57689         if (~item.indexOf('\n ')) {
57690           space -= item.length;
57691           item = !this.options.pedantic
57692             ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
57693             : item.replace(/^ {1,4}/gm, '');
57694         }
57695
57696         // Determine whether the next list item belongs here.
57697         // Backpedal if it does not belong in this list.
57698         if (this.options.smartLists && i !== l - 1) {
57699           b = block.bullet.exec(cap[i + 1])[0];
57700           if (bull !== b && !(bull.length > 1 && b.length > 1)) {
57701             src = cap.slice(i + 1).join('\n') + src;
57702             i = l - 1;
57703           }
57704         }
57705
57706         // Determine whether item is loose or not.
57707         // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
57708         // for discount behavior.
57709         loose = next || /\n\n(?!\s*$)/.test(item);
57710         if (i !== l - 1) {
57711           next = item.charAt(item.length - 1) === '\n';
57712           if (!loose) loose = next;
57713         }
57714
57715         this.tokens.push({
57716           type: loose
57717             ? 'loose_item_start'
57718             : 'list_item_start'
57719         });
57720
57721         // Recurse.
57722         this.token(item, false, bq);
57723
57724         this.tokens.push({
57725           type: 'list_item_end'
57726         });
57727       }
57728
57729       this.tokens.push({
57730         type: 'list_end'
57731       });
57732
57733       continue;
57734     }
57735
57736     // html
57737     if (cap = this.rules.html.exec(src)) {
57738       src = src.substring(cap[0].length);
57739       this.tokens.push({
57740         type: this.options.sanitize
57741           ? 'paragraph'
57742           : 'html',
57743         pre: !this.options.sanitizer
57744           && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
57745         text: cap[0]
57746       });
57747       continue;
57748     }
57749
57750     // def
57751     if ((!bq && top) && (cap = this.rules.def.exec(src))) {
57752       src = src.substring(cap[0].length);
57753       this.tokens.links[cap[1].toLowerCase()] = {
57754         href: cap[2],
57755         title: cap[3]
57756       };
57757       continue;
57758     }
57759
57760     // table (gfm)
57761     if (top && (cap = this.rules.table.exec(src))) {
57762       src = src.substring(cap[0].length);
57763
57764       item = {
57765         type: 'table',
57766         header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
57767         align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
57768         cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
57769       };
57770
57771       for (i = 0; i < item.align.length; i++) {
57772         if (/^ *-+: *$/.test(item.align[i])) {
57773           item.align[i] = 'right';
57774         } else if (/^ *:-+: *$/.test(item.align[i])) {
57775           item.align[i] = 'center';
57776         } else if (/^ *:-+ *$/.test(item.align[i])) {
57777           item.align[i] = 'left';
57778         } else {
57779           item.align[i] = null;
57780         }
57781       }
57782
57783       for (i = 0; i < item.cells.length; i++) {
57784         item.cells[i] = item.cells[i]
57785           .replace(/^ *\| *| *\| *$/g, '')
57786           .split(/ *\| */);
57787       }
57788
57789       this.tokens.push(item);
57790
57791       continue;
57792     }
57793
57794     // top-level paragraph
57795     if (top && (cap = this.rules.paragraph.exec(src))) {
57796       src = src.substring(cap[0].length);
57797       this.tokens.push({
57798         type: 'paragraph',
57799         text: cap[1].charAt(cap[1].length - 1) === '\n'
57800           ? cap[1].slice(0, -1)
57801           : cap[1]
57802       });
57803       continue;
57804     }
57805
57806     // text
57807     if (cap = this.rules.text.exec(src)) {
57808       // Top-level should never reach here.
57809       src = src.substring(cap[0].length);
57810       this.tokens.push({
57811         type: 'text',
57812         text: cap[0]
57813       });
57814       continue;
57815     }
57816
57817     if (src) {
57818       throw new
57819         Error('Infinite loop on byte: ' + src.charCodeAt(0));
57820     }
57821   }
57822
57823   return this.tokens;
57824 };
57825
57826 /**
57827  * Inline-Level Grammar
57828  */
57829
57830 var inline = {
57831   escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
57832   autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
57833   url: noop,
57834   tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
57835   link: /^!?\[(inside)\]\(href\)/,
57836   reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
57837   nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
57838   strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
57839   em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
57840   code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
57841   br: /^ {2,}\n(?!\s*$)/,
57842   del: noop,
57843   text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
57844 };
57845
57846 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
57847 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
57848
57849 inline.link = replace(inline.link)
57850   ('inside', inline._inside)
57851   ('href', inline._href)
57852   ();
57853
57854 inline.reflink = replace(inline.reflink)
57855   ('inside', inline._inside)
57856   ();
57857
57858 /**
57859  * Normal Inline Grammar
57860  */
57861
57862 inline.normal = merge({}, inline);
57863
57864 /**
57865  * Pedantic Inline Grammar
57866  */
57867
57868 inline.pedantic = merge({}, inline.normal, {
57869   strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
57870   em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
57871 });
57872
57873 /**
57874  * GFM Inline Grammar
57875  */
57876
57877 inline.gfm = merge({}, inline.normal, {
57878   escape: replace(inline.escape)('])', '~|])')(),
57879   url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
57880   del: /^~~(?=\S)([\s\S]*?\S)~~/,
57881   text: replace(inline.text)
57882     (']|', '~]|')
57883     ('|', '|https?://|')
57884     ()
57885 });
57886
57887 /**
57888  * GFM + Line Breaks Inline Grammar
57889  */
57890
57891 inline.breaks = merge({}, inline.gfm, {
57892   br: replace(inline.br)('{2,}', '*')(),
57893   text: replace(inline.gfm.text)('{2,}', '*')()
57894 });
57895
57896 /**
57897  * Inline Lexer & Compiler
57898  */
57899
57900 function InlineLexer(links, options) {
57901   this.options = options || marked.defaults;
57902   this.links = links;
57903   this.rules = inline.normal;
57904   this.renderer = this.options.renderer || new Renderer;
57905   this.renderer.options = this.options;
57906
57907   if (!this.links) {
57908     throw new
57909       Error('Tokens array requires a `links` property.');
57910   }
57911
57912   if (this.options.gfm) {
57913     if (this.options.breaks) {
57914       this.rules = inline.breaks;
57915     } else {
57916       this.rules = inline.gfm;
57917     }
57918   } else if (this.options.pedantic) {
57919     this.rules = inline.pedantic;
57920   }
57921 }
57922
57923 /**
57924  * Expose Inline Rules
57925  */
57926
57927 InlineLexer.rules = inline;
57928
57929 /**
57930  * Static Lexing/Compiling Method
57931  */
57932
57933 InlineLexer.output = function(src, links, options) {
57934   var inline = new InlineLexer(links, options);
57935   return inline.output(src);
57936 };
57937
57938 /**
57939  * Lexing/Compiling
57940  */
57941
57942 InlineLexer.prototype.output = function(src) {
57943   var out = ''
57944     , link
57945     , text
57946     , href
57947     , cap;
57948
57949   while (src) {
57950     // escape
57951     if (cap = this.rules.escape.exec(src)) {
57952       src = src.substring(cap[0].length);
57953       out += cap[1];
57954       continue;
57955     }
57956
57957     // autolink
57958     if (cap = this.rules.autolink.exec(src)) {
57959       src = src.substring(cap[0].length);
57960       if (cap[2] === '@') {
57961         text = cap[1].charAt(6) === ':'
57962           ? this.mangle(cap[1].substring(7))
57963           : this.mangle(cap[1]);
57964         href = this.mangle('mailto:') + text;
57965       } else {
57966         text = escape(cap[1]);
57967         href = text;
57968       }
57969       out += this.renderer.link(href, null, text);
57970       continue;
57971     }
57972
57973     // url (gfm)
57974     if (!this.inLink && (cap = this.rules.url.exec(src))) {
57975       src = src.substring(cap[0].length);
57976       text = escape(cap[1]);
57977       href = text;
57978       out += this.renderer.link(href, null, text);
57979       continue;
57980     }
57981
57982     // tag
57983     if (cap = this.rules.tag.exec(src)) {
57984       if (!this.inLink && /^<a /i.test(cap[0])) {
57985         this.inLink = true;
57986       } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
57987         this.inLink = false;
57988       }
57989       src = src.substring(cap[0].length);
57990       out += this.options.sanitize
57991         ? this.options.sanitizer
57992           ? this.options.sanitizer(cap[0])
57993           : escape(cap[0])
57994         : cap[0];
57995       continue;
57996     }
57997
57998     // link
57999     if (cap = this.rules.link.exec(src)) {
58000       src = src.substring(cap[0].length);
58001       this.inLink = true;
58002       out += this.outputLink(cap, {
58003         href: cap[2],
58004         title: cap[3]
58005       });
58006       this.inLink = false;
58007       continue;
58008     }
58009
58010     // reflink, nolink
58011     if ((cap = this.rules.reflink.exec(src))
58012         || (cap = this.rules.nolink.exec(src))) {
58013       src = src.substring(cap[0].length);
58014       link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
58015       link = this.links[link.toLowerCase()];
58016       if (!link || !link.href) {
58017         out += cap[0].charAt(0);
58018         src = cap[0].substring(1) + src;
58019         continue;
58020       }
58021       this.inLink = true;
58022       out += this.outputLink(cap, link);
58023       this.inLink = false;
58024       continue;
58025     }
58026
58027     // strong
58028     if (cap = this.rules.strong.exec(src)) {
58029       src = src.substring(cap[0].length);
58030       out += this.renderer.strong(this.output(cap[2] || cap[1]));
58031       continue;
58032     }
58033
58034     // em
58035     if (cap = this.rules.em.exec(src)) {
58036       src = src.substring(cap[0].length);
58037       out += this.renderer.em(this.output(cap[2] || cap[1]));
58038       continue;
58039     }
58040
58041     // code
58042     if (cap = this.rules.code.exec(src)) {
58043       src = src.substring(cap[0].length);
58044       out += this.renderer.codespan(escape(cap[2], true));
58045       continue;
58046     }
58047
58048     // br
58049     if (cap = this.rules.br.exec(src)) {
58050       src = src.substring(cap[0].length);
58051       out += this.renderer.br();
58052       continue;
58053     }
58054
58055     // del (gfm)
58056     if (cap = this.rules.del.exec(src)) {
58057       src = src.substring(cap[0].length);
58058       out += this.renderer.del(this.output(cap[1]));
58059       continue;
58060     }
58061
58062     // text
58063     if (cap = this.rules.text.exec(src)) {
58064       src = src.substring(cap[0].length);
58065       out += this.renderer.text(escape(this.smartypants(cap[0])));
58066       continue;
58067     }
58068
58069     if (src) {
58070       throw new
58071         Error('Infinite loop on byte: ' + src.charCodeAt(0));
58072     }
58073   }
58074
58075   return out;
58076 };
58077
58078 /**
58079  * Compile Link
58080  */
58081
58082 InlineLexer.prototype.outputLink = function(cap, link) {
58083   var href = escape(link.href)
58084     , title = link.title ? escape(link.title) : null;
58085
58086   return cap[0].charAt(0) !== '!'
58087     ? this.renderer.link(href, title, this.output(cap[1]))
58088     : this.renderer.image(href, title, escape(cap[1]));
58089 };
58090
58091 /**
58092  * Smartypants Transformations
58093  */
58094
58095 InlineLexer.prototype.smartypants = function(text) {
58096   if (!this.options.smartypants) return text;
58097   return text
58098     // em-dashes
58099     .replace(/---/g, '\u2014')
58100     // en-dashes
58101     .replace(/--/g, '\u2013')
58102     // opening singles
58103     .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
58104     // closing singles & apostrophes
58105     .replace(/'/g, '\u2019')
58106     // opening doubles
58107     .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
58108     // closing doubles
58109     .replace(/"/g, '\u201d')
58110     // ellipses
58111     .replace(/\.{3}/g, '\u2026');
58112 };
58113
58114 /**
58115  * Mangle Links
58116  */
58117
58118 InlineLexer.prototype.mangle = function(text) {
58119   if (!this.options.mangle) return text;
58120   var out = ''
58121     , l = text.length
58122     , i = 0
58123     , ch;
58124
58125   for (; i < l; i++) {
58126     ch = text.charCodeAt(i);
58127     if (Math.random() > 0.5) {
58128       ch = 'x' + ch.toString(16);
58129     }
58130     out += '&#' + ch + ';';
58131   }
58132
58133   return out;
58134 };
58135
58136 /**
58137  * Renderer
58138  */
58139
58140 function Renderer(options) {
58141   this.options = options || {};
58142 }
58143
58144 Renderer.prototype.code = function(code, lang, escaped) {
58145   if (this.options.highlight) {
58146     var out = this.options.highlight(code, lang);
58147     if (out != null && out !== code) {
58148       escaped = true;
58149       code = out;
58150     }
58151   }
58152
58153   if (!lang) {
58154     return '<pre><code>'
58155       + (escaped ? code : escape(code, true))
58156       + '\n</code></pre>';
58157   }
58158
58159   return '<pre><code class="'
58160     + this.options.langPrefix
58161     + escape(lang, true)
58162     + '">'
58163     + (escaped ? code : escape(code, true))
58164     + '\n</code></pre>\n';
58165 };
58166
58167 Renderer.prototype.blockquote = function(quote) {
58168   return '<blockquote>\n' + quote + '</blockquote>\n';
58169 };
58170
58171 Renderer.prototype.html = function(html) {
58172   return html;
58173 };
58174
58175 Renderer.prototype.heading = function(text, level, raw) {
58176   return '<h'
58177     + level
58178     + ' id="'
58179     + this.options.headerPrefix
58180     + raw.toLowerCase().replace(/[^\w]+/g, '-')
58181     + '">'
58182     + text
58183     + '</h'
58184     + level
58185     + '>\n';
58186 };
58187
58188 Renderer.prototype.hr = function() {
58189   return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
58190 };
58191
58192 Renderer.prototype.list = function(body, ordered) {
58193   var type = ordered ? 'ol' : 'ul';
58194   return '<' + type + '>\n' + body + '</' + type + '>\n';
58195 };
58196
58197 Renderer.prototype.listitem = function(text) {
58198   return '<li>' + text + '</li>\n';
58199 };
58200
58201 Renderer.prototype.paragraph = function(text) {
58202   return '<p>' + text + '</p>\n';
58203 };
58204
58205 Renderer.prototype.table = function(header, body) {
58206   return '<table>\n'
58207     + '<thead>\n'
58208     + header
58209     + '</thead>\n'
58210     + '<tbody>\n'
58211     + body
58212     + '</tbody>\n'
58213     + '</table>\n';
58214 };
58215
58216 Renderer.prototype.tablerow = function(content) {
58217   return '<tr>\n' + content + '</tr>\n';
58218 };
58219
58220 Renderer.prototype.tablecell = function(content, flags) {
58221   var type = flags.header ? 'th' : 'td';
58222   var tag = flags.align
58223     ? '<' + type + ' style="text-align:' + flags.align + '">'
58224     : '<' + type + '>';
58225   return tag + content + '</' + type + '>\n';
58226 };
58227
58228 // span level renderer
58229 Renderer.prototype.strong = function(text) {
58230   return '<strong>' + text + '</strong>';
58231 };
58232
58233 Renderer.prototype.em = function(text) {
58234   return '<em>' + text + '</em>';
58235 };
58236
58237 Renderer.prototype.codespan = function(text) {
58238   return '<code>' + text + '</code>';
58239 };
58240
58241 Renderer.prototype.br = function() {
58242   return this.options.xhtml ? '<br/>' : '<br>';
58243 };
58244
58245 Renderer.prototype.del = function(text) {
58246   return '<del>' + text + '</del>';
58247 };
58248
58249 Renderer.prototype.link = function(href, title, text) {
58250   if (this.options.sanitize) {
58251     try {
58252       var prot = decodeURIComponent(unescape(href))
58253         .replace(/[^\w:]/g, '')
58254         .toLowerCase();
58255     } catch (e) {
58256       return '';
58257     }
58258     if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
58259       return '';
58260     }
58261   }
58262   var out = '<a href="' + href + '"';
58263   if (title) {
58264     out += ' title="' + title + '"';
58265   }
58266   out += '>' + text + '</a>';
58267   return out;
58268 };
58269
58270 Renderer.prototype.image = function(href, title, text) {
58271   var out = '<img src="' + href + '" alt="' + text + '"';
58272   if (title) {
58273     out += ' title="' + title + '"';
58274   }
58275   out += this.options.xhtml ? '/>' : '>';
58276   return out;
58277 };
58278
58279 Renderer.prototype.text = function(text) {
58280   return text;
58281 };
58282
58283 /**
58284  * Parsing & Compiling
58285  */
58286
58287 function Parser(options) {
58288   this.tokens = [];
58289   this.token = null;
58290   this.options = options || marked.defaults;
58291   this.options.renderer = this.options.renderer || new Renderer;
58292   this.renderer = this.options.renderer;
58293   this.renderer.options = this.options;
58294 }
58295
58296 /**
58297  * Static Parse Method
58298  */
58299
58300 Parser.parse = function(src, options, renderer) {
58301   var parser = new Parser(options, renderer);
58302   return parser.parse(src);
58303 };
58304
58305 /**
58306  * Parse Loop
58307  */
58308
58309 Parser.prototype.parse = function(src) {
58310   this.inline = new InlineLexer(src.links, this.options, this.renderer);
58311   this.tokens = src.reverse();
58312
58313   var out = '';
58314   while (this.next()) {
58315     out += this.tok();
58316   }
58317
58318   return out;
58319 };
58320
58321 /**
58322  * Next Token
58323  */
58324
58325 Parser.prototype.next = function() {
58326   return this.token = this.tokens.pop();
58327 };
58328
58329 /**
58330  * Preview Next Token
58331  */
58332
58333 Parser.prototype.peek = function() {
58334   return this.tokens[this.tokens.length - 1] || 0;
58335 };
58336
58337 /**
58338  * Parse Text Tokens
58339  */
58340
58341 Parser.prototype.parseText = function() {
58342   var body = this.token.text;
58343
58344   while (this.peek().type === 'text') {
58345     body += '\n' + this.next().text;
58346   }
58347
58348   return this.inline.output(body);
58349 };
58350
58351 /**
58352  * Parse Current Token
58353  */
58354
58355 Parser.prototype.tok = function() {
58356   switch (this.token.type) {
58357     case 'space': {
58358       return '';
58359     }
58360     case 'hr': {
58361       return this.renderer.hr();
58362     }
58363     case 'heading': {
58364       return this.renderer.heading(
58365         this.inline.output(this.token.text),
58366         this.token.depth,
58367         this.token.text);
58368     }
58369     case 'code': {
58370       return this.renderer.code(this.token.text,
58371         this.token.lang,
58372         this.token.escaped);
58373     }
58374     case 'table': {
58375       var header = ''
58376         , body = ''
58377         , i
58378         , row
58379         , cell
58380         , flags
58381         , j;
58382
58383       // header
58384       cell = '';
58385       for (i = 0; i < this.token.header.length; i++) {
58386         flags = { header: true, align: this.token.align[i] };
58387         cell += this.renderer.tablecell(
58388           this.inline.output(this.token.header[i]),
58389           { header: true, align: this.token.align[i] }
58390         );
58391       }
58392       header += this.renderer.tablerow(cell);
58393
58394       for (i = 0; i < this.token.cells.length; i++) {
58395         row = this.token.cells[i];
58396
58397         cell = '';
58398         for (j = 0; j < row.length; j++) {
58399           cell += this.renderer.tablecell(
58400             this.inline.output(row[j]),
58401             { header: false, align: this.token.align[j] }
58402           );
58403         }
58404
58405         body += this.renderer.tablerow(cell);
58406       }
58407       return this.renderer.table(header, body);
58408     }
58409     case 'blockquote_start': {
58410       var body = '';
58411
58412       while (this.next().type !== 'blockquote_end') {
58413         body += this.tok();
58414       }
58415
58416       return this.renderer.blockquote(body);
58417     }
58418     case 'list_start': {
58419       var body = ''
58420         , ordered = this.token.ordered;
58421
58422       while (this.next().type !== 'list_end') {
58423         body += this.tok();
58424       }
58425
58426       return this.renderer.list(body, ordered);
58427     }
58428     case 'list_item_start': {
58429       var body = '';
58430
58431       while (this.next().type !== 'list_item_end') {
58432         body += this.token.type === 'text'
58433           ? this.parseText()
58434           : this.tok();
58435       }
58436
58437       return this.renderer.listitem(body);
58438     }
58439     case 'loose_item_start': {
58440       var body = '';
58441
58442       while (this.next().type !== 'list_item_end') {
58443         body += this.tok();
58444       }
58445
58446       return this.renderer.listitem(body);
58447     }
58448     case 'html': {
58449       var html = !this.token.pre && !this.options.pedantic
58450         ? this.inline.output(this.token.text)
58451         : this.token.text;
58452       return this.renderer.html(html);
58453     }
58454     case 'paragraph': {
58455       return this.renderer.paragraph(this.inline.output(this.token.text));
58456     }
58457     case 'text': {
58458       return this.renderer.paragraph(this.parseText());
58459     }
58460   }
58461 };
58462
58463 /**
58464  * Helpers
58465  */
58466
58467 function escape(html, encode) {
58468   return html
58469     .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
58470     .replace(/</g, '&lt;')
58471     .replace(/>/g, '&gt;')
58472     .replace(/"/g, '&quot;')
58473     .replace(/'/g, '&#39;');
58474 }
58475
58476 function unescape(html) {
58477         // explicitly match decimal, hex, and named HTML entities 
58478   return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
58479     n = n.toLowerCase();
58480     if (n === 'colon') return ':';
58481     if (n.charAt(0) === '#') {
58482       return n.charAt(1) === 'x'
58483         ? String.fromCharCode(parseInt(n.substring(2), 16))
58484         : String.fromCharCode(+n.substring(1));
58485     }
58486     return '';
58487   });
58488 }
58489
58490 function replace(regex, opt) {
58491   regex = regex.source;
58492   opt = opt || '';
58493   return function self(name, val) {
58494     if (!name) return new RegExp(regex, opt);
58495     val = val.source || val;
58496     val = val.replace(/(^|[^\[])\^/g, '$1');
58497     regex = regex.replace(name, val);
58498     return self;
58499   };
58500 }
58501
58502 function noop() {}
58503 noop.exec = noop;
58504
58505 function merge(obj) {
58506   var i = 1
58507     , target
58508     , key;
58509
58510   for (; i < arguments.length; i++) {
58511     target = arguments[i];
58512     for (key in target) {
58513       if (Object.prototype.hasOwnProperty.call(target, key)) {
58514         obj[key] = target[key];
58515       }
58516     }
58517   }
58518
58519   return obj;
58520 }
58521
58522
58523 /**
58524  * Marked
58525  */
58526
58527 function marked(src, opt, callback) {
58528   if (callback || typeof opt === 'function') {
58529     if (!callback) {
58530       callback = opt;
58531       opt = null;
58532     }
58533
58534     opt = merge({}, marked.defaults, opt || {});
58535
58536     var highlight = opt.highlight
58537       , tokens
58538       , pending
58539       , i = 0;
58540
58541     try {
58542       tokens = Lexer.lex(src, opt);
58543     } catch (e) {
58544       return callback(e);
58545     }
58546
58547     pending = tokens.length;
58548
58549     var done = function(err) {
58550       if (err) {
58551         opt.highlight = highlight;
58552         return callback(err);
58553       }
58554
58555       var out;
58556
58557       try {
58558         out = Parser.parse(tokens, opt);
58559       } catch (e) {
58560         err = e;
58561       }
58562
58563       opt.highlight = highlight;
58564
58565       return err
58566         ? callback(err)
58567         : callback(null, out);
58568     };
58569
58570     if (!highlight || highlight.length < 3) {
58571       return done();
58572     }
58573
58574     delete opt.highlight;
58575
58576     if (!pending) return done();
58577
58578     for (; i < tokens.length; i++) {
58579       (function(token) {
58580         if (token.type !== 'code') {
58581           return --pending || done();
58582         }
58583         return highlight(token.text, token.lang, function(err, code) {
58584           if (err) return done(err);
58585           if (code == null || code === token.text) {
58586             return --pending || done();
58587           }
58588           token.text = code;
58589           token.escaped = true;
58590           --pending || done();
58591         });
58592       })(tokens[i]);
58593     }
58594
58595     return;
58596   }
58597   try {
58598     if (opt) opt = merge({}, marked.defaults, opt);
58599     return Parser.parse(Lexer.lex(src, opt), opt);
58600   } catch (e) {
58601     e.message += '\nPlease report this to https://github.com/chjj/marked.';
58602     if ((opt || marked.defaults).silent) {
58603       return '<p>An error occured:</p><pre>'
58604         + escape(e.message + '', true)
58605         + '</pre>';
58606     }
58607     throw e;
58608   }
58609 }
58610
58611 /**
58612  * Options
58613  */
58614
58615 marked.options =
58616 marked.setOptions = function(opt) {
58617   merge(marked.defaults, opt);
58618   return marked;
58619 };
58620
58621 marked.defaults = {
58622   gfm: true,
58623   tables: true,
58624   breaks: false,
58625   pedantic: false,
58626   sanitize: false,
58627   sanitizer: null,
58628   mangle: true,
58629   smartLists: false,
58630   silent: false,
58631   highlight: null,
58632   langPrefix: 'lang-',
58633   smartypants: false,
58634   headerPrefix: '',
58635   renderer: new Renderer,
58636   xhtml: false
58637 };
58638
58639 /**
58640  * Expose
58641  */
58642
58643 marked.Parser = Parser;
58644 marked.parser = Parser.parse;
58645
58646 marked.Renderer = Renderer;
58647
58648 marked.Lexer = Lexer;
58649 marked.lexer = Lexer.lex;
58650
58651 marked.InlineLexer = InlineLexer;
58652 marked.inlineLexer = InlineLexer.output;
58653
58654 marked.parse = marked;
58655
58656 {
58657   module.exports = marked;
58658 }
58659
58660 }).call(function() {
58661   return this || (typeof window !== 'undefined' ? window : commonjsGlobal);
58662 }());
58663 });
58664
58665 function pointBox(loc, context) {
58666     var rect = context.surfaceRect();
58667     var point = context.curtainProjection(loc);
58668     return {
58669         left: point[0] + rect.left - 40,
58670         top: point[1] + rect.top - 60,
58671         width: 80,
58672         height: 90
58673     };
58674 }
58675
58676
58677 function pad$1(locOrBox, padding, context) {
58678     var box;
58679     if (locOrBox instanceof Array) {
58680         var rect = context.surfaceRect();
58681         var point = context.curtainProjection(locOrBox);
58682         box = {
58683             left: point[0] + rect.left,
58684             top: point[1] + rect.top
58685         };
58686     } else {
58687         box = locOrBox;
58688     }
58689
58690     return {
58691         left: box.left - padding,
58692         top: box.top - padding,
58693         width: (box.width || 0) + 2 * padding,
58694         height: (box.width || 0) + 2 * padding
58695     };
58696 }
58697
58698
58699 function icon(name, svgklass) {
58700     return '<svg class="icon ' + (svgklass || '') + '">' +
58701          '<use xlink:href="' + name + '"></use></svg>';
58702 }
58703
58704
58705 function slugify(text$$1) {
58706     return text$$1.toString().toLowerCase()
58707         .replace(/\s+/g, '-')           // Replace spaces with -
58708         .replace(/[^\w\-]+/g, '')       // Remove all non-word chars
58709         .replace(/\-\-+/g, '-')         // Replace multiple - with single -
58710         .replace(/^-+/, '')             // Trim - from start of text
58711         .replace(/-+$/, '');            // Trim - from end of text
58712 }
58713
58714
58715 // console warning for missing walkthrough names
58716 var missingStrings = {};
58717 function checkKey(key, text$$1) {
58718     if (t(key, { default: undefined}) === undefined) {
58719         if (missingStrings.hasOwnProperty(key)) return;  // warn once
58720         missingStrings[key] = text$$1;
58721         var missing = key + ': ' + text$$1;
58722         if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
58723     }
58724 }
58725
58726
58727 function localize(obj) {
58728     var key;
58729
58730     // Assign name if entity has one..
58731     var name = obj.tags && obj.tags.name;
58732     if (name) {
58733         key = 'intro.graph.name.' + slugify(name);
58734         obj.tags.name = t(key, { default: name });
58735         checkKey(key, name);
58736     }
58737
58738     // Assign street name if entity has one..
58739     var street = obj.tags && obj.tags['addr:street'];
58740     if (street) {
58741         key = 'intro.graph.name.' + slugify(street);
58742         obj.tags['addr:street'] = t(key, { default: street });
58743         checkKey(key, street);
58744
58745         // Add address details common across walkthrough..
58746         var addrTags = [
58747             'block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood',
58748             'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'
58749         ];
58750         addrTags.forEach(function(k) {
58751             var key = 'intro.graph.' + k,
58752                 tag = 'addr:' + k,
58753                 val = obj.tags && obj.tags[tag],
58754                 str = t(key, { default: val });
58755
58756             if (str) {
58757                 if (str.match(/^<.*>$/) !== null) {
58758                     delete obj.tags[tag];
58759                 } else {
58760                     obj.tags[tag] = str;
58761                 }
58762             }
58763         });
58764     }
58765
58766     return obj;
58767 }
58768
58769
58770 // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
58771 function isMostlySquare(points) {
58772     // note: uses 15 here instead of the 12 from actionOrthogonalize because
58773     // actionOrthogonalize can actually straighten some larger angles as it iterates
58774     var threshold$$1 = 15, // degrees within right or straight
58775         lowerBound = Math.cos((90 - threshold$$1) * Math.PI / 180),  // near right
58776         upperBound = Math.cos(threshold$$1 * Math.PI / 180),         // near straight
58777         mag;
58778
58779     for (var i = 0; i < points.length; i++) {
58780         mag = Math.abs(normalizedDotProduct(i, points));
58781         if (mag > lowerBound && mag < upperBound) {
58782             return false;
58783         }
58784     }
58785
58786     return true;
58787
58788
58789     function normalizedDotProduct(i, points) {
58790         var a = points[(i - 1 + points.length) % points.length],
58791             b = points[i],
58792             c = points[(i + 1) % points.length],
58793             p = subtractPoints(a, b),
58794             q = subtractPoints(c, b);
58795
58796         p = normalizePoint(p);
58797         q = normalizePoint(q);
58798
58799         return p[0] * q[0] + p[1] * q[1];
58800
58801
58802         function subtractPoints(a, b) {
58803             return [a[0] - b[0], a[1] - b[1]];
58804         }
58805
58806         function normalizePoint(point) {
58807             var vector = [0, 0];
58808             var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
58809             if (length !== 0) {
58810                 vector[0] = point[0] / length;
58811                 vector[1] = point[1] / length;
58812             }
58813             return vector;
58814         }
58815     }
58816 }
58817
58818
58819 function selectMenuItem(operation) {
58820     var selector$$1 = '.edit-menu .edit-menu-item-' + operation +
58821         ', .radial-menu .radial-menu-item-' + operation;
58822     return select(selector$$1);
58823 }
58824
58825
58826 function transitionTime(point1, point2) {
58827     var distance$$1 = geoSphericalDistance(point1, point2);
58828     if (distance$$1 === 0)
58829         return 0;
58830     else if (distance$$1 < 80)
58831         return 500;
58832     else
58833         return 1000;
58834 }
58835
58836 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"}}};
58837
58838 // toggles the visibility of ui elements, using a combination of the
58839 // hide class, which sets display=none, and a d3 transition for opacity.
58840 // this will cause blinking when called repeatedly, so check that the
58841 // value actually changes between calls.
58842 function uiToggle(show, callback) {
58843     return function(selection$$1) {
58844         selection$$1
58845             .style('opacity', show ? 0 : 1)
58846             .classed('hide', false)
58847             .transition()
58848             .style('opacity', show ? 1 : 0)
58849             .on('end', function() {
58850                 select(this)
58851                     .classed('hide', !show)
58852                     .style('opacity', null);
58853                 if (callback) callback.apply(this);
58854             });
58855     };
58856 }
58857
58858 // Tooltips and svg mask used to highlight certain features
58859 function uiCurtain() {
58860
58861     var surface = select(null),
58862         tooltip = select(null),
58863         darkness = select(null);
58864
58865     function curtain(selection$$1) {
58866         surface = selection$$1
58867             .append('svg')
58868             .attr('id', 'curtain')
58869             .style('z-index', 1000)
58870             .style('pointer-events', 'none')
58871             .style('position', 'absolute')
58872             .style('top', 0)
58873             .style('left', 0);
58874
58875         darkness = surface.append('path')
58876             .attr('x', 0)
58877             .attr('y', 0)
58878             .attr('class', 'curtain-darkness');
58879
58880         select(window).on('resize.curtain', resize);
58881
58882         tooltip = selection$$1.append('div')
58883             .attr('class', 'tooltip')
58884             .style('z-index', 1002);
58885
58886         tooltip
58887             .append('div')
58888             .attr('class', 'tooltip-arrow');
58889
58890         tooltip
58891             .append('div')
58892             .attr('class', 'tooltip-inner');
58893
58894         resize();
58895
58896
58897         function resize() {
58898             surface
58899                 .attr('width', window.innerWidth)
58900                 .attr('height', window.innerHeight);
58901             curtain.cut(darkness.datum());
58902         }
58903     }
58904
58905
58906     /**
58907      * Reveal cuts the curtain to highlight the given box,
58908      * and shows a tooltip with instructions next to the box.
58909      *
58910      * @param  {String|ClientRect} [box]   box used to cut the curtain
58911      * @param  {String}    [text]          text for a tooltip
58912      * @param  {Object}    [options]
58913      * @param  {string}    [options.tooltipClass]    optional class to add to the tooltip
58914      * @param  {integer}   [options.duration]        transition time in milliseconds
58915      * @param  {string}    [options.buttonText]      if set, create a button with this text label
58916      * @param  {function}  [options.buttonCallback]  if set, the callback for the button
58917      * @param  {String|ClientRect} [options.tooltipBox]  box for tooltip position, if different from box for the curtain
58918      */
58919     curtain.reveal = function(box, text$$1, options) {
58920         if (typeof box === 'string') {
58921             box = select(box).node();
58922         }
58923         if (box && box.getBoundingClientRect) {
58924             box = copyBox(box.getBoundingClientRect());
58925         }
58926
58927         options = options || {};
58928
58929         var tooltipBox;
58930         if (options.tooltipBox) {
58931             tooltipBox = options.tooltipBox;
58932             if (typeof tooltipBox === 'string') {
58933                 tooltipBox = select(tooltipBox).node();
58934             }
58935             if (tooltipBox && tooltipBox.getBoundingClientRect) {
58936                 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
58937             }
58938         } else {
58939             tooltipBox = box;
58940         }
58941
58942         if (tooltipBox && text$$1) {
58943             // pseudo markdown bold text for the instruction section..
58944             var parts = text$$1.split('**');
58945             var html$$1 = parts[0] ? '<span>' + parts[0] + '</span>' : '';
58946             if (parts[1]) {
58947                 html$$1 += '<span class="instruction">' + parts[1] + '</span>';
58948             }
58949
58950             html$$1 = html$$1.replace(/\*(.*?)\*/g, '<em>$1</em>');   // emphasis
58951             html$$1 = html$$1.replace(/\{br\}/g, '<br/><br/>');       // linebreak
58952
58953             if (options.buttonText && options.buttonCallback) {
58954                 html$$1 += '<div class="button-section">' +
58955                     '<button href="#" class="button action col8">' + options.buttonText + '</button></div>';
58956             }
58957
58958             var classes = 'curtain-tooltip tooltip in ' + (options.tooltipClass || '');
58959             tooltip
58960                 .classed(classes, true)
58961                 .selectAll('.tooltip-inner')
58962                 .html(html$$1);
58963
58964             if (options.buttonText && options.buttonCallback) {
58965                 var button = tooltip.selectAll('.button-section .button.action');
58966                 button
58967                     .on('click', function() {
58968                         event.preventDefault();
58969                         options.buttonCallback();
58970                     });
58971             }
58972
58973             var tip = copyBox(tooltip.node().getBoundingClientRect()),
58974                 w = window.innerWidth,
58975                 h = window.innerHeight,
58976                 tooltipWidth = 200,
58977                 tooltipArrow = 5,
58978                 side, pos;
58979
58980
58981             // hack: this will have bottom placement,
58982             // so need to reserve extra space for the tooltip illustration.
58983             if (options.tooltipClass === 'intro-mouse') {
58984                 tip.height += 80;
58985             }
58986
58987             // trim box dimensions to just the portion that fits in the window..
58988             if (tooltipBox.top + tooltipBox.height > h) {
58989                 tooltipBox.height -= (tooltipBox.top + tooltipBox.height - h);
58990             }
58991             if (tooltipBox.left + tooltipBox.width > w) {
58992                 tooltipBox.width -= (tooltipBox.left + tooltipBox.width - w);
58993             }
58994
58995             // determine tooltip placement..
58996
58997             if (tooltipBox.top + tooltipBox.height < 100) {
58998                 // tooltip below box..
58999                 side = 'bottom';
59000                 pos = [
59001                     tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
59002                     tooltipBox.top + tooltipBox.height
59003                 ];
59004
59005             } else if (tooltipBox.top > h - 140) {
59006                 // tooltip above box..
59007                 side = 'top';
59008                 pos = [
59009                     tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
59010                     tooltipBox.top - tip.height
59011                 ];
59012
59013             } else {
59014                 // tooltip to the side of the tooltipBox..
59015                 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
59016
59017                 if (textDirection === 'rtl') {
59018                     if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
59019                         side = 'right';
59020                         pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
59021
59022                     } else {
59023                         side = 'left';
59024                         pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
59025                     }
59026
59027                 } else {
59028                     if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
59029                         side = 'left';
59030                         pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
59031                     }
59032                     else {
59033                         side = 'right';
59034                         pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
59035                     }
59036                 }
59037             }
59038
59039             if (options.duration !== 0 || !tooltip.classed(side)) {
59040                 tooltip.call(uiToggle(true));
59041             }
59042
59043             tooltip
59044                 .style('top', pos[1] + 'px')
59045                 .style('left', pos[0] + 'px')
59046                 .attr('class', classes + ' ' + side);
59047
59048
59049             // shift tooltip-inner if it is very close to the top or bottom edge
59050             // (doesn't affect the placement of the tooltip-arrow)
59051             var shiftY = 0;
59052             if (side === 'left' || side === 'right') {
59053                 if (pos[1] < 60) {
59054                     shiftY = 60 - pos[1];
59055                 }
59056                 else if (pos[1] + tip.height > h - 100) {
59057                     shiftY = h - pos[1] - tip.height - 100;
59058                 }
59059             }
59060             tooltip.selectAll('.tooltip-inner')
59061                 .style('top', shiftY + 'px');
59062
59063         } else {
59064             tooltip
59065                 .classed('in', false)
59066                 .call(uiToggle(false));
59067         }
59068
59069         curtain.cut(box, options.duration);
59070
59071         return tooltip;
59072     };
59073
59074
59075     curtain.cut = function(datum, duration) {
59076         darkness.datum(datum)
59077             .interrupt();
59078
59079         var selection$$1;
59080         if (duration === 0) {
59081             selection$$1 = darkness;
59082         } else {
59083             selection$$1 = darkness
59084                 .transition()
59085                 .duration(duration || 600)
59086                 .ease(linear$1);
59087         }
59088
59089         selection$$1
59090             .attr('d', function(d) {
59091                 var string = 'M 0,0 L 0,' + window.innerHeight + ' L ' +
59092                     window.innerWidth + ',' + window.innerHeight + 'L' +
59093                     window.innerWidth + ',0 Z';
59094
59095                 if (!d) return string;
59096                 return string + 'M' +
59097                     d.left + ',' + d.top + 'L' +
59098                     d.left + ',' + (d.top + d.height) + 'L' +
59099                     (d.left + d.width) + ',' + (d.top + d.height) + 'L' +
59100                     (d.left + d.width) + ',' + (d.top) + 'Z';
59101
59102             });
59103     };
59104
59105
59106     curtain.remove = function() {
59107         surface.remove();
59108         tooltip.remove();
59109         select(window).on('resize.curtain', null);
59110     };
59111
59112
59113     // ClientRects are immutable, so copy them to an object,
59114     // in case we need to trim the height/width.
59115     function copyBox(src) {
59116         return {
59117             top: src.top,
59118             right: src.right,
59119             bottom: src.bottom,
59120             left: src.left,
59121             width: src.width,
59122             height: src.height
59123         };
59124     }
59125
59126
59127     return curtain;
59128 }
59129
59130 function uiIntroWelcome(context, reveal) {
59131     var dispatch$$1 = dispatch('done'),
59132         listener = clickListener();
59133
59134     var chapter = {
59135         title: 'intro.welcome.title'
59136     };
59137
59138
59139     function welcome() {
59140         context.map().centerZoom([-85.63591, 41.94285], 19);
59141         reveal('.intro-nav-wrap .chapter-welcome',
59142             t('intro.welcome.welcome'),
59143             { buttonText: t('intro.ok'), buttonCallback: practice }
59144         );
59145     }
59146
59147     function practice() {
59148         reveal('.intro-nav-wrap .chapter-welcome',
59149             t('intro.welcome.practice'),
59150             { buttonText: t('intro.ok'), buttonCallback: words }
59151         );
59152     }
59153
59154     function words() {
59155         reveal('.intro-nav-wrap .chapter-welcome',
59156             t('intro.welcome.words'),
59157             { buttonText: t('intro.ok'), buttonCallback: mouse$$1 }
59158         );
59159     }
59160
59161
59162     function mouse$$1() {
59163         reveal('.intro-nav-wrap .chapter-welcome',
59164             t('intro.welcome.mouse'),
59165             { buttonText: t('intro.ok'), buttonCallback: leftClick }
59166         );
59167     }
59168
59169
59170     function leftClick() {
59171         var counter = 0,
59172             times = 5;
59173
59174         var tooltip = reveal('.intro-nav-wrap .chapter-welcome',
59175             t('intro.welcome.leftclick', { num: times }),
59176             { tooltipClass: 'intro-mouse' }
59177         );
59178
59179         tooltip.selectAll('.tooltip-inner')
59180             .insert('svg', 'span')
59181             .attr('class', 'tooltip-illustration')
59182             .append('use')
59183             .attr('xlink:href', '#walkthrough-mouse');
59184
59185         tooltip
59186             .append('div')
59187             .attr('class', 'counter');
59188
59189         tooltip.call(listener);
59190
59191         listener.on('click', function(which) {
59192             if (which === 'left') {
59193                 select('.curtain-tooltip.intro-mouse .counter')
59194                     .text(String(++counter));
59195
59196                 if (counter === times) {
59197                     window.setTimeout(function() { continueTo(rightClick); }, 1000);
59198                 }
59199             }
59200         });
59201
59202         function continueTo(nextStep) {
59203             listener.on('click', null);
59204             tooltip.call(listener.off);
59205             tooltip.select('.counter').remove();
59206             nextStep();
59207         }
59208     }
59209
59210
59211     function rightClick() {
59212         var counter = 0,
59213             times = 5;
59214
59215         var tooltip = reveal('.intro-nav-wrap .chapter-welcome',
59216             t('intro.welcome.rightclick', { num: times }),
59217             { tooltipClass: 'intro-mouse' }
59218         );
59219
59220         tooltip.selectAll('.tooltip-inner')
59221             .insert('svg', 'span')
59222             .attr('class', 'tooltip-illustration')
59223             .append('use')
59224             .attr('xlink:href', '#walkthrough-mouse');
59225
59226         tooltip
59227             .append('div')
59228             .attr('class', 'counter');
59229
59230         tooltip.call(listener);
59231
59232         listener.on('click', function(which) {
59233             if (which === 'right') {
59234                 select('.curtain-tooltip.intro-mouse .counter')
59235                     .text(String(++counter));
59236
59237                 if (counter === times) {
59238                     window.setTimeout(function() { continueTo(chapters); }, 1000);
59239                 }
59240             }
59241         });
59242
59243         function continueTo(nextStep) {
59244             listener.on('click', null);
59245             tooltip.call(listener.off);
59246             tooltip.select('.counter').remove();
59247             nextStep();
59248         }
59249     }
59250
59251
59252     function chapters() {
59253         dispatch$$1.call('done');
59254         reveal('.intro-nav-wrap .chapter-navigation',
59255             t('intro.welcome.chapters', { next: t('intro.navigation.title') })
59256         );
59257     }
59258
59259
59260     chapter.enter = function() {
59261         welcome();
59262     };
59263
59264
59265     chapter.exit = function() {
59266         listener.off();
59267     };
59268
59269
59270     chapter.restart = function() {
59271         chapter.exit();
59272         chapter.enter();
59273     };
59274
59275
59276     return utilRebind(chapter, dispatch$$1, 'on');
59277 }
59278
59279
59280
59281 function clickListener() {
59282     var dispatch$$1 = dispatch('click'),
59283         minTime = 120,
59284         tooltip = select(null),
59285         down = {};
59286
59287     // `down` keeps track of which buttons/keys are down.
59288     // Setting a property in `down` happens immediately.
59289     // Unsetting a property in `down` is delayed because
59290     //   on Windows a contextmenu event happens after keyup/mouseup
59291
59292     function keydown() {
59293         if (event.keyCode === 93)  {   // context menu
59294             event.preventDefault();
59295             event.stopPropagation();
59296             down.menu = event.timeStamp;
59297             tooltip.classed('rightclick', true);
59298         }
59299     }
59300
59301
59302     function keyup() {
59303         if (event.keyCode === 93)  {   // context menu
59304             event.preventDefault();
59305             event.stopPropagation();
59306             var endTime = event.timeStamp,
59307                 startTime = down.menu || endTime,
59308                 delay = (endTime - startTime < minTime) ? minTime : 0;
59309
59310             window.setTimeout(function() {
59311                 tooltip.classed('rightclick', false);
59312                 down.menu = undefined;  // delayed, for Windows
59313             }, delay);
59314
59315             dispatch$$1.call('click', this, 'right');
59316         }
59317     }
59318
59319
59320     function mousedown() {
59321         var button = event.button;
59322         if (button === 0 && !event.ctrlKey) {
59323             tooltip.classed('leftclick', true);
59324         } else if (button === 2) {
59325             tooltip.classed('rightclick', true);
59326         }
59327         down[button] = event.timeStamp;
59328     }
59329
59330
59331     function mouseup() {
59332         var button = event.button,
59333             endTime = event.timeStamp,
59334             startTime = down[button] || endTime,
59335             delay = (endTime - startTime < minTime) ? minTime : 0;
59336
59337         if (button === 0 && !event.ctrlKey) {
59338             window.setTimeout(function() {
59339                 tooltip.classed('leftclick', false);
59340                 down[button] = undefined;  // delayed, for Windows
59341             }, delay);
59342
59343             dispatch$$1.call('click', this, 'left');
59344
59345         } else if (button === 2) {
59346             window.setTimeout(function() {
59347                 tooltip.classed('rightclick', false);
59348                 down[button] = undefined;  // delayed, for Windows
59349             }, delay);
59350
59351             dispatch$$1.call('click', this, 'right');
59352
59353         } else {
59354             window.setTimeout(function() {
59355                 down[button] = undefined;  // delayed, for Windows
59356             }, delay);
59357         }
59358     }
59359
59360
59361     function contextmenu() {
59362         event.preventDefault();
59363         event.stopPropagation();
59364         if (!down[2] && !down.menu) {
59365             tooltip.classed('rightclick', true);
59366             window.setTimeout(function() {
59367                 tooltip.classed('rightclick', false);
59368             }, minTime);
59369             dispatch$$1.call('click', this, 'right');
59370         }
59371     }
59372
59373
59374     var behavior = function(selection$$1) {
59375         tooltip = selection$$1;
59376         down = {};
59377
59378         select(window)
59379             .on('keydown.intro', keydown)
59380             .on('keyup.intro', keyup)
59381             .on('mousedown.intro', mousedown)
59382             .on('mouseup.intro', mouseup)
59383             .on('contextmenu.intro', contextmenu);
59384     };
59385
59386
59387     behavior.off = function() {
59388         select(window)
59389             .on('keydown.intro', null)
59390             .on('keyup.intro', null)
59391             .on('mousedown.intro', null)
59392             .on('mouseup.intro', null)
59393             .on('contextmenu.intro', null);
59394
59395         tooltip
59396             .classed('leftclick', false)
59397             .classed('rightclick', false);
59398     };
59399
59400     return utilRebind(behavior, dispatch$$1, 'on');
59401 }
59402
59403 function uiIntroNavigation(context, reveal) {
59404     var dispatch$$1 = dispatch('done'),
59405         timeouts = [],
59406         hallId = 'n2061',
59407         townHall = [-85.63591, 41.94285],
59408         springStreetId = 'w397',
59409         springStreetEndId = 'n1834',
59410         springStreet = [-85.63582, 41.94255],
59411         onewayField = context.presets().field('oneway'),
59412         maxspeedField = context.presets().field('maxspeed');
59413
59414
59415     var chapter = {
59416         title: 'intro.navigation.title'
59417     };
59418
59419
59420     function timeout(f, t$$1) {
59421         timeouts.push(window.setTimeout(f, t$$1));
59422     }
59423
59424
59425     function eventCancel() {
59426         event.stopPropagation();
59427         event.preventDefault();
59428     }
59429
59430
59431     function isTownHallSelected() {
59432         var ids = context.selectedIDs();
59433         return ids.length === 1 && ids[0] === hallId;
59434     }
59435
59436
59437     function dragMap() {
59438         context.enter(modeBrowse(context));
59439         context.history().reset('initial');
59440
59441         var msec = transitionTime(townHall, context.map().center());
59442         if (msec) { reveal(null, null, { duration: 0 }); }
59443         context.map().zoom(19).centerEase(townHall, msec);
59444
59445         timeout(function() {
59446             var centerStart = context.map().center();
59447
59448             reveal('#surface', t('intro.navigation.drag'));
59449             context.map().on('drawn.intro', function() {
59450                 reveal('#surface', t('intro.navigation.drag'), { duration: 0 });
59451             });
59452
59453             context.map().on('move.intro', function() {
59454                 var centerNow = context.map().center();
59455                 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
59456                     context.map().on('move.intro', null);
59457                     timeout(function() { continueTo(zoomMap); }, 3000);
59458                 }
59459             });
59460
59461         }, msec + 100);
59462
59463         function continueTo(nextStep) {
59464             context.map().on('move.intro drawn.intro', null);
59465             nextStep();
59466         }
59467     }
59468
59469
59470     function zoomMap() {
59471         var zoomStart = context.map().zoom();
59472
59473         reveal('#surface',
59474             t('intro.navigation.zoom', {
59475                 plus: icon('#icon-plus', 'pre-text'),
59476                 minus: icon('#icon-minus', 'pre-text')
59477             })
59478         );
59479
59480         context.map().on('drawn.intro', function() {
59481             reveal('#surface',
59482                 t('intro.navigation.zoom', {
59483                     plus: icon('#icon-plus', 'pre-text'),
59484                     minus: icon('#icon-minus', 'pre-text')
59485                 }), { duration: 0 }
59486             );
59487         });
59488
59489         context.map().on('move.intro', function() {
59490             if (context.map().zoom() !== zoomStart) {
59491                 context.map().on('move.intro', null);
59492                 timeout(function() { continueTo(features); }, 3000);
59493             }
59494         });
59495
59496         function continueTo(nextStep) {
59497             context.map().on('move.intro drawn.intro', null);
59498             nextStep();
59499         }
59500     }
59501
59502
59503     function features() {
59504         var onClick = function() { continueTo(pointsLinesAreas); };
59505
59506         reveal('#surface', t('intro.navigation.features'),
59507             { buttonText: t('intro.ok'), buttonCallback: onClick }
59508         );
59509
59510         context.map().on('drawn.intro', function() {
59511             reveal('#surface', t('intro.navigation.features'),
59512                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59513             );
59514         });
59515
59516         function continueTo(nextStep) {
59517             context.map().on('drawn.intro', null);
59518             nextStep();
59519         }
59520     }
59521
59522     function pointsLinesAreas() {
59523         var onClick = function() { continueTo(nodesWays); };
59524
59525         reveal('#surface', t('intro.navigation.points_lines_areas'),
59526             { buttonText: t('intro.ok'), buttonCallback: onClick }
59527         );
59528
59529         context.map().on('drawn.intro', function() {
59530             reveal('#surface', t('intro.navigation.points_lines_areas'),
59531                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59532             );
59533         });
59534
59535         function continueTo(nextStep) {
59536             context.map().on('drawn.intro', null);
59537             nextStep();
59538         }
59539     }
59540
59541     function nodesWays() {
59542         var onClick = function() { continueTo(clickTownHall); };
59543
59544         reveal('#surface', t('intro.navigation.nodes_ways'),
59545             { buttonText: t('intro.ok'), buttonCallback: onClick }
59546         );
59547
59548         context.map().on('drawn.intro', function() {
59549             reveal('#surface', t('intro.navigation.nodes_ways'),
59550                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59551             );
59552         });
59553
59554         function continueTo(nextStep) {
59555             context.map().on('drawn.intro', null);
59556             nextStep();
59557         }
59558     }
59559
59560     function clickTownHall() {
59561         context.enter(modeBrowse(context));
59562         context.history().reset('initial');
59563
59564         reveal(null, null, { duration: 0 });
59565         context.map().zoomEase(19, 500);
59566
59567         timeout(function() {
59568             var entity = context.hasEntity(hallId);
59569             if (!entity) return;
59570             context.map().centerEase(entity.loc, 500);
59571
59572             timeout(function() {
59573                 var entity = context.hasEntity(hallId);
59574                 if (!entity) return;
59575                 var box = pointBox(entity.loc, context);
59576                 reveal(box, t('intro.navigation.click_townhall'));
59577
59578                 context.map().on('move.intro drawn.intro', function() {
59579                     var entity = context.hasEntity(hallId);
59580                     if (!entity) return;
59581                     var box = pointBox(entity.loc, context);
59582                     reveal(box, t('intro.navigation.click_townhall'), { duration: 0 });
59583                 });
59584
59585                 context.on('enter.intro', function() {
59586                     if (isTownHallSelected()) continueTo(selectedTownHall);
59587                 });
59588
59589             }, 550);  // after centerEase
59590
59591         }, 550); // after zoomEase
59592
59593         context.history().on('change.intro', function() {
59594             if (!context.hasEntity(hallId)) {
59595                 continueTo(clickTownHall);
59596             }
59597         });
59598
59599         function continueTo(nextStep) {
59600             context.on('enter.intro', null);
59601             context.map().on('move.intro drawn.intro', null);
59602             context.history().on('change.intro', null);
59603             nextStep();
59604         }
59605     }
59606
59607
59608     function selectedTownHall() {
59609         if (!isTownHallSelected()) return clickTownHall();
59610
59611         var entity = context.hasEntity(hallId);
59612         if (!entity) return clickTownHall();
59613
59614         var box = pointBox(entity.loc, context);
59615         var onClick = function() { continueTo(editorTownHall); };
59616
59617         reveal(box, t('intro.navigation.selected_townhall'),
59618             { buttonText: t('intro.ok'), buttonCallback: onClick }
59619         );
59620
59621         context.map().on('move.intro drawn.intro', function() {
59622             var entity = context.hasEntity(hallId);
59623             if (!entity) return;
59624             var box = pointBox(entity.loc, context);
59625             reveal(box, t('intro.navigation.selected_townhall'),
59626                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59627             );
59628         });
59629
59630         context.history().on('change.intro', function() {
59631             if (!context.hasEntity(hallId)) {
59632                 continueTo(clickTownHall);
59633             }
59634         });
59635
59636         function continueTo(nextStep) {
59637             context.map().on('move.intro drawn.intro', null);
59638             context.history().on('change.intro', null);
59639             nextStep();
59640         }
59641     }
59642
59643
59644     function editorTownHall() {
59645         if (!isTownHallSelected()) return clickTownHall();
59646
59647         // disallow scrolling
59648         select('.inspector-wrap').on('wheel.intro', eventCancel);
59649
59650         var onClick = function() { continueTo(presetTownHall); };
59651
59652         reveal('.entity-editor-pane',
59653             t('intro.navigation.editor_townhall'),
59654             { buttonText: t('intro.ok'), buttonCallback: onClick }
59655         );
59656
59657         context.on('exit.intro', function() {
59658             continueTo(clickTownHall);
59659         });
59660
59661         context.history().on('change.intro', function() {
59662             if (!context.hasEntity(hallId)) {
59663                 continueTo(clickTownHall);
59664             }
59665         });
59666
59667         function continueTo(nextStep) {
59668             context.on('exit.intro', null);
59669             context.history().on('change.intro', null);
59670             select('.inspector-wrap').on('wheel.intro', null);
59671             nextStep();
59672         }
59673     }
59674
59675
59676     function presetTownHall() {
59677         if (!isTownHallSelected()) return clickTownHall();
59678
59679         // reset pane, in case user happened to change it..
59680         select('.inspector-wrap .panewrap').style('right', '0%');
59681         // disallow scrolling
59682         select('.inspector-wrap').on('wheel.intro', eventCancel);
59683
59684         // preset match, in case the user happened to change it.
59685         var entity = context.entity(context.selectedIDs()[0]);
59686         var preset = context.presets().match(entity, context.graph());
59687
59688         var onClick = function() { continueTo(fieldsTownHall); };
59689
59690         context.on('exit.intro', function() {
59691             continueTo(clickTownHall);
59692         });
59693
59694         context.history().on('change.intro', function() {
59695             if (!context.hasEntity(hallId)) {
59696                 continueTo(clickTownHall);
59697             }
59698         });
59699
59700         reveal('.inspector-body .preset-list-item.inspector-inner',
59701             t('intro.navigation.preset_townhall', { preset: preset.name() }),
59702             { buttonText: t('intro.ok'), buttonCallback: onClick }
59703         );
59704
59705         function continueTo(nextStep) {
59706             context.on('exit.intro', null);
59707             context.history().on('change.intro', null);
59708             select('.inspector-wrap').on('wheel.intro', null);
59709             nextStep();
59710         }
59711     }
59712
59713
59714     function fieldsTownHall() {
59715         if (!isTownHallSelected()) return clickTownHall();
59716
59717         // reset pane, in case user happened to change it..
59718         select('.inspector-wrap .panewrap').style('right', '0%');
59719         // disallow scrolling
59720         select('.inspector-wrap').on('wheel.intro', eventCancel);
59721
59722         var onClick = function() { continueTo(closeTownHall); };
59723
59724         reveal('.inspector-body .inspector-preset',
59725             t('intro.navigation.fields_townhall'),
59726             { buttonText: t('intro.ok'), buttonCallback: onClick }
59727         );
59728
59729         context.on('exit.intro', function() {
59730             continueTo(clickTownHall);
59731         });
59732
59733         context.history().on('change.intro', function() {
59734             if (!context.hasEntity(hallId)) {
59735                 continueTo(clickTownHall);
59736             }
59737         });
59738
59739         function continueTo(nextStep) {
59740             context.on('exit.intro', null);
59741             context.history().on('change.intro', null);
59742             select('.inspector-wrap').on('wheel.intro', null);
59743             nextStep();
59744         }
59745     }
59746
59747
59748     function closeTownHall() {
59749         if (!isTownHallSelected()) return clickTownHall();
59750
59751         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59752         var href = select(selector$$1).attr('href') || '#icon-close';
59753
59754         reveal('.entity-editor-pane',
59755             t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') })
59756         );
59757
59758         context.on('exit.intro', function() {
59759             continueTo(searchStreet);
59760         });
59761
59762         context.history().on('change.intro', function() {
59763             // update the close icon in the tooltip if the user edits something.
59764             var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59765             var href = select(selector$$1).attr('href') || '#icon-close';
59766
59767             reveal('.entity-editor-pane',
59768                 t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') }),
59769                 { duration: 0 }
59770             );
59771         });
59772
59773         function continueTo(nextStep) {
59774             context.on('exit.intro', null);
59775             context.history().on('change.intro', null);
59776             nextStep();
59777         }
59778     }
59779
59780
59781     function searchStreet() {
59782         context.enter(modeBrowse(context));
59783         context.history().reset('initial');  // ensure spring street exists
59784
59785         var msec = transitionTime(springStreet, context.map().center());
59786         if (msec) { reveal(null, null, { duration: 0 }); }
59787         context.map().zoom(19).centerEase(springStreet, msec);  // ..and user can see it
59788
59789         timeout(function() {
59790             reveal('.search-header input',
59791                 t('intro.navigation.search_street', { name: t('intro.graph.name.spring-street') })
59792             );
59793
59794             select('.search-header input')
59795                 .on('keyup.intro', checkSearchResult);
59796         }, msec + 100);
59797     }
59798
59799
59800     function checkSearchResult() {
59801         var first = select('.feature-list-item:nth-child(0n+2)'),  // skip "No Results" item
59802             firstName = first.select('.entity-name'),
59803             name = t('intro.graph.name.spring-street');
59804
59805         if (!firstName.empty() && firstName.text() === name) {
59806             reveal(first.node(),
59807                 t('intro.navigation.choose_street', { name: name }),
59808                 { duration: 300 }
59809             );
59810
59811             context.on('exit.intro', function() {
59812                 continueTo(selectedStreet);
59813             });
59814
59815             select('.search-header input')
59816                 .on('keydown.intro', eventCancel, true)
59817                 .on('keyup.intro', null);
59818         }
59819
59820         function continueTo(nextStep) {
59821             context.on('exit.intro', null);
59822             select('.search-header input')
59823                 .on('keydown.intro', null)
59824                 .on('keyup.intro', null);
59825             nextStep();
59826         }
59827     }
59828
59829
59830     function selectedStreet() {
59831         if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
59832             return searchStreet();
59833         }
59834
59835         var onClick = function() { continueTo(editorStreet); };
59836         var entity = context.entity(springStreetEndId);
59837         var box = pointBox(entity.loc, context);
59838         box.height = 500;
59839
59840         reveal(box,
59841             t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
59842             { duration: 600, buttonText: t('intro.ok'), buttonCallback: onClick }
59843         );
59844
59845         timeout(function() {
59846             context.map().on('move.intro drawn.intro', function() {
59847                 var entity = context.hasEntity(springStreetEndId);
59848                 if (!entity) return;
59849                 var box = pointBox(entity.loc, context);
59850                 box.height = 500;
59851                 reveal(box,
59852                     t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
59853                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
59854                 );
59855             });
59856         }, 600);  // after reveal.
59857
59858         context.on('enter.intro', function(mode) {
59859             if (!context.hasEntity(springStreetId)) {
59860                 return continueTo(searchStreet);
59861             }
59862             var ids = context.selectedIDs();
59863             if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
59864                 // keep Spring Street selected..
59865                 context.enter(modeSelect(context, [springStreetId]));
59866             }
59867         });
59868
59869         context.history().on('change.intro', function() {
59870             if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
59871                 timeout(function() {
59872                     continueTo(searchStreet);
59873                 }, 300);  // after any transition (e.g. if user deleted intersection)
59874             }
59875         });
59876
59877         function continueTo(nextStep) {
59878             context.map().on('move.intro drawn.intro', null);
59879             context.on('enter.intro', null);
59880             context.history().on('change.intro', null);
59881             nextStep();
59882         }
59883     }
59884
59885
59886     function editorStreet() {
59887         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59888         var href = select(selector$$1).attr('href') || '#icon-close';
59889
59890         reveal('.entity-editor-pane',
59891             t('intro.navigation.editor_street', {
59892                 button: icon(href, 'pre-text'),
59893                 field1: onewayField.label(),
59894                 field2: maxspeedField.label()
59895             })
59896         );
59897
59898         context.on('exit.intro', function() {
59899             continueTo(play);
59900         });
59901
59902         context.history().on('change.intro', function() {
59903             // update the close icon in the tooltip if the user edits something.
59904             var selector$$1 = '.entity-editor-pane button.preset-close svg use';
59905             var href = select(selector$$1).attr('href') || '#icon-close';
59906
59907             reveal('.entity-editor-pane',
59908                 t('intro.navigation.editor_street', {
59909                     button: icon(href, 'pre-text'),
59910                     field1: onewayField.label().toLowerCase(),
59911                     field2: maxspeedField.label().toLowerCase()
59912                 }), { duration: 0 }
59913             );
59914         });
59915
59916         function continueTo(nextStep) {
59917             context.on('exit.intro', null);
59918             context.history().on('change.intro', null);
59919             nextStep();
59920         }
59921     }
59922
59923
59924     function play() {
59925         dispatch$$1.call('done');
59926         reveal('#id-container',
59927             t('intro.navigation.play', { next: t('intro.points.title') }), {
59928                 tooltipBox: '.intro-nav-wrap .chapter-point',
59929                 buttonText: t('intro.ok'),
59930                 buttonCallback: function() { reveal('#id-container'); }
59931             }
59932         );
59933     }
59934
59935
59936     chapter.enter = function() {
59937         dragMap();
59938     };
59939
59940
59941     chapter.exit = function() {
59942         timeouts.forEach(window.clearTimeout);
59943         context.on('enter.intro exit.intro', null);
59944         context.map().on('move.intro drawn.intro', null);
59945         context.history().on('change.intro', null);
59946         select('.inspector-wrap').on('wheel.intro', null);
59947         select('.search-header input').on('keydown.intro keyup.intro', null);
59948     };
59949
59950
59951     chapter.restart = function() {
59952         chapter.exit();
59953         chapter.enter();
59954     };
59955
59956
59957     return utilRebind(chapter, dispatch$$1, 'on');
59958 }
59959
59960 function uiIntroPoint(context, reveal) {
59961     var dispatch$$1 = dispatch('done'),
59962         timeouts = [],
59963         intersection = [-85.63279, 41.94394],
59964         building = [-85.632422, 41.944045],
59965         cafePreset = context.presets().item('amenity/cafe'),
59966         pointId = null;
59967
59968
59969     var chapter = {
59970         title: 'intro.points.title'
59971     };
59972
59973
59974     function timeout(f, t$$1) {
59975         timeouts.push(window.setTimeout(f, t$$1));
59976     }
59977
59978
59979     function revealEditMenu(loc, text$$1, options) {
59980         var rect = context.surfaceRect();
59981         var point = context.curtainProjection(loc);
59982         var pad = 40;
59983         var width = 250 + (2 * pad);
59984         var height = 250;
59985         var startX = rect.left + point[0];
59986         var left = (textDirection === 'rtl') ? (startX - width + pad) : (startX - pad);
59987         var box = {
59988             left: left,
59989             top: point[1] + rect.top - 60,
59990             width: width,
59991             height: height
59992         };
59993         reveal(box, text$$1, options);
59994     }
59995
59996
59997     function eventCancel() {
59998         event.stopPropagation();
59999         event.preventDefault();
60000     }
60001
60002
60003     function addPoint() {
60004         context.enter(modeBrowse(context));
60005         context.history().reset('initial');
60006
60007         var msec = transitionTime(intersection, context.map().center());
60008         if (msec) { reveal(null, null, { duration: 0 }); }
60009         context.map().zoom(19).centerEase(intersection, msec);
60010
60011         timeout(function() {
60012             var tooltip = reveal('button.add-point',
60013                 t('intro.points.add_point', { button: icon('#icon-point', 'pre-text') }));
60014
60015             pointId = null;
60016
60017             tooltip.selectAll('.tooltip-inner')
60018                 .insert('svg', 'span')
60019                 .attr('class', 'tooltip-illustration')
60020                 .append('use')
60021                 .attr('xlink:href', '#poi-images');
60022
60023             context.on('enter.intro', function(mode) {
60024                 if (mode.id !== 'add-point') return;
60025                 continueTo(placePoint);
60026             });
60027         }, msec + 100);
60028
60029         function continueTo(nextStep) {
60030             context.on('enter.intro', null);
60031             nextStep();
60032         }
60033     }
60034
60035
60036     function placePoint() {
60037         if (context.mode().id !== 'add-point') {
60038             return chapter.restart();
60039         }
60040
60041         var pointBox$$1 = pad$1(building, 150, context);
60042         reveal(pointBox$$1, t('intro.points.place_point'));
60043
60044         context.map().on('move.intro drawn.intro', function() {
60045             pointBox$$1 = pad$1(building, 150, context);
60046             reveal(pointBox$$1, t('intro.points.place_point'), { duration: 0 });
60047         });
60048
60049         context.on('enter.intro', function(mode) {
60050             if (mode.id !== 'select') return chapter.restart();
60051             pointId = context.mode().selectedIDs()[0];
60052             continueTo(searchPreset);
60053         });
60054
60055         function continueTo(nextStep) {
60056             context.map().on('move.intro drawn.intro', null);
60057             context.on('enter.intro', null);
60058             nextStep();
60059         }
60060     }
60061
60062
60063     function searchPreset() {
60064         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
60065             return addPoint();
60066         }
60067
60068         // disallow scrolling
60069         select('.inspector-wrap').on('wheel.intro', eventCancel);
60070
60071         select('.preset-search-input')
60072             .on('keydown.intro', null)
60073             .on('keyup.intro', checkPresetSearch);
60074
60075         reveal('.preset-search-input',
60076             t('intro.points.search_cafe', { preset: cafePreset.name() })
60077         );
60078
60079         context.on('enter.intro', function(mode) {
60080             if (!pointId || !context.hasEntity(pointId)) {
60081                 return continueTo(addPoint);
60082             }
60083
60084             var ids = context.selectedIDs();
60085             if (mode.id !== 'select' || !ids.length || ids[0] !== pointId) {
60086                 // keep the user's point selected..
60087                 context.enter(modeSelect(context, [pointId]));
60088
60089                 // disallow scrolling
60090                 select('.inspector-wrap').on('wheel.intro', eventCancel);
60091
60092                 select('.preset-search-input')
60093                     .on('keydown.intro', null)
60094                     .on('keyup.intro', checkPresetSearch);
60095
60096                 reveal('.preset-search-input',
60097                     t('intro.points.search_cafe', { preset: cafePreset.name() })
60098                 );
60099
60100                 context.history().on('change.intro', null);
60101             }
60102         });
60103
60104
60105         function checkPresetSearch() {
60106             var first = select('.preset-list-item:first-child');
60107
60108             if (first.classed('preset-amenity-cafe')) {
60109                 select('.preset-search-input')
60110                     .on('keydown.intro', eventCancel, true)
60111                     .on('keyup.intro', null);
60112
60113                 reveal(first.select('.preset-list-button').node(),
60114                     t('intro.points.choose_cafe', { preset: cafePreset.name() }),
60115                     { duration: 300 }
60116                 );
60117
60118                 context.history().on('change.intro', function() {
60119                     continueTo(aboutFeatureEditor);
60120                 });
60121             }
60122         }
60123
60124         function continueTo(nextStep) {
60125             context.on('enter.intro', null);
60126             context.history().on('change.intro', null);
60127             select('.inspector-wrap').on('wheel.intro', null);
60128             select('.preset-search-input').on('keydown.intro keyup.intro', null);
60129             nextStep();
60130         }
60131     }
60132
60133
60134     function aboutFeatureEditor() {
60135         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
60136             return addPoint();
60137         }
60138
60139         timeout(function() {
60140             reveal('.entity-editor-pane', t('intro.points.feature_editor'), {
60141                 tooltipClass: 'intro-points-describe',
60142                 buttonText: t('intro.ok'),
60143                 buttonCallback: function() { continueTo(addName); }
60144             });
60145         }, 400);
60146
60147         context.on('exit.intro', function() {
60148             // if user leaves select mode here, just continue with the tutorial.
60149             continueTo(reselectPoint);
60150         });
60151
60152         function continueTo(nextStep) {
60153             context.on('exit.intro', null);
60154             nextStep();
60155         }
60156     }
60157
60158
60159     function addName() {
60160         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
60161             return addPoint();
60162         }
60163
60164         // reset pane, in case user happened to change it..
60165         select('.inspector-wrap .panewrap').style('right', '0%');
60166
60167         timeout(function() {
60168             // It's possible for the user to add a name in a previous step..
60169             // If so, don't tell them to add the name in this step.
60170             // Give them an OK button instead.
60171             var entity = context.entity(pointId);
60172             if (entity.tags.name) {
60173                 var tooltip = reveal('.entity-editor-pane', t('intro.points.add_name'), {
60174                     tooltipClass: 'intro-points-describe',
60175                     buttonText: t('intro.ok'),
60176                     buttonCallback: function() { continueTo(addCloseEditor); }
60177                 });
60178                 tooltip.select('.instruction').style('display', 'none');
60179
60180             } else {
60181                 reveal('.entity-editor-pane', t('intro.points.add_name'),
60182                     { tooltipClass: 'intro-points-describe' }
60183                 );
60184             }
60185         }, 400);
60186
60187         context.history().on('change.intro', function() {
60188             continueTo(addCloseEditor);
60189         });
60190
60191         context.on('exit.intro', function() {
60192             // if user leaves select mode here, just continue with the tutorial.
60193             continueTo(reselectPoint);
60194         });
60195
60196         function continueTo(nextStep) {
60197             context.on('exit.intro', null);
60198             context.history().on('change.intro', null);
60199             nextStep();
60200         }
60201     }
60202
60203
60204     function addCloseEditor() {
60205         // reset pane, in case user happened to change it..
60206         select('.inspector-wrap .panewrap').style('right', '0%');
60207
60208         var selector$$1 = '.entity-editor-pane button.preset-close svg use';
60209         var href = select(selector$$1).attr('href') || '#icon-close';
60210
60211         context.on('exit.intro', function() {
60212             continueTo(reselectPoint);
60213         });
60214
60215         reveal('.entity-editor-pane',
60216             t('intro.points.add_close', { button: icon(href, 'pre-text') })
60217         );
60218
60219         function continueTo(nextStep) {
60220             context.on('exit.intro', null);
60221             nextStep();
60222         }
60223     }
60224
60225
60226     function reselectPoint() {
60227         if (!pointId) return chapter.restart();
60228         var entity = context.hasEntity(pointId);
60229         if (!entity) return chapter.restart();
60230
60231         // make sure it's still a cafe, in case user somehow changed it..
60232         var oldPreset = context.presets().match(entity, context.graph());
60233         context.replace(actionChangePreset(pointId, oldPreset, cafePreset));
60234
60235         context.enter(modeBrowse(context));
60236
60237         var msec = transitionTime(entity.loc, context.map().center());
60238         if (msec) { reveal(null, null, { duration: 0 }); }
60239         context.map().centerEase(entity.loc, msec);
60240
60241         timeout(function() {
60242             var box = pointBox(entity.loc, context);
60243             reveal(box, t('intro.points.reselect'), { duration: 600 });
60244
60245             timeout(function() {
60246                 context.map().on('move.intro drawn.intro', function() {
60247                     var entity = context.hasEntity(pointId);
60248                     if (!entity) return chapter.restart();
60249                     var box = pointBox(entity.loc, context);
60250                     reveal(box, t('intro.points.reselect'), { duration: 0 });
60251                 });
60252             }, 600); // after reveal..
60253
60254             context.on('enter.intro', function(mode) {
60255                 if (mode.id !== 'select') return;
60256                 continueTo(updatePoint);
60257             });
60258
60259         }, msec + 100);
60260
60261         function continueTo(nextStep) {
60262             context.map().on('move.intro drawn.intro', null);
60263             context.on('enter.intro', null);
60264             nextStep();
60265         }
60266     }
60267
60268
60269     function updatePoint() {
60270         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
60271             return continueTo(reselectPoint);
60272         }
60273
60274         // reset pane, in case user happened to untag the point..
60275         select('.inspector-wrap .panewrap').style('right', '0%');
60276
60277         context.on('exit.intro', function() {
60278             continueTo(reselectPoint);
60279         });
60280
60281         context.history().on('change.intro', function() {
60282             continueTo(updateCloseEditor);
60283         });
60284
60285         timeout(function() {
60286             reveal('.entity-editor-pane', t('intro.points.update'),
60287                 { tooltipClass: 'intro-points-describe' }
60288             );
60289         }, 400);
60290
60291         function continueTo(nextStep) {
60292             context.on('exit.intro', null);
60293             context.history().on('change.intro', null);
60294             nextStep();
60295         }
60296     }
60297
60298
60299     function updateCloseEditor() {
60300         if (context.mode().id !== 'select' || !pointId || !context.hasEntity(pointId)) {
60301             return continueTo(reselectPoint);
60302         }
60303
60304         // reset pane, in case user happened to change it..
60305         select('.inspector-wrap .panewrap').style('right', '0%');
60306
60307         context.on('exit.intro', function() {
60308             continueTo(rightClickPoint);
60309         });
60310
60311         timeout(function() {
60312             reveal('.entity-editor-pane',
60313                 t('intro.points.update_close', { button: icon('#icon-apply', 'pre-text') })
60314             );
60315         }, 500);
60316
60317         function continueTo(nextStep) {
60318             context.on('exit.intro', null);
60319             nextStep();
60320         }
60321     }
60322
60323
60324     function rightClickPoint() {
60325         if (!pointId) return chapter.restart();
60326         var entity = context.hasEntity(pointId);
60327         if (!entity) return chapter.restart();
60328
60329         context.enter(modeBrowse(context));
60330
60331         var box = pointBox(entity.loc, context);
60332         reveal(box, t('intro.points.rightclick'), { duration: 600 });
60333
60334         timeout(function() {
60335             context.map().on('move.intro drawn.intro', function() {
60336                 var entity = context.hasEntity(pointId);
60337                 if (!entity) return chapter.restart();
60338                 var box = pointBox(entity.loc, context);
60339                 reveal(box, t('intro.points.rightclick'), { duration: 0 });
60340             });
60341         }, 600); // after reveal
60342
60343         context.on('enter.intro', function(mode) {
60344             if (mode.id !== 'select') return;
60345             var ids = context.selectedIDs();
60346             if (ids.length !== 1 || ids[0] !== pointId) return;
60347
60348             timeout(function() {
60349                 var node = selectMenuItem('delete').node();
60350                 if (!node) return;
60351                 continueTo(enterDelete);
60352             }, 300);  // after menu visible
60353         });
60354
60355         function continueTo(nextStep) {
60356             context.on('enter.intro', null);
60357             context.map().on('move.intro drawn.intro', null);
60358             nextStep();
60359         }
60360     }
60361
60362
60363     function enterDelete() {
60364         if (!pointId) return chapter.restart();
60365         var entity = context.hasEntity(pointId);
60366         if (!entity) return chapter.restart();
60367
60368         var node = selectMenuItem('delete').node();
60369         if (!node) { return continueTo(rightClickPoint); }
60370
60371         revealEditMenu(entity.loc,
60372             t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') })
60373         );
60374
60375         timeout(function() {
60376             context.map().on('move.intro drawn.intro', function() {
60377                 revealEditMenu(entity.loc,
60378                     t('intro.points.delete', { button: icon('#operation-delete', 'pre-text') }),
60379                     { duration: 0}
60380                 );
60381             });
60382         }, 300); // after menu visible
60383
60384         context.on('exit.intro', function() {
60385             if (!pointId) return chapter.restart();
60386             var entity = context.hasEntity(pointId);
60387             if (entity) return continueTo(rightClickPoint);  // point still exists
60388         });
60389
60390         context.history().on('change.intro', function(changed) {
60391             if (changed.deleted().length) {
60392                 continueTo(undo);
60393             }
60394         });
60395
60396         function continueTo(nextStep) {
60397             context.map().on('move.intro drawn.intro', null);
60398             context.history().on('change.intro', null);
60399             context.on('exit.intro', null);
60400             nextStep();
60401         }
60402     }
60403
60404
60405     function undo() {
60406         context.history().on('change.intro', function() {
60407             continueTo(play);
60408         });
60409
60410         var iconName = '#icon-' + (textDirection === 'rtl' ? 'redo' : 'undo');
60411         reveal('#bar button.undo-button',
60412             t('intro.points.undo', { button: icon(iconName, 'pre-text') })
60413         );
60414
60415         function continueTo(nextStep) {
60416             context.history().on('change.intro', null);
60417             nextStep();
60418         }
60419     }
60420
60421
60422     function play() {
60423         dispatch$$1.call('done');
60424         reveal('#id-container',
60425             t('intro.points.play', { next: t('intro.areas.title') }), {
60426                 tooltipBox: '.intro-nav-wrap .chapter-area',
60427                 buttonText: t('intro.ok'),
60428                 buttonCallback: function() { reveal('#id-container'); }
60429             }
60430         );
60431     }
60432
60433
60434     chapter.enter = function() {
60435         addPoint();
60436     };
60437
60438
60439     chapter.exit = function() {
60440         timeouts.forEach(window.clearTimeout);
60441         context.on('enter.intro exit.intro', null);
60442         context.map().on('move.intro drawn.intro', null);
60443         context.history().on('change.intro', null);
60444         select('.inspector-wrap').on('wheel.intro', eventCancel);
60445         select('.preset-search-input').on('keydown.intro keyup.intro', null);
60446     };
60447
60448
60449     chapter.restart = function() {
60450         chapter.exit();
60451         chapter.enter();
60452     };
60453
60454
60455     return utilRebind(chapter, dispatch$$1, 'on');
60456 }
60457
60458 function uiIntroArea(context, reveal) {
60459     var dispatch$$1 = dispatch('done'),
60460         playground = [-85.63552, 41.94159],
60461         playgroundPreset = context.presets().item('leisure/playground'),
60462         descriptionField = context.presets().field('description'),
60463         timeouts = [],
60464         areaId;
60465
60466
60467     var chapter = {
60468         title: 'intro.areas.title'
60469     };
60470
60471
60472     function timeout(f, t$$1) {
60473         timeouts.push(window.setTimeout(f, t$$1));
60474     }
60475
60476
60477     function eventCancel() {
60478         event.stopPropagation();
60479         event.preventDefault();
60480     }
60481
60482
60483     function revealPlayground(center, text$$1, options) {
60484         var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
60485         var box = pad$1(center, padding, context);
60486         reveal(box, text$$1, options);
60487     }
60488
60489
60490     function addArea() {
60491         context.enter(modeBrowse(context));
60492         context.history().reset('initial');
60493         areaId = null;
60494
60495         var msec = transitionTime(playground, context.map().center());
60496         if (msec) { reveal(null, null, { duration: 0 }); }
60497         context.map().zoom(19).centerEase(playground, msec);
60498
60499         timeout(function() {
60500             var tooltip = reveal('button.add-area',
60501                 t('intro.areas.add_playground', { button: icon('#icon-area', 'pre-text') }));
60502
60503             tooltip.selectAll('.tooltip-inner')
60504                 .insert('svg', 'span')
60505                 .attr('class', 'tooltip-illustration')
60506                 .append('use')
60507                 .attr('xlink:href', '#landuse-images');
60508
60509             context.on('enter.intro', function(mode) {
60510                 if (mode.id !== 'add-area') return;
60511                 continueTo(startPlayground);
60512             });
60513         }, msec + 100);
60514
60515         function continueTo(nextStep) {
60516             context.on('enter.intro', null);
60517             nextStep();
60518         }
60519     }
60520
60521
60522     function startPlayground() {
60523         if (context.mode().id !== 'add-area') {
60524             return chapter.restart();
60525         }
60526
60527         areaId = null;
60528         context.map().zoomEase(19.5, 500);
60529
60530         timeout(function() {
60531             revealPlayground(playground,
60532                 t('intro.areas.start_playground'), { duration: 250 }
60533             );
60534
60535             timeout(function() {
60536                 context.map().on('move.intro drawn.intro', function() {
60537                     revealPlayground(playground,
60538                         t('intro.areas.start_playground'), { duration: 0 }
60539                     );
60540                 });
60541                 context.on('enter.intro', function(mode) {
60542                     if (mode.id !== 'draw-area') return chapter.restart();
60543                     continueTo(continuePlayground);
60544                 });
60545             }, 250);  // after reveal
60546
60547         }, 550);  // after easing
60548
60549         function continueTo(nextStep) {
60550             context.map().on('move.intro drawn.intro', null);
60551             context.on('enter.intro', null);
60552             nextStep();
60553         }
60554     }
60555
60556
60557     function continuePlayground() {
60558         if (context.mode().id !== 'draw-area') {
60559             return chapter.restart();
60560         }
60561
60562         areaId = null;
60563         revealPlayground(playground,
60564             t('intro.areas.continue_playground'), { duration: 250 }
60565         );
60566
60567         timeout(function() {
60568             context.map().on('move.intro drawn.intro', function() {
60569                 revealPlayground(playground,
60570                     t('intro.areas.continue_playground'), { duration: 0 }
60571                 );
60572             });
60573         }, 250);  // after reveal
60574
60575         context.on('enter.intro', function(mode) {
60576             if (mode.id === 'draw-area') {
60577                 var entity = context.hasEntity(context.selectedIDs()[0]);
60578                 if (entity && entity.nodes.length >= 6) {
60579                     return continueTo(finishPlayground);
60580                 } else {
60581                     return;
60582                 }
60583             } else if (mode.id === 'select') {
60584                 areaId = context.selectedIDs()[0];
60585                 return continueTo(searchPresets);
60586             } else {
60587                 return chapter.restart();
60588             }
60589         });
60590
60591         function continueTo(nextStep) {
60592             context.map().on('move.intro drawn.intro', null);
60593             context.on('enter.intro', null);
60594             nextStep();
60595         }
60596     }
60597
60598
60599     function finishPlayground() {
60600         if (context.mode().id !== 'draw-area') {
60601             return chapter.restart();
60602         }
60603
60604         areaId = null;
60605         revealPlayground(playground,
60606             t('intro.areas.finish_playground'), { duration: 250 }
60607         );
60608
60609         timeout(function() {
60610             context.map().on('move.intro drawn.intro', function() {
60611                 revealPlayground(playground,
60612                     t('intro.areas.finish_playground'), { duration: 0 }
60613                 );
60614             });
60615         }, 250);  // after reveal
60616
60617         context.on('enter.intro', function(mode) {
60618             if (mode.id === 'draw-area') {
60619                 return;
60620             } else if (mode.id === 'select') {
60621                 areaId = context.selectedIDs()[0];
60622                 return continueTo(searchPresets);
60623             } else {
60624                 return chapter.restart();
60625             }
60626         });
60627
60628         function continueTo(nextStep) {
60629             context.map().on('move.intro drawn.intro', null);
60630             context.on('enter.intro', null);
60631             nextStep();
60632         }
60633     }
60634
60635
60636     function searchPresets() {
60637         if (!areaId || !context.hasEntity(areaId)) {
60638             return addArea();
60639         }
60640         var ids = context.selectedIDs();
60641         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60642             context.enter(modeSelect(context, [areaId]));
60643         }
60644
60645         // disallow scrolling
60646         select('.inspector-wrap').on('wheel.intro', eventCancel);
60647
60648         timeout(function() {
60649             // reset pane, in case user somehow happened to change it..
60650             select('.inspector-wrap .panewrap').style('right', '-100%');
60651
60652             select('.preset-search-input')
60653                 .on('keydown.intro', null)
60654                 .on('keyup.intro', checkPresetSearch);
60655
60656             reveal('.preset-search-input',
60657                 t('intro.areas.search_playground', { preset: playgroundPreset.name() })
60658             );
60659         }, 400);  // after preset list pane visible..
60660
60661         context.on('enter.intro', function(mode) {
60662             if (!areaId || !context.hasEntity(areaId)) {
60663                 return continueTo(addArea);
60664             }
60665
60666             var ids = context.selectedIDs();
60667             if (mode.id !== 'select' || !ids.length || ids[0] !== areaId) {
60668                 // keep the user's area selected..
60669                 context.enter(modeSelect(context, [areaId]));
60670
60671                 // reset pane, in case user somehow happened to change it..
60672                 select('.inspector-wrap .panewrap').style('right', '-100%');
60673                 // disallow scrolling
60674                 select('.inspector-wrap').on('wheel.intro', eventCancel);
60675
60676                 select('.preset-search-input')
60677                     .on('keydown.intro', null)
60678                     .on('keyup.intro', checkPresetSearch);
60679
60680                 reveal('.preset-search-input',
60681                     t('intro.areas.search_playground', { preset: playgroundPreset.name() })
60682                 );
60683
60684                 context.history().on('change.intro', null);
60685             }
60686         });
60687
60688         function checkPresetSearch() {
60689             var first = select('.preset-list-item:first-child');
60690
60691             if (first.classed('preset-leisure-playground')) {
60692                 reveal(first.select('.preset-list-button').node(),
60693                     t('intro.areas.choose_playground', { preset: playgroundPreset.name() }),
60694                     { duration: 300 }
60695                 );
60696
60697                 select('.preset-search-input')
60698                     .on('keydown.intro', eventCancel, true)
60699                     .on('keyup.intro', null);
60700
60701                 context.history().on('change.intro', function() {
60702                     continueTo(clickAddField);
60703                 });
60704             }
60705         }
60706
60707         function continueTo(nextStep) {
60708             select('.inspector-wrap').on('wheel.intro', null);
60709             context.on('enter.intro', null);
60710             context.history().on('change.intro', null);
60711             select('.preset-search-input').on('keydown.intro keyup.intro', null);
60712             nextStep();
60713         }
60714     }
60715
60716
60717     function clickAddField() {
60718         if (!areaId || !context.hasEntity(areaId)) {
60719             return addArea();
60720         }
60721         var ids = context.selectedIDs();
60722         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60723             return searchPresets();
60724         }
60725
60726         if (!select('.form-field-description').empty()) {
60727             return continueTo(describePlayground);
60728         }
60729
60730         // disallow scrolling
60731         select('.inspector-wrap').on('wheel.intro', eventCancel);
60732
60733         timeout(function() {
60734             // reset pane, in case user somehow happened to change it..
60735             select('.inspector-wrap .panewrap').style('right', '0%');
60736
60737             // It's possible for the user to add a description in a previous step..
60738             // If they did this already, just continue to next step.
60739             var entity = context.entity(areaId);
60740             if (entity.tags.description) {
60741                 return continueTo(play);
60742             }
60743
60744             reveal('.more-fields .combobox-input',
60745                 t('intro.areas.add_field'),
60746                 { duration: 300 }
60747             );
60748
60749             select('.more-fields .combobox-input')
60750                 .on('click.intro', function() {
60751                     continueTo(chooseDescriptionField);
60752                 });
60753         }, 400);  // after editor pane visible
60754
60755         context.on('exit.intro', function() {
60756             return continueTo(searchPresets);
60757         });
60758
60759         function continueTo(nextStep) {
60760             select('.inspector-wrap').on('wheel.intro', null);
60761             select('.more-fields .combobox-input').on('click.intro', null);
60762             context.on('exit.intro', null);
60763             nextStep();
60764         }
60765     }
60766
60767
60768     function chooseDescriptionField() {
60769         if (!areaId || !context.hasEntity(areaId)) {
60770             return addArea();
60771         }
60772         var ids = context.selectedIDs();
60773         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60774             return searchPresets();
60775         }
60776
60777         if (!select('.form-field-description').empty()) {
60778             return continueTo(describePlayground);
60779         }
60780
60781         // Make sure combobox is ready..
60782         if (select('div.combobox').empty()) {
60783             return continueTo(clickAddField);
60784         }
60785         // Watch for the combobox to go away..
60786         var watcher;
60787         watcher = window.setInterval(function() {
60788             if (select('div.combobox').empty()) {
60789                 window.clearInterval(watcher);
60790                 timeout(function() {
60791                     if (select('.form-field-description').empty()) {
60792                         continueTo(retryChooseDescription);
60793                     } else {
60794                         continueTo(describePlayground);
60795                     }
60796                 }, 300);  // after description field added.
60797             }
60798         }, 300);
60799
60800         reveal('div.combobox',
60801             t('intro.areas.choose_field', { field: descriptionField.label() }),
60802             { duration: 300 }
60803         );
60804
60805         context.on('exit.intro', function() {
60806             return continueTo(searchPresets);
60807         });
60808
60809         function continueTo(nextStep) {
60810             if (watcher) window.clearInterval(watcher);
60811             context.on('exit.intro', null);
60812             nextStep();
60813         }
60814     }
60815
60816
60817     function describePlayground() {
60818         if (!areaId || !context.hasEntity(areaId)) {
60819             return addArea();
60820         }
60821         var ids = context.selectedIDs();
60822         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60823             return searchPresets();
60824         }
60825
60826         // reset pane, in case user happened to change it..
60827         select('.inspector-wrap .panewrap').style('right', '0%');
60828
60829         if (select('.form-field-description').empty()) {
60830             return continueTo(retryChooseDescription);
60831         }
60832
60833         context.on('exit.intro', function() {
60834             continueTo(play);
60835         });
60836
60837         reveal('.entity-editor-pane',
60838             t('intro.areas.describe_playground', { button: icon('#icon-apply', 'pre-text') }),
60839             { duration: 300 }
60840         );
60841
60842         function continueTo(nextStep) {
60843             context.on('exit.intro', null);
60844             nextStep();
60845         }
60846     }
60847
60848
60849     function retryChooseDescription() {
60850         if (!areaId || !context.hasEntity(areaId)) {
60851             return addArea();
60852         }
60853         var ids = context.selectedIDs();
60854         if (context.mode().id !== 'select' || !ids.length || ids[0] !== areaId) {
60855             return searchPresets();
60856         }
60857
60858         // reset pane, in case user happened to change it..
60859         select('.inspector-wrap .panewrap').style('right', '0%');
60860
60861         reveal('.entity-editor-pane',
60862             t('intro.areas.retry_add_field', { field: descriptionField.label() }), {
60863             buttonText: t('intro.ok'),
60864             buttonCallback: function() { continueTo(clickAddField); }
60865         });
60866
60867         context.on('exit.intro', function() {
60868             return continueTo(searchPresets);
60869         });
60870
60871         function continueTo(nextStep) {
60872             context.on('exit.intro', null);
60873             nextStep();
60874         }
60875     }
60876
60877
60878     function play() {
60879         dispatch$$1.call('done');
60880         reveal('#id-container',
60881             t('intro.areas.play', { next: t('intro.lines.title') }), {
60882                 tooltipBox: '.intro-nav-wrap .chapter-line',
60883                 buttonText: t('intro.ok'),
60884                 buttonCallback: function() { reveal('#id-container'); }
60885             }
60886         );
60887     }
60888
60889
60890     chapter.enter = function() {
60891         addArea();
60892     };
60893
60894
60895     chapter.exit = function() {
60896         timeouts.forEach(window.clearTimeout);
60897         context.on('enter.intro exit.intro', null);
60898         context.map().on('move.intro drawn.intro', null);
60899         context.history().on('change.intro', null);
60900         select('.inspector-wrap').on('wheel.intro', null);
60901         select('.preset-search-input').on('keydown.intro keyup.intro', null);
60902         select('.more-fields .combobox-input').on('click.intro', null);
60903     };
60904
60905
60906     chapter.restart = function() {
60907         chapter.exit();
60908         chapter.enter();
60909     };
60910
60911
60912     return utilRebind(chapter, dispatch$$1, 'on');
60913 }
60914
60915 function uiIntroLine(context, reveal) {
60916     var dispatch$$1 = dispatch('done'),
60917         timeouts = [],
60918         tulipRoadId = null,
60919         flowerRoadId = 'w646',
60920         tulipRoadStart = [-85.6297754121684, 41.95805253325314],
60921         tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204],
60922         tulipRoadIntersection = [-85.62974496187628, 41.95742515554585],
60923         roadCategory = context.presets().item('category-road'),
60924         residentialPreset = context.presets().item('highway/residential'),
60925         woodRoadId = 'w525',
60926         woodRoadEndId = 'n2862',
60927         woodRoadAddNode = [-85.62390110349587, 41.95397111462291],
60928         woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487],
60929         woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872],
60930         washingtonStreetId = 'w522',
60931         twelfthAvenueId = 'w1',
60932         eleventhAvenueEndId = 'n3550',
60933         twelfthAvenueEndId = 'n5',
60934         washingtonSegmentId = null,
60935         eleventhAvenueEnd = context.entity(eleventhAvenueEndId).loc,
60936         twelfthAvenueEnd = context.entity(twelfthAvenueEndId).loc,
60937         deleteLinesLoc = [-85.6219395542764, 41.95228033922477],
60938         twelfthAvenue = [-85.62219310052491, 41.952505413152956];
60939
60940
60941     var chapter = {
60942         title: 'intro.lines.title'
60943     };
60944
60945
60946     function timeout(f, t$$1) {
60947         timeouts.push(window.setTimeout(f, t$$1));
60948     }
60949
60950
60951     function eventCancel() {
60952         event.stopPropagation();
60953         event.preventDefault();
60954     }
60955
60956
60957     function revealEditMenu(loc, text$$1, options) {
60958         var rect = context.surfaceRect();
60959         var point = context.curtainProjection(loc);
60960         var pad = 40;
60961         var width = 250 + (2 * pad);
60962         var height = 350;
60963         var startX = rect.left + point[0];
60964         var left = (textDirection === 'rtl') ? (startX - width + pad) : (startX - pad);
60965         var box = {
60966             left: left,
60967             top: point[1] + rect.top - 60,
60968             width: width,
60969             height: height
60970         };
60971         reveal(box, text$$1, options);
60972     }
60973
60974
60975     function addLine() {
60976         context.enter(modeBrowse(context));
60977         context.history().reset('initial');
60978
60979         var msec = transitionTime(tulipRoadStart, context.map().center());
60980         if (msec) { reveal(null, null, { duration: 0 }); }
60981         context.map().zoom(18.5).centerEase(tulipRoadStart, msec);
60982
60983         timeout(function() {
60984             var tooltip = reveal('button.add-line',
60985                 t('intro.lines.add_line', { button: icon('#icon-line', 'pre-text') }));
60986
60987             tooltip.selectAll('.tooltip-inner')
60988                 .insert('svg', 'span')
60989                 .attr('class', 'tooltip-illustration')
60990                 .append('use')
60991                 .attr('xlink:href', '#feature-images');
60992
60993             context.on('enter.intro', function(mode) {
60994                 if (mode.id !== 'add-line') return;
60995                 continueTo(startLine);
60996             });
60997         }, msec + 100);
60998
60999         function continueTo(nextStep) {
61000             context.on('enter.intro', null);
61001             nextStep();
61002         }
61003     }
61004
61005
61006     function startLine() {
61007         if (context.mode().id !== 'add-line') {
61008             return chapter.restart();
61009         }
61010
61011         tulipRoadId = null;
61012
61013         var padding = 70 * Math.pow(2, context.map().zoom() - 18);
61014         var box = pad$1(tulipRoadStart, padding, context);
61015         box.height = box.height + 100;
61016         reveal(box, t('intro.lines.start_line'));
61017
61018         context.map().on('move.intro drawn.intro', function() {
61019             padding = 70 * Math.pow(2, context.map().zoom() - 18);
61020             box = pad$1(tulipRoadStart, padding, context);
61021             box.height = box.height + 100;
61022             reveal(box, t('intro.lines.start_line'), { duration: 0 });
61023         });
61024
61025         context.on('enter.intro', function(mode) {
61026             if (mode.id !== 'draw-line') return chapter.restart();
61027             continueTo(drawLine);
61028         });
61029
61030         function continueTo(nextStep) {
61031             context.map().on('move.intro drawn.intro', null);
61032             context.on('enter.intro', null);
61033             nextStep();
61034         }
61035     }
61036
61037
61038     function drawLine() {
61039         if (context.mode().id !== 'draw-line') {
61040             return chapter.restart();
61041         }
61042
61043         tulipRoadId = context.mode().selectedIDs()[0];
61044         context.map().centerEase(tulipRoadMidpoint, 500);
61045
61046         timeout(function() {
61047             var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
61048             var box = pad$1(tulipRoadMidpoint, padding, context);
61049             box.height = box.height * 2;
61050             reveal(box,
61051                 t('intro.lines.intersect', { name: t('intro.graph.name.flower-street') })
61052             );
61053
61054             context.map().on('move.intro drawn.intro', function() {
61055                 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
61056                 box = pad$1(tulipRoadMidpoint, padding, context);
61057                 box.height = box.height * 2;
61058                 reveal(box,
61059                     t('intro.lines.intersect', { name: t('intro.graph.name.flower-street') }),
61060                     { duration: 0 }
61061                 );
61062             });
61063         }, 550);  // after easing..
61064
61065         context.history().on('change.intro', function() {
61066             var entity = tulipRoadId && context.hasEntity(tulipRoadId);
61067             if (!entity) return chapter.restart();
61068
61069             if (isLineConnected()) {
61070                 continueTo(continueLine);
61071             }
61072         });
61073
61074         context.on('enter.intro', function(mode) {
61075             if (mode.id === 'draw-line')
61076                 return;
61077             else if (mode.id === 'select') {
61078                 continueTo(retryIntersect);
61079                 return;
61080             }
61081             else
61082                 return chapter.restart();
61083         });
61084
61085         function continueTo(nextStep) {
61086             context.map().on('move.intro drawn.intro', null);
61087             context.history().on('change.intro', null);
61088             context.on('enter.intro', null);
61089             nextStep();
61090         }
61091     }
61092
61093
61094     function isLineConnected() {
61095         var entity = tulipRoadId && context.hasEntity(tulipRoadId);
61096         if (!entity) return false;
61097
61098         var drawNodes = context.graph().childNodes(entity);
61099         return lodash.some(drawNodes, function(node) {
61100             return lodash.some(context.graph().parentWays(node), function(parent) {
61101                 return parent.id === flowerRoadId;
61102             });
61103         });
61104     }
61105
61106
61107     function retryIntersect() {
61108         select(window).on('mousedown.intro', eventCancel, true);
61109
61110         var box = pad$1(tulipRoadIntersection, 80, context);
61111         reveal(box,
61112             t('intro.lines.retry_intersect', { name: t('intro.graph.name.flower-street') })
61113         );
61114
61115         timeout(chapter.restart, 3000);
61116     }
61117
61118
61119     function continueLine() {
61120         if (context.mode().id !== 'draw-line') return chapter.restart();
61121         var entity = tulipRoadId && context.hasEntity(tulipRoadId);
61122         if (!entity) return chapter.restart();
61123
61124         context.map().centerEase(tulipRoadIntersection, 500);
61125
61126         reveal('#surface', t('intro.lines.continue_line'));
61127
61128         context.on('enter.intro', function(mode) {
61129             if (mode.id === 'draw-line')
61130                 return;
61131             else if (mode.id === 'select')
61132                 return continueTo(chooseCategoryRoad);
61133             else
61134                 return chapter.restart();
61135         });
61136
61137         function continueTo(nextStep) {
61138             context.on('enter.intro', null);
61139             nextStep();
61140         }
61141     }
61142
61143
61144     function chooseCategoryRoad() {
61145         if (context.mode().id !== 'select') {
61146             return chapter.restart();
61147         }
61148
61149         context.on('exit.intro', function() {
61150             return chapter.restart();
61151         });
61152
61153         var button = select('.preset-category-road .preset-list-button');
61154         if (button.empty()) return chapter.restart();
61155
61156         // disallow scrolling
61157         select('.inspector-wrap').on('wheel.intro', eventCancel);
61158
61159         timeout(function() {
61160             // reset pane, in case user somehow happened to change it..
61161             select('.inspector-wrap .panewrap').style('right', '-100%');
61162
61163             reveal(button.node(),
61164                 t('intro.lines.choose_category_road', { category: roadCategory.name() })
61165             );
61166
61167             button.on('click.intro', function() {
61168                 continueTo(choosePresetResidential);
61169             });
61170
61171         }, 400);  // after editor pane visible
61172
61173         function continueTo(nextStep) {
61174             select('.inspector-wrap').on('wheel.intro', null);
61175             select('.preset-list-button').on('click.intro', null);
61176             context.on('exit.intro', null);
61177             nextStep();
61178         }
61179     }
61180
61181
61182     function choosePresetResidential() {
61183         if (context.mode().id !== 'select') {
61184             return chapter.restart();
61185         }
61186
61187         context.on('exit.intro', function() {
61188             return chapter.restart();
61189         });
61190
61191         var subgrid = select('.preset-category-road .subgrid');
61192         if (subgrid.empty()) return chapter.restart();
61193
61194         subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button')
61195             .on('click.intro', function() {
61196                 continueTo(retryPresetResidential);
61197             });
61198
61199         subgrid.selectAll('.preset-highway-residential .preset-list-button')
61200             .on('click.intro', function() {
61201                 continueTo(nameRoad);
61202             });
61203
61204         timeout(function() {
61205             reveal(subgrid.node(),
61206                 t('intro.lines.choose_preset_residential', { preset: residentialPreset.name() }),
61207                 { tooltipBox: '.preset-highway-residential .preset-list-button', duration: 300 }
61208             );
61209         }, 300);
61210
61211         function continueTo(nextStep) {
61212             select('.preset-list-button').on('click.intro', null);
61213             context.on('exit.intro', null);
61214             nextStep();
61215         }
61216     }
61217
61218
61219     // selected wrong road type
61220     function retryPresetResidential() {
61221         if (context.mode().id !== 'select') {
61222             return chapter.restart();
61223         }
61224
61225         context.on('exit.intro', function() {
61226             return chapter.restart();
61227         });
61228
61229         // disallow scrolling
61230         select('.inspector-wrap').on('wheel.intro', eventCancel);
61231
61232         timeout(function() {
61233             var button = select('.entity-editor-pane .preset-list-button');
61234
61235             reveal(button.node(),
61236                 t('intro.lines.retry_preset_residential', { preset: residentialPreset.name() })
61237             );
61238
61239             button.on('click.intro', function() {
61240                 continueTo(chooseCategoryRoad);
61241             });
61242
61243         }, 500);
61244
61245         function continueTo(nextStep) {
61246             select('.inspector-wrap').on('wheel.intro', null);
61247             select('.preset-list-button').on('click.intro', null);
61248             context.on('exit.intro', null);
61249             nextStep();
61250         }
61251     }
61252
61253
61254     function nameRoad() {
61255         context.on('exit.intro', function() {
61256             continueTo(didNameRoad);
61257         });
61258
61259         timeout(function() {
61260             reveal('.entity-editor-pane',
61261                 t('intro.lines.name_road', { button: icon('#icon-apply', 'pre-text') }),
61262                 { tooltipClass: 'intro-lines-name_road' }
61263             );
61264         }, 500);
61265
61266         function continueTo(nextStep) {
61267             context.on('exit.intro', null);
61268             nextStep();
61269         }
61270     }
61271
61272
61273     function didNameRoad() {
61274         context.history().checkpoint('doneAddLine');
61275
61276         timeout(function() {
61277             reveal('#surface', t('intro.lines.did_name_road'), {
61278                 buttonText: t('intro.ok'),
61279                 buttonCallback: function() { continueTo(updateLine); }
61280             });
61281         }, 500);
61282
61283         function continueTo(nextStep) {
61284             nextStep();
61285         }
61286     }
61287
61288
61289     function updateLine() {
61290         context.history().reset('doneAddLine');
61291         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61292             return chapter.restart();
61293         }
61294
61295         var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
61296         if (msec) { reveal(null, null, { duration: 0 }); }
61297         context.map().zoom(19).centerEase(woodRoadDragMidpoint, msec);
61298
61299         timeout(function() {
61300             var padding = 250 * Math.pow(2, context.map().zoom() - 19);
61301             var box = pad$1(woodRoadDragMidpoint, padding, context);
61302             var advance = function() { continueTo(addNode); };
61303
61304             reveal(box, t('intro.lines.update_line'),
61305                 { buttonText: t('intro.ok'), buttonCallback: advance }
61306             );
61307
61308             context.map().on('move.intro drawn.intro', function() {
61309                 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
61310                 var box = pad$1(woodRoadDragMidpoint, padding, context);
61311                 reveal(box, t('intro.lines.update_line'),
61312                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
61313                 );
61314             });
61315         }, msec + 100);
61316
61317         function continueTo(nextStep) {
61318             context.map().on('move.intro drawn.intro', null);
61319             nextStep();
61320         }
61321     }
61322
61323
61324     function addNode() {
61325         context.history().reset('doneAddLine');
61326         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61327             return chapter.restart();
61328         }
61329
61330         var padding = 40 * Math.pow(2, context.map().zoom() - 19);
61331         var box = pad$1(woodRoadAddNode, padding, context);
61332         reveal(box, t('intro.lines.add_node'));
61333
61334         context.map().on('move.intro drawn.intro', function() {
61335             var padding = 40 * Math.pow(2, context.map().zoom() - 19);
61336             var box = pad$1(woodRoadAddNode, padding, context);
61337             reveal(box, t('intro.lines.add_node'), { duration: 0 });
61338         });
61339
61340         context.history().on('change.intro', function(changed) {
61341             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61342                 return continueTo(updateLine);
61343             }
61344             if (changed.created().length === 1) {
61345                 timeout(function() { continueTo(startDragEndpoint); }, 500);
61346             }
61347         });
61348
61349         context.on('enter.intro', function(mode) {
61350             if (mode.id !== 'select') {
61351                 continueTo(updateLine);
61352             }
61353         });
61354
61355         function continueTo(nextStep) {
61356             context.map().on('move.intro drawn.intro', null);
61357             context.history().on('change.intro', null);
61358             context.on('enter.intro', null);
61359             nextStep();
61360         }
61361     }
61362
61363
61364     function startDragEndpoint() {
61365         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61366             return continueTo(updateLine);
61367         }
61368         if (context.selectedIDs().indexOf(woodRoadId) === -1) {
61369             context.enter(modeSelect(context, [woodRoadId]));
61370         }
61371
61372         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
61373         var box = pad$1(woodRoadDragEndpoint, padding, context);
61374         reveal(box, t('intro.lines.start_drag_endpoint'));
61375
61376         context.map().on('move.intro drawn.intro', function() {
61377             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61378                 return continueTo(updateLine);
61379             }
61380             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
61381             var box = pad$1(woodRoadDragEndpoint, padding, context);
61382             reveal(box, t('intro.lines.start_drag_endpoint'), { duration: 0 });
61383
61384             var entity = context.entity(woodRoadEndId);
61385             if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
61386                 continueTo(finishDragEndpoint);
61387             }
61388         });
61389
61390         context.on('enter.intro', function(mode) {
61391             if (mode.id !== 'select') {
61392                 // keep Wood Road selected so endpoint stays draggable..
61393                 context.enter(modeSelect(context, [woodRoadId]));
61394             }
61395         });
61396
61397         function continueTo(nextStep) {
61398             context.map().on('move.intro drawn.intro', null);
61399             context.on('enter.intro', null);
61400             nextStep();
61401         }
61402     }
61403
61404
61405     function finishDragEndpoint() {
61406         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61407             return continueTo(updateLine);
61408         }
61409
61410         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
61411         var box = pad$1(woodRoadDragEndpoint, padding, context);
61412         reveal(box, t('intro.lines.finish_drag_endpoint'));
61413
61414         context.map().on('move.intro drawn.intro', function() {
61415             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61416                 return continueTo(updateLine);
61417             }
61418             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
61419             var box = pad$1(woodRoadDragEndpoint, padding, context);
61420             reveal(box, t('intro.lines.finish_drag_endpoint'), { duration: 0 });
61421
61422             var entity = context.entity(woodRoadEndId);
61423             if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
61424                 continueTo(startDragEndpoint);
61425             }
61426         });
61427
61428         context.on('enter.intro', function() {
61429             continueTo(startDragMidpoint);
61430         });
61431
61432         function continueTo(nextStep) {
61433             context.map().on('move.intro drawn.intro', null);
61434             context.on('enter.intro', null);
61435             nextStep();
61436         }
61437     }
61438
61439
61440     function startDragMidpoint() {
61441         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61442             return continueTo(updateLine);
61443         }
61444         if (context.selectedIDs().indexOf(woodRoadId) === -1) {
61445             context.enter(modeSelect(context, [woodRoadId]));
61446         }
61447
61448         var padding = 80 * Math.pow(2, context.map().zoom() - 19);
61449         var box = pad$1(woodRoadDragMidpoint, padding, context);
61450         reveal(box, t('intro.lines.start_drag_midpoint'));
61451
61452         context.map().on('move.intro drawn.intro', function() {
61453             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61454                 return continueTo(updateLine);
61455             }
61456             var padding = 80 * Math.pow(2, context.map().zoom() - 19);
61457             var box = pad$1(woodRoadDragMidpoint, padding, context);
61458             reveal(box, t('intro.lines.start_drag_midpoint'), { duration: 0 });
61459         });
61460
61461         context.history().on('change.intro', function(changed) {
61462             if (changed.created().length === 1) {
61463                 continueTo(continueDragMidpoint);
61464             }
61465         });
61466
61467         context.on('enter.intro', function(mode) {
61468             if (mode.id !== 'select') {
61469                 // keep Wood Road selected so midpoint triangles are drawn..
61470                 context.enter(modeSelect(context, [woodRoadId]));
61471             }
61472         });
61473
61474         function continueTo(nextStep) {
61475             context.map().on('move.intro drawn.intro', null);
61476             context.history().on('change.intro', null);
61477             context.on('enter.intro', null);
61478             nextStep();
61479         }
61480     }
61481
61482
61483     function continueDragMidpoint() {
61484         if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61485             return continueTo(updateLine);
61486         }
61487
61488         var padding = 100 * Math.pow(2, context.map().zoom() - 19);
61489         var box = pad$1(woodRoadDragEndpoint, padding, context);
61490         box.height += 400;
61491
61492         var advance = function() {
61493             context.history().checkpoint('doneUpdateLine');
61494             continueTo(deleteLines);
61495         };
61496
61497         reveal(box, t('intro.lines.continue_drag_midpoint'),
61498             { buttonText: t('intro.ok'), buttonCallback: advance }
61499         );
61500
61501         context.map().on('move.intro drawn.intro', function() {
61502             if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) {
61503                 return continueTo(updateLine);
61504             }
61505             var padding = 100 * Math.pow(2, context.map().zoom() - 19);
61506             var box = pad$1(woodRoadDragEndpoint, padding, context);
61507             box.height += 400;
61508             reveal(box, t('intro.lines.continue_drag_midpoint'),
61509                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
61510             );
61511         });
61512
61513         function continueTo(nextStep) {
61514             context.map().on('move.intro drawn.intro', null);
61515             nextStep();
61516         }
61517     }
61518
61519
61520     function deleteLines() {
61521         context.history().reset('doneUpdateLine');
61522         context.enter(modeBrowse(context));
61523
61524         if (!context.hasEntity(washingtonStreetId) ||
61525             !context.hasEntity(twelfthAvenueId) ||
61526             !context.hasEntity(eleventhAvenueEndId)) {
61527             return chapter.restart();
61528         }
61529
61530         var msec = transitionTime(deleteLinesLoc, context.map().center());
61531         if (msec) { reveal(null, null, { duration: 0 }); }
61532         context.map().zoom(18).centerEase(deleteLinesLoc, msec);
61533
61534         timeout(function() {
61535             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61536             var box = pad$1(deleteLinesLoc, padding, context);
61537             box.top -= 200;
61538             box.height += 400;
61539             var advance = function() { continueTo(rightClickIntersection); };
61540
61541             reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }),
61542                 { buttonText: t('intro.ok'), buttonCallback: advance }
61543             );
61544
61545             context.map().on('move.intro drawn.intro', function() {
61546                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61547                 var box = pad$1(deleteLinesLoc, padding, context);
61548                 box.top -= 200;
61549                 box.height += 400;
61550                 reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }),
61551                     { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
61552                 );
61553             });
61554
61555             context.history().on('change.intro', function() {
61556                 timeout(function() {
61557                     continueTo(deleteLines);
61558                 }, 500);  // after any transition (e.g. if user deleted intersection)
61559             });
61560
61561         }, msec + 100);
61562
61563         function continueTo(nextStep) {
61564             context.map().on('move.intro drawn.intro', null);
61565             context.history().on('change.intro', null);
61566             nextStep();
61567         }
61568     }
61569
61570
61571     function rightClickIntersection() {
61572         context.history().reset('doneUpdateLine');
61573         context.enter(modeBrowse(context));
61574
61575         context.map().zoom(18).centerEase(eleventhAvenueEnd, 500);
61576
61577         timeout(function() {
61578             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
61579             var box = pad$1(eleventhAvenueEnd, padding, context);
61580             reveal(box, t('intro.lines.rightclick_intersection',
61581                 { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') })
61582             );
61583
61584             context.map().on('move.intro drawn.intro', function() {
61585                 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
61586                 var box = pad$1(eleventhAvenueEnd, padding, context);
61587                 reveal(box, t('intro.lines.rightclick_intersection',
61588                     { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') }),
61589                     { duration: 0 }
61590                 );
61591             });
61592
61593             context.on('enter.intro', function(mode) {
61594                 if (mode.id !== 'select') return;
61595                 var ids = context.selectedIDs();
61596                 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndId) return;
61597
61598                 timeout(function() {
61599                     var node = selectMenuItem('split').node();
61600                     if (!node) return;
61601                     continueTo(splitIntersection);
61602                 }, 300);  // after menu visible
61603             });
61604
61605             context.history().on('change.intro', function() {
61606                 timeout(function() {
61607                     continueTo(deleteLines);
61608                 }, 300);  // after any transition (e.g. if user deleted intersection)
61609             });
61610
61611         }, 600);
61612
61613         function continueTo(nextStep) {
61614             context.map().on('move.intro drawn.intro', null);
61615             context.on('enter.intro', null);
61616             context.history().on('change.intro', null);
61617             nextStep();
61618         }
61619     }
61620
61621
61622     function splitIntersection() {
61623         if (!context.hasEntity(washingtonStreetId) ||
61624             !context.hasEntity(twelfthAvenueId) ||
61625             !context.hasEntity(eleventhAvenueEndId)) {
61626             return continueTo(deleteLines);
61627         }
61628
61629         var node = selectMenuItem('split').node();
61630         if (!node) { return continueTo(rightClickIntersection); }
61631
61632         var wasChanged = false;
61633         var menuCoords = context.map().mouseCoordinates();
61634         washingtonSegmentId = null;
61635
61636         revealEditMenu(menuCoords, t('intro.lines.split_intersection',
61637             { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') })
61638         );
61639
61640         context.map().on('move.intro drawn.intro', function() {
61641             var node = selectMenuItem('split').node();
61642             if (!wasChanged && !node) { return continueTo(rightClickIntersection); }
61643
61644             revealEditMenu(menuCoords, t('intro.lines.split_intersection',
61645                 { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') }),
61646                 { duration: 0 }
61647             );
61648         });
61649
61650         context.history().on('change.intro', function(changed) {
61651             wasChanged = true;
61652             timeout(function() {
61653                 if (context.history().undoAnnotation() === t('operations.split.annotation.line')) {
61654                     washingtonSegmentId = changed.created()[0].id;
61655                     continueTo(didSplit);
61656                 } else {
61657                     washingtonSegmentId = null;
61658                     continueTo(retrySplit);
61659                 }
61660             }, 300);  // after any transition (e.g. if user deleted intersection)
61661         });
61662
61663         function continueTo(nextStep) {
61664             context.map().on('move.intro drawn.intro', null);
61665             context.history().on('change.intro', null);
61666             nextStep();
61667         }
61668     }
61669
61670
61671     function retrySplit() {
61672         context.enter(modeBrowse(context));
61673         context.map().zoom(18).centerEase(eleventhAvenueEnd, 500);
61674         var advance = function() { continueTo(rightClickIntersection); };
61675
61676         var padding = 60 * Math.pow(2, context.map().zoom() - 18);
61677         var box = pad$1(eleventhAvenueEnd, padding, context);
61678         reveal(box, t('intro.lines.retry_split'),
61679             { buttonText: t('intro.ok'), buttonCallback: advance }
61680         );
61681
61682         context.map().on('move.intro drawn.intro', function() {
61683             var padding = 60 * Math.pow(2, context.map().zoom() - 18);
61684             var box = pad$1(eleventhAvenueEnd, padding, context);
61685             reveal(box, t('intro.lines.retry_split'),
61686                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance }
61687             );
61688         });
61689
61690         function continueTo(nextStep) {
61691             context.map().on('move.intro drawn.intro', null);
61692             nextStep();
61693         }
61694     }
61695
61696
61697     function didSplit() {
61698         if (!washingtonSegmentId ||
61699             !context.hasEntity(washingtonSegmentId) ||
61700             !context.hasEntity(washingtonStreetId) ||
61701             !context.hasEntity(twelfthAvenueId) ||
61702             !context.hasEntity(eleventhAvenueEndId)) {
61703             return continueTo(rightClickIntersection);
61704         }
61705
61706         var ids = context.selectedIDs();
61707         var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
61708         var street = t('intro.graph.name.washington-street');
61709
61710         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61711         var box = pad$1(twelfthAvenue, padding, context);
61712         box.width = box.width / 2;
61713         reveal(box, t(string, { street1: street, street2: street }),
61714             { duration: 500 }
61715         );
61716
61717         timeout(function() {
61718             context.map().zoom(18).centerEase(twelfthAvenue, 500);
61719
61720             context.map().on('move.intro drawn.intro', function() {
61721                 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61722                 var box = pad$1(twelfthAvenue, padding, context);
61723                 box.width = box.width / 2;
61724                 reveal(box, t(string, { street1: street, street2: street }),
61725                     { duration: 0 }
61726                 );
61727             });
61728         }, 600);  // after initial reveal and curtain cut
61729
61730         context.on('enter.intro', function() {
61731             var ids = context.selectedIDs();
61732             if (ids.length === 1 && ids[0] === washingtonSegmentId) {
61733                 continueTo(multiSelect);
61734             }
61735         });
61736
61737         context.history().on('change.intro', function() {
61738             if (!washingtonSegmentId ||
61739                 !context.hasEntity(washingtonSegmentId) ||
61740                 !context.hasEntity(washingtonStreetId) ||
61741                 !context.hasEntity(twelfthAvenueId) ||
61742                 !context.hasEntity(eleventhAvenueEndId)) {
61743                 return continueTo(rightClickIntersection);
61744             }
61745         });
61746
61747         function continueTo(nextStep) {
61748             context.map().on('move.intro drawn.intro', null);
61749             context.on('enter.intro', null);
61750             context.history().on('change.intro', null);
61751             nextStep();
61752         }
61753     }
61754
61755
61756     function multiSelect() {
61757         if (!washingtonSegmentId ||
61758             !context.hasEntity(washingtonSegmentId) ||
61759             !context.hasEntity(washingtonStreetId) ||
61760             !context.hasEntity(twelfthAvenueId) ||
61761             !context.hasEntity(eleventhAvenueEndId)) {
61762             return continueTo(rightClickIntersection);
61763         }
61764
61765         var ids = context.selectedIDs();
61766         var hasWashington = ids.indexOf(washingtonSegmentId) !== -1;
61767         var hasTwelfth = ids.indexOf(twelfthAvenueId) !== -1;
61768
61769         if (hasWashington && hasTwelfth) {
61770             return continueTo(multiRightClick);
61771         } else if (!hasWashington && !hasTwelfth) {
61772             return continueTo(didSplit);
61773         }
61774
61775         context.map().zoom(18).centerEase(twelfthAvenue, 500);
61776
61777         timeout(function() {
61778             var selected, other, padding, box;
61779             if (hasWashington) {
61780                 selected = t('intro.graph.name.washington-street');
61781                 other = t('intro.graph.name.12th-avenue');
61782                 padding = 60 * Math.pow(2, context.map().zoom() - 18);
61783                 box = pad$1(twelfthAvenueEnd, padding, context);
61784                 box.width *= 3;
61785             } else {
61786                 selected = t('intro.graph.name.12th-avenue');
61787                 other = t('intro.graph.name.washington-street');
61788                 padding = 200 * Math.pow(2, context.map().zoom() - 18);
61789                 box = pad$1(twelfthAvenue, padding, context);
61790                 box.width /= 2;
61791             }
61792
61793             reveal(box,
61794                 t('intro.lines.multi_select', { selected: selected, other1: other, other2: other })
61795             );
61796
61797             context.map().on('move.intro drawn.intro', function() {
61798                 if (hasWashington) {
61799                     selected = t('intro.graph.name.washington-street');
61800                     other = t('intro.graph.name.12th-avenue');
61801                     padding = 60 * Math.pow(2, context.map().zoom() - 18);
61802                     box = pad$1(twelfthAvenueEnd, padding, context);
61803                     box.width *= 3;
61804                 } else {
61805                     selected = t('intro.graph.name.12th-avenue');
61806                     other = t('intro.graph.name.washington-street');
61807                     padding = 200 * Math.pow(2, context.map().zoom() - 18);
61808                     box = pad$1(twelfthAvenue, padding, context);
61809                     box.width /= 2;
61810                 }
61811
61812                 reveal(box,
61813                     t('intro.lines.multi_select', { selected: selected, other1: other, other2: other }),
61814                     { duration: 0 }
61815                 );
61816             });
61817
61818             context.on('enter.intro', function() {
61819                 continueTo(multiSelect);
61820             });
61821
61822             context.history().on('change.intro', function() {
61823                 if (!washingtonSegmentId ||
61824                     !context.hasEntity(washingtonSegmentId) ||
61825                     !context.hasEntity(washingtonStreetId) ||
61826                     !context.hasEntity(twelfthAvenueId) ||
61827                     !context.hasEntity(eleventhAvenueEndId)) {
61828                     return continueTo(rightClickIntersection);
61829                 }
61830             });
61831         }, 600);
61832
61833         function continueTo(nextStep) {
61834             context.map().on('move.intro drawn.intro', null);
61835             context.on('enter.intro', null);
61836             context.history().on('change.intro', null);
61837             nextStep();
61838         }
61839     }
61840
61841
61842     function multiRightClick() {
61843         if (!washingtonSegmentId ||
61844             !context.hasEntity(washingtonSegmentId) ||
61845             !context.hasEntity(washingtonStreetId) ||
61846             !context.hasEntity(twelfthAvenueId) ||
61847             !context.hasEntity(eleventhAvenueEndId)) {
61848             return continueTo(rightClickIntersection);
61849         }
61850
61851         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61852         var box = pad$1(twelfthAvenue, padding, context);
61853         reveal(box, t('intro.lines.multi_rightclick'));
61854
61855         context.map().on('move.intro drawn.intro', function() {
61856             var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61857             var box = pad$1(twelfthAvenue, padding, context);
61858             reveal(box, t('intro.lines.multi_rightclick'), { duration: 0 });
61859         });
61860
61861         select(window).on('click.intro contextmenu.intro', function() {
61862             timeout(function() {
61863                 var ids = context.selectedIDs();
61864                 if (ids.length === 2 &&
61865                     ids.indexOf(twelfthAvenueId) !== -1 &&
61866                     ids.indexOf(washingtonSegmentId) !== -1) {
61867                         var node = selectMenuItem('delete').node();
61868                         if (!node) return;
61869                         continueTo(multiDelete);
61870                 } else if (ids.length === 1 &&
61871                     ids.indexOf(washingtonSegmentId) !== -1) {
61872                     return continueTo(multiSelect);
61873                 } else {
61874                     return continueTo(didSplit);
61875                 }
61876             }, 300);  // after edit menu visible
61877         }, true);
61878
61879         context.history().on('change.intro', function() {
61880             if (!washingtonSegmentId ||
61881                 !context.hasEntity(washingtonSegmentId) ||
61882                 !context.hasEntity(washingtonStreetId) ||
61883                 !context.hasEntity(twelfthAvenueId) ||
61884                 !context.hasEntity(eleventhAvenueEndId)) {
61885                 return continueTo(rightClickIntersection);
61886             }
61887         });
61888
61889         function continueTo(nextStep) {
61890             context.map().on('move.intro drawn.intro', null);
61891             select(window).on('click.intro contextmenu.intro', null, true);
61892             context.history().on('change.intro', null);
61893             nextStep();
61894         }
61895     }
61896
61897
61898     function multiDelete() {
61899         if (!washingtonSegmentId ||
61900             !context.hasEntity(washingtonSegmentId) ||
61901             !context.hasEntity(washingtonStreetId) ||
61902             !context.hasEntity(twelfthAvenueId) ||
61903             !context.hasEntity(eleventhAvenueEndId)) {
61904             return continueTo(rightClickIntersection);
61905         }
61906
61907         var node = selectMenuItem('delete').node();
61908         if (!node) return continueTo(multiRightClick);
61909
61910         var menuCoords = context.map().mouseCoordinates();
61911         revealEditMenu(menuCoords,
61912             t('intro.lines.multi_delete', { button: icon('#operation-delete', 'pre-text') })
61913         );
61914
61915         context.map().on('move.intro drawn.intro', function() {
61916             revealEditMenu(menuCoords,
61917                 t('intro.lines.multi_delete', { button: icon('#operation-delete', 'pre-text') }),
61918                 { duration: 0 }
61919             );
61920         });
61921
61922         context.on('exit.intro', function() {
61923             if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) {
61924                 return continueTo(multiSelect);  // left select mode but roads still exist
61925             }
61926         });
61927
61928         context.history().on('change.intro', function() {
61929             if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) {
61930                 continueTo(retryDelete);         // changed something but roads still exist
61931             } else {
61932                 continueTo(play);
61933             }
61934         });
61935
61936         function continueTo(nextStep) {
61937             context.map().on('move.intro drawn.intro', null);
61938             context.on('exit.intro', null);
61939             context.history().on('change.intro', null);
61940             nextStep();
61941         }
61942     }
61943
61944
61945     function retryDelete() {
61946         context.enter(modeBrowse(context));
61947
61948         var padding = 200 * Math.pow(2, context.map().zoom() - 18);
61949         var box = pad$1(twelfthAvenue, padding, context);
61950         reveal(box, t('intro.lines.retry_delete'), {
61951             buttonText: t('intro.ok'),
61952             buttonCallback: function() { continueTo(multiSelect); }
61953         });
61954
61955         function continueTo(nextStep) {
61956             nextStep();
61957         }
61958     }
61959
61960
61961     function play() {
61962         dispatch$$1.call('done');
61963         reveal('#id-container',
61964             t('intro.lines.play', { next: t('intro.buildings.title') }), {
61965                 tooltipBox: '.intro-nav-wrap .chapter-building',
61966                 buttonText: t('intro.ok'),
61967                 buttonCallback: function() { reveal('#id-container'); }
61968             }
61969         );
61970    }
61971
61972
61973     chapter.enter = function() {
61974         addLine();
61975     };
61976
61977
61978     chapter.exit = function() {
61979         timeouts.forEach(window.clearTimeout);
61980         select(window).on('mousedown.intro', null, true);
61981         context.on('enter.intro exit.intro', null);
61982         context.map().on('move.intro drawn.intro', null);
61983         context.history().on('change.intro', null);
61984         select('.inspector-wrap').on('wheel.intro', null);
61985         select('.preset-list-button').on('click.intro', null);
61986     };
61987
61988
61989     chapter.restart = function() {
61990         chapter.exit();
61991         chapter.enter();
61992     };
61993
61994
61995     return utilRebind(chapter, dispatch$$1, 'on');
61996 }
61997
61998 function uiIntroBuilding(context, reveal) {
61999     var dispatch$$1 = dispatch('done'),
62000         house = [-85.62815, 41.95638],
62001         tank = [-85.62732, 41.95347],
62002         buildingCatetory = context.presets().item('category-building'),
62003         housePreset = context.presets().item('building/house'),
62004         tankPreset = context.presets().item('man_made/storage_tank'),
62005         timeouts = [],
62006         houseId = null,
62007         tankId = null;
62008
62009
62010     var chapter = {
62011         title: 'intro.buildings.title'
62012     };
62013
62014
62015     function timeout(f, t$$1) {
62016         timeouts.push(window.setTimeout(f, t$$1));
62017     }
62018
62019
62020     function eventCancel() {
62021         event.stopPropagation();
62022         event.preventDefault();
62023     }
62024
62025
62026     function revealHouse(center, text$$1, options) {
62027         var padding = 160 * Math.pow(2, context.map().zoom() - 20);
62028         var box = pad$1(center, padding, context);
62029         reveal(box, text$$1, options);
62030     }
62031
62032
62033     function revealTank(center, text$$1, options) {
62034         var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
62035         var box = pad$1(center, padding, context);
62036         reveal(box, text$$1, options);
62037     }
62038
62039
62040     function revealEditMenu(loc, text$$1, options) {
62041         var rect = context.surfaceRect();
62042         var point = context.curtainProjection(loc);
62043         var pad = 40;
62044         var width = 250 + (2 * pad);
62045         var height = 350;
62046         var startX = rect.left + point[0];
62047         var left = (textDirection === 'rtl') ? (startX - width + pad) : (startX - pad);
62048         var box = {
62049             left: left,
62050             top: point[1] + rect.top - 60,
62051             width: width,
62052             height: height
62053         };
62054         reveal(box, text$$1, options);
62055     }
62056
62057
62058     function addHouse() {
62059         context.enter(modeBrowse(context));
62060         context.history().reset('initial');
62061         houseId = null;
62062
62063         var msec = transitionTime(house, context.map().center());
62064         if (msec) { reveal(null, null, { duration: 0 }); }
62065         context.map().zoom(19).centerEase(house, msec);
62066
62067         timeout(function() {
62068             var tooltip = reveal('button.add-area',
62069                 t('intro.buildings.add_building', { button: icon('#icon-area', 'pre-text') }));
62070
62071             tooltip.selectAll('.tooltip-inner')
62072                 .insert('svg', 'span')
62073                 .attr('class', 'tooltip-illustration')
62074                 .append('use')
62075                 .attr('xlink:href', '#building-images');
62076
62077             context.on('enter.intro', function(mode) {
62078                 if (mode.id !== 'add-area') return;
62079                 continueTo(startHouse);
62080             });
62081         }, msec + 100);
62082
62083         function continueTo(nextStep) {
62084             context.on('enter.intro', null);
62085             nextStep();
62086         }
62087     }
62088
62089
62090     function startHouse() {
62091         if (context.mode().id !== 'add-area') {
62092             return continueTo(addHouse);
62093         }
62094
62095         houseId = null;
62096         context.map().zoomEase(20, 500);
62097
62098         timeout(function() {
62099             revealHouse(house, t('intro.buildings.start_building'));
62100
62101             context.map().on('move.intro drawn.intro', function() {
62102                 revealHouse(house, t('intro.buildings.start_building'), { duration: 0 });
62103             });
62104
62105             context.on('enter.intro', function(mode) {
62106                 if (mode.id !== 'draw-area') return chapter.restart();
62107                 continueTo(continueHouse);
62108             });
62109
62110         }, 550);  // after easing
62111
62112         function continueTo(nextStep) {
62113             context.map().on('move.intro drawn.intro', null);
62114             context.on('enter.intro', null);
62115             nextStep();
62116         }
62117     }
62118
62119
62120     function continueHouse() {
62121         if (context.mode().id !== 'draw-area') {
62122             return continueTo(addHouse);
62123         }
62124
62125         houseId = null;
62126
62127         revealHouse(house, t('intro.buildings.continue_building'));
62128
62129         context.map().on('move.intro drawn.intro', function() {
62130             revealHouse(house, t('intro.buildings.continue_building'), { duration: 0 });
62131         });
62132
62133         context.on('enter.intro', function(mode) {
62134             if (mode.id === 'draw-area') {
62135                 return;
62136             } else if (mode.id === 'select') {
62137                 var graph = context.graph(),
62138                     way = context.entity(context.selectedIDs()[0]),
62139                     nodes = graph.childNodes(way),
62140                     points = lodash.uniq(nodes).map(function(n) { return context.projection(n.loc); });
62141
62142                 if (isMostlySquare(points)) {
62143                     houseId = way.id;
62144                     return continueTo(chooseCategoryBuilding);
62145                 } else {
62146                     return continueTo(retryHouse);
62147                 }
62148
62149             } else {
62150                 return chapter.restart();
62151             }
62152         });
62153
62154         function continueTo(nextStep) {
62155             context.map().on('move.intro drawn.intro', null);
62156             context.on('enter.intro', null);
62157             nextStep();
62158         }
62159     }
62160
62161
62162     function retryHouse() {
62163         var onClick = function() { continueTo(addHouse); };
62164
62165         revealHouse(house, t('intro.buildings.retry_building'),
62166             { buttonText: t('intro.ok'), buttonCallback: onClick }
62167         );
62168
62169         context.map().on('move.intro drawn.intro', function() {
62170             revealHouse(house, t('intro.buildings.retry_building'),
62171                 { duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
62172             );
62173         });
62174
62175         function continueTo(nextStep) {
62176             context.map().on('move.intro drawn.intro', null);
62177             nextStep();
62178         }
62179     }
62180
62181
62182     function chooseCategoryBuilding() {
62183         if (!houseId || !context.hasEntity(houseId)) {
62184             return addHouse();
62185         }
62186         var ids = context.selectedIDs();
62187         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
62188             context.enter(modeSelect(context, [houseId]));
62189         }
62190
62191         // disallow scrolling
62192         select('.inspector-wrap').on('wheel.intro', eventCancel);
62193
62194         timeout(function() {
62195             // reset pane, in case user somehow happened to change it..
62196             select('.inspector-wrap .panewrap').style('right', '-100%');
62197
62198             var button = select('.preset-category-building .preset-list-button');
62199
62200             reveal(button.node(),
62201                 t('intro.buildings.choose_category_building', { category: buildingCatetory.name() })
62202             );
62203
62204             button.on('click.intro', function() {
62205                 button.on('click.intro', null);
62206                 continueTo(choosePresetHouse);
62207             });
62208
62209         }, 400);  // after preset list pane visible..
62210
62211
62212         context.on('enter.intro', function(mode) {
62213             if (!houseId || !context.hasEntity(houseId)) {
62214                 return continueTo(addHouse);
62215             }
62216             var ids = context.selectedIDs();
62217             if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) {
62218                 return continueTo(chooseCategoryBuilding);
62219             }
62220         });
62221
62222         function continueTo(nextStep) {
62223             select('.inspector-wrap').on('wheel.intro', null);
62224             select('.preset-list-button').on('click.intro', null);
62225             context.on('enter.intro', null);
62226             nextStep();
62227         }
62228     }
62229
62230
62231     function choosePresetHouse() {
62232         if (!houseId || !context.hasEntity(houseId)) {
62233             return addHouse();
62234         }
62235         var ids = context.selectedIDs();
62236         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
62237             context.enter(modeSelect(context, [houseId]));
62238         }
62239
62240         // disallow scrolling
62241         select('.inspector-wrap').on('wheel.intro', eventCancel);
62242
62243         timeout(function() {
62244             // reset pane, in case user somehow happened to change it..
62245             select('.inspector-wrap .panewrap').style('right', '-100%');
62246
62247             var button = select('.preset-building-house .preset-list-button');
62248
62249             reveal(button.node(),
62250                 t('intro.buildings.choose_preset_house', { preset: housePreset.name() }),
62251                 { duration: 300 }
62252             );
62253
62254             button.on('click.intro', function() {
62255                 button.on('click.intro', null);
62256                 continueTo(closeEditorHouse);
62257             });
62258
62259
62260         }, 400);  // after preset list pane visible..
62261
62262         context.on('enter.intro', function(mode) {
62263             if (!houseId || !context.hasEntity(houseId)) {
62264                 return continueTo(addHouse);
62265             }
62266             var ids = context.selectedIDs();
62267             if (mode.id !== 'select' || !ids.length || ids[0] !== houseId) {
62268                 return continueTo(chooseCategoryBuilding);
62269             }
62270         });
62271
62272         function continueTo(nextStep) {
62273             select('.inspector-wrap').on('wheel.intro', null);
62274             select('.preset-list-button').on('click.intro', null);
62275             context.on('enter.intro', null);
62276             nextStep();
62277         }
62278     }
62279
62280
62281     function closeEditorHouse() {
62282         if (!houseId || !context.hasEntity(houseId)) {
62283             return addHouse();
62284         }
62285         var ids = context.selectedIDs();
62286         if (context.mode().id !== 'select' || !ids.length || ids[0] !== houseId) {
62287             context.enter(modeSelect(context, [houseId]));
62288         }
62289
62290         context.history().checkpoint('hasHouse');
62291
62292         context.on('exit.intro', function() {
62293             continueTo(rightClickHouse);
62294         });
62295
62296         timeout(function() {
62297             reveal('.entity-editor-pane',
62298                 t('intro.buildings.close', { button: icon('#icon-apply', 'pre-text') })
62299             );
62300         }, 500);
62301
62302         function continueTo(nextStep) {
62303             context.on('exit.intro', null);
62304             nextStep();
62305         }
62306     }
62307
62308
62309     function rightClickHouse() {
62310         if (!houseId) return chapter.restart();
62311
62312         context.enter(modeBrowse(context));
62313         context.history().reset('hasHouse');
62314         context.map().centerEase(house, 500);
62315
62316         timeout(function() {
62317             if (context.map().zoom() < 20) {
62318                 context.map().zoomEase(20, 500);
62319             }
62320         }, 520);
62321
62322         context.on('enter.intro', function(mode) {
62323             if (mode.id !== 'select') return;
62324             var ids = context.selectedIDs();
62325             if (ids.length !== 1 || ids[0] !== houseId) return;
62326
62327             timeout(function() {
62328                 var node = selectMenuItem('orthogonalize').node();
62329                 if (!node) return;
62330                 continueTo(clickSquare);
62331             }, 300);  // after menu visible
62332         });
62333
62334         context.map().on('move.intro drawn.intro', function() {
62335             revealHouse(house, t('intro.buildings.rightclick_building'), { duration: 0 });
62336         });
62337
62338         context.history().on('change.intro', function() {
62339             continueTo(rightClickHouse);
62340         });
62341
62342         function continueTo(nextStep) {
62343             context.on('enter.intro', null);
62344             context.map().on('move.intro drawn.intro', null);
62345             context.history().on('change.intro', null);
62346             nextStep();
62347         }
62348     }
62349
62350
62351     function clickSquare() {
62352         if (!houseId) return chapter.restart();
62353         var entity = context.hasEntity(houseId);
62354         if (!entity) return continueTo(rightClickHouse);
62355
62356         var node = selectMenuItem('orthogonalize').node();
62357         if (!node) { return continueTo(rightClickHouse); }
62358
62359         var wasChanged = false;
62360         var menuCoords = context.map().mouseCoordinates();
62361
62362         revealEditMenu(menuCoords,
62363             t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') })
62364         );
62365
62366         context.on('enter.intro', function(mode) {
62367             if (mode.id === 'browse') {
62368                 continueTo(rightClickHouse);
62369             } else if (mode.id === 'move' || mode.id === 'rotate') {
62370                 continueTo(retryClickSquare);
62371             }
62372         });
62373
62374         context.map().on('move.intro drawn.intro', function() {
62375             var node = selectMenuItem('orthogonalize').node();
62376             if (!wasChanged && !node) { return continueTo(rightClickHouse); }
62377
62378             revealEditMenu(menuCoords,
62379                 t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') }),
62380                 { duration: 0 }
62381             );
62382         });
62383
62384         context.history().on('change.intro', function() {
62385             wasChanged = true;
62386             context.history().on('change.intro', null);
62387
62388             // Something changed.  Wait for transition to complete and check undo annotation.
62389             timeout(function() {
62390                 if (context.history().undoAnnotation() === t('operations.orthogonalize.annotation.area')) {
62391                     continueTo(doneSquare);
62392                 } else {
62393                     continueTo(retryClickSquare);
62394                 }
62395             }, 500);  // after transitioned actions
62396         });
62397
62398         function continueTo(nextStep) {
62399             context.on('enter.intro', null);
62400             context.map().on('move.intro drawn.intro', null);
62401             context.history().on('change.intro', null);
62402             nextStep();
62403         }
62404     }
62405
62406
62407     function retryClickSquare() {
62408         context.enter(modeBrowse(context));
62409
62410         revealHouse(house, t('intro.buildings.retry_square'), {
62411             buttonText: t('intro.ok'),
62412             buttonCallback: function() { continueTo(rightClickHouse); }
62413         });
62414
62415         function continueTo(nextStep) {
62416             nextStep();
62417         }
62418     }
62419
62420
62421     function doneSquare() {
62422         context.history().checkpoint('doneSquare');
62423
62424         revealHouse(house, t('intro.buildings.done_square'), {
62425             buttonText: t('intro.ok'),
62426             buttonCallback: function() { continueTo(addTank); }
62427         });
62428
62429         function continueTo(nextStep) {
62430             nextStep();
62431         }
62432     }
62433
62434
62435     function addTank() {
62436         context.enter(modeBrowse(context));
62437         context.history().reset('doneSquare');
62438         tankId = null;
62439
62440         var msec = transitionTime(tank, context.map().center());
62441         if (msec) { reveal(null, null, { duration: 0 }); }
62442         context.map().zoom(19.5).centerEase(tank, msec);
62443
62444         timeout(function() {
62445             reveal('button.add-area',
62446                 t('intro.buildings.add_tank', { button: icon('#icon-area', 'pre-text') })
62447             );
62448
62449             context.on('enter.intro', function(mode) {
62450                 if (mode.id !== 'add-area') return;
62451                 continueTo(startTank);
62452             });
62453         }, msec + 100);
62454
62455         function continueTo(nextStep) {
62456             context.on('enter.intro', null);
62457             nextStep();
62458         }
62459     }
62460
62461
62462     function startTank() {
62463         if (context.mode().id !== 'add-area') {
62464             return continueTo(addTank);
62465         }
62466
62467         tankId = null;
62468
62469         timeout(function() {
62470             revealTank(tank, t('intro.buildings.start_tank'));
62471
62472             context.map().on('move.intro drawn.intro', function() {
62473                 revealTank(tank, t('intro.buildings.start_tank'), { duration: 0 });
62474             });
62475
62476             context.on('enter.intro', function(mode) {
62477                 if (mode.id !== 'draw-area') return chapter.restart();
62478                 continueTo(continueTank);
62479             });
62480
62481         }, 550);  // after easing
62482
62483         function continueTo(nextStep) {
62484             context.map().on('move.intro drawn.intro', null);
62485             context.on('enter.intro', null);
62486             nextStep();
62487         }
62488     }
62489
62490
62491     function continueTank() {
62492         if (context.mode().id !== 'draw-area') {
62493             return continueTo(addTank);
62494         }
62495
62496         tankId = null;
62497
62498         revealTank(tank, t('intro.buildings.continue_tank'));
62499
62500         context.map().on('move.intro drawn.intro', function() {
62501             revealTank(tank, t('intro.buildings.continue_tank'), { duration: 0 });
62502         });
62503
62504         context.on('enter.intro', function(mode) {
62505             if (mode.id === 'draw-area') {
62506                 return;
62507             } else if (mode.id === 'select') {
62508                 tankId = context.selectedIDs()[0];
62509                 return continueTo(searchPresetTank);
62510             } else {
62511                 return continueTo(addTank);
62512             }
62513         });
62514
62515         function continueTo(nextStep) {
62516             context.map().on('move.intro drawn.intro', null);
62517             context.on('enter.intro', null);
62518             nextStep();
62519         }
62520     }
62521
62522
62523     function searchPresetTank() {
62524         if (!tankId || !context.hasEntity(tankId)) {
62525             return addTank();
62526         }
62527         var ids = context.selectedIDs();
62528         if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) {
62529             context.enter(modeSelect(context, [tankId]));
62530         }
62531
62532         // disallow scrolling
62533         select('.inspector-wrap').on('wheel.intro', eventCancel);
62534
62535         timeout(function() {
62536             // reset pane, in case user somehow happened to change it..
62537             select('.inspector-wrap .panewrap').style('right', '-100%');
62538
62539             select('.preset-search-input')
62540                 .on('keydown.intro', null)
62541                 .on('keyup.intro', checkPresetSearch);
62542
62543             reveal('.preset-search-input',
62544                 t('intro.buildings.search_tank', { preset: tankPreset.name() })
62545             );
62546         }, 400);  // after preset list pane visible..
62547
62548         context.on('enter.intro', function(mode) {
62549             if (!tankId || !context.hasEntity(tankId)) {
62550                 return continueTo(addTank);
62551             }
62552
62553             var ids = context.selectedIDs();
62554             if (mode.id !== 'select' || !ids.length || ids[0] !== tankId) {
62555                 // keep the user's area selected..
62556                 context.enter(modeSelect(context, [tankId]));
62557
62558                 // reset pane, in case user somehow happened to change it..
62559                 select('.inspector-wrap .panewrap').style('right', '-100%');
62560                 // disallow scrolling
62561                 select('.inspector-wrap').on('wheel.intro', eventCancel);
62562
62563                 select('.preset-search-input')
62564                     .on('keydown.intro', null)
62565                     .on('keyup.intro', checkPresetSearch);
62566
62567                 reveal('.preset-search-input',
62568                     t('intro.buildings.search_tank', { preset: tankPreset.name() })
62569                 );
62570
62571                 context.history().on('change.intro', null);
62572             }
62573         });
62574
62575         function checkPresetSearch() {
62576             var first = select('.preset-list-item:first-child');
62577
62578             if (first.classed('preset-man_made-storage_tank')) {
62579                 reveal(first.select('.preset-list-button').node(),
62580                     t('intro.buildings.choose_tank', { preset: tankPreset.name() }),
62581                     { duration: 300 }
62582                 );
62583
62584                 select('.preset-search-input')
62585                     .on('keydown.intro', eventCancel, true)
62586                     .on('keyup.intro', null);
62587
62588                 context.history().on('change.intro', function() {
62589                     continueTo(closeEditorTank);
62590                 });
62591             }
62592         }
62593
62594         function continueTo(nextStep) {
62595             select('.inspector-wrap').on('wheel.intro', null);
62596             context.on('enter.intro', null);
62597             context.history().on('change.intro', null);
62598             select('.preset-search-input').on('keydown.intro keyup.intro', null);
62599             nextStep();
62600         }
62601     }
62602
62603
62604     function closeEditorTank() {
62605         if (!tankId || !context.hasEntity(tankId)) {
62606             return addTank();
62607         }
62608         var ids = context.selectedIDs();
62609         if (context.mode().id !== 'select' || !ids.length || ids[0] !== tankId) {
62610             context.enter(modeSelect(context, [tankId]));
62611         }
62612
62613         context.history().checkpoint('hasTank');
62614
62615         context.on('exit.intro', function() {
62616             continueTo(rightClickTank);
62617         });
62618
62619         timeout(function() {
62620             reveal('.entity-editor-pane',
62621                 t('intro.buildings.close', { button: icon('#icon-apply', 'pre-text') })
62622             );
62623         }, 500);
62624
62625         function continueTo(nextStep) {
62626             context.on('exit.intro', null);
62627             nextStep();
62628         }
62629     }
62630
62631
62632     function rightClickTank() {
62633         if (!tankId) return continueTo(addTank);
62634
62635         context.enter(modeBrowse(context));
62636         context.history().reset('hasTank');
62637         context.map().centerEase(tank, 500);
62638
62639         timeout(function() {
62640             context.on('enter.intro', function(mode) {
62641                 if (mode.id !== 'select') return;
62642                 var ids = context.selectedIDs();
62643                 if (ids.length !== 1 || ids[0] !== tankId) return;
62644
62645                 timeout(function() {
62646                     var node = selectMenuItem('circularize').node();
62647                     if (!node) return;
62648                     continueTo(clickCircle);
62649                 }, 300);  // after menu visible
62650             });
62651
62652             revealTank(tank, t('intro.buildings.rightclick_tank'));
62653
62654             context.map().on('move.intro drawn.intro', function() {
62655                 revealTank(tank, t('intro.buildings.rightclick_tank'), { duration: 0 });
62656             });
62657
62658             context.history().on('change.intro', function() {
62659                 continueTo(rightClickTank);
62660             });
62661
62662         }, 600);
62663
62664         function continueTo(nextStep) {
62665             context.on('enter.intro', null);
62666             context.map().on('move.intro drawn.intro', null);
62667             context.history().on('change.intro', null);
62668             nextStep();
62669         }
62670     }
62671
62672
62673     function clickCircle() {
62674         if (!tankId) return chapter.restart();
62675         var entity = context.hasEntity(tankId);
62676         if (!entity) return continueTo(rightClickTank);
62677
62678         var node = selectMenuItem('circularize').node();
62679         if (!node) { return continueTo(rightClickTank); }
62680
62681         var wasChanged = false;
62682         var menuCoords = context.map().mouseCoordinates();
62683
62684         revealEditMenu(menuCoords,
62685             t('intro.buildings.circle_tank', { button: icon('#operation-circularize', 'pre-text') })
62686         );
62687
62688         context.on('enter.intro', function(mode) {
62689             if (mode.id === 'browse') {
62690                 continueTo(rightClickTank);
62691             } else if (mode.id === 'move' || mode.id === 'rotate') {
62692                 continueTo(retryClickCircle);
62693             }
62694         });
62695
62696         context.map().on('move.intro drawn.intro', function() {
62697             var node = selectMenuItem('circularize').node();
62698             if (!wasChanged && !node) { return continueTo(rightClickTank); }
62699
62700             revealEditMenu(menuCoords,
62701                 t('intro.buildings.circle_tank', { button: icon('#operation-circularize', 'pre-text') }),
62702                 { duration: 0 }
62703             );
62704         });
62705
62706         context.history().on('change.intro', function() {
62707             wasChanged = true;
62708             context.history().on('change.intro', null);
62709
62710             // Something changed.  Wait for transition to complete and check undo annotation.
62711             timeout(function() {
62712                 if (context.history().undoAnnotation() === t('operations.circularize.annotation.area')) {
62713                     continueTo(play);
62714                 } else {
62715                     continueTo(retryClickCircle);
62716                 }
62717             }, 500);  // after transitioned actions
62718         });
62719
62720         function continueTo(nextStep) {
62721             context.on('enter.intro', null);
62722             context.map().on('move.intro drawn.intro', null);
62723             context.history().on('change.intro', null);
62724             nextStep();
62725         }
62726     }
62727
62728
62729     function retryClickCircle() {
62730         context.enter(modeBrowse(context));
62731
62732         revealTank(tank, t('intro.buildings.retry_circle'), {
62733             buttonText: t('intro.ok'),
62734             buttonCallback: function() { continueTo(rightClickTank); }
62735         });
62736
62737         function continueTo(nextStep) {
62738             nextStep();
62739         }
62740     }
62741
62742
62743     function play() {
62744         dispatch$$1.call('done');
62745         reveal('#id-container',
62746             t('intro.buildings.play', { next: t('intro.startediting.title') }), {
62747                 tooltipBox: '.intro-nav-wrap .chapter-startEditing',
62748                 buttonText: t('intro.ok'),
62749                 buttonCallback: function() { reveal('#id-container'); }
62750             }
62751         );
62752     }
62753
62754
62755     chapter.enter = function() {
62756         addHouse();
62757     };
62758
62759
62760     chapter.exit = function() {
62761         timeouts.forEach(window.clearTimeout);
62762         context.on('enter.intro exit.intro', null);
62763         context.map().on('move.intro drawn.intro', null);
62764         context.history().on('change.intro', null);
62765         select('.inspector-wrap').on('wheel.intro', null);
62766         select('.preset-search-input').on('keydown.intro keyup.intro', null);
62767         select('.more-fields .combobox-input').on('click.intro', null);
62768     };
62769
62770
62771     chapter.restart = function() {
62772         chapter.exit();
62773         chapter.enter();
62774     };
62775
62776
62777     return utilRebind(chapter, dispatch$$1, 'on');
62778 }
62779
62780 function uiIntroStartEditing(context, reveal) {
62781     var dispatch$$1 = dispatch('done', 'startEditing'),
62782         modalSelection = select(null);
62783
62784
62785     var chapter = {
62786         title: 'intro.startediting.title'
62787     };
62788
62789
62790     function showHelp() {
62791         reveal('.map-control.help-control',
62792             t('intro.startediting.help', { button: icon('#icon-help', 'pre-text') }), {
62793                 buttonText: t('intro.ok'),
62794                 buttonCallback: function() { showSave(); }
62795             }
62796         );
62797     }
62798
62799     function showSave() {
62800         reveal('#bar button.save',
62801             t('intro.startediting.save'), {
62802                 buttonText: t('intro.ok'),
62803                 buttonCallback: function() { showStart(); }
62804             }
62805         );
62806     }
62807
62808     function showStart() {
62809         modalSelection = uiModal(context.container());
62810
62811         modalSelection.select('.modal')
62812             .attr('class', 'modal-splash modal col6');
62813
62814         modalSelection.selectAll('.close').remove();
62815
62816         var startbutton = modalSelection.select('.content')
62817             .attr('class', 'fillL')
62818             .append('button')
62819                 .attr('class', 'modal-section huge-modal-button')
62820                 .on('click', function() {
62821                     modalSelection.remove();
62822                 });
62823
62824             startbutton
62825                 .append('svg')
62826                 .attr('class', 'illustration')
62827                 .append('use')
62828                 .attr('xlink:href', '#logo-walkthrough');
62829
62830             startbutton
62831                 .append('h2')
62832                 .text(t('intro.startediting.start'));
62833
62834         dispatch$$1.call('startEditing');
62835     }
62836
62837
62838     chapter.enter = function() {
62839         showHelp();
62840     };
62841
62842
62843     chapter.exit = function() {
62844         modalSelection.remove();
62845     };
62846
62847
62848     return utilRebind(chapter, dispatch$$1, 'on');
62849 }
62850
62851 var chapterUi = {
62852     welcome: uiIntroWelcome,
62853     navigation: uiIntroNavigation,
62854     point: uiIntroPoint,
62855     area: uiIntroArea,
62856     line: uiIntroLine,
62857     building: uiIntroBuilding,
62858     startEditing: uiIntroStartEditing
62859 };
62860
62861 var chapterFlow = [
62862     'welcome',
62863     'navigation',
62864     'point',
62865     'area',
62866     'line',
62867     'building',
62868     'startEditing'
62869 ];
62870
62871
62872 function uiIntro(context) {
62873     var introGraph = {},
62874         currChapter;
62875
62876
62877     // create entities for intro graph and localize names
62878     for (var id in dataIntroGraph) {
62879         introGraph[id] = osmEntity$$1(localize(dataIntroGraph[id]));
62880     }
62881
62882
62883     function intro(selection$$1) {
62884         context.enter(modeBrowse(context));
62885
62886         // Save current map state
62887         var history = context.history().toJSON(),
62888             hash = window.location.hash,
62889             center = context.map().center(),
62890             zoom$$1 = context.map().zoom(),
62891             background = context.background().baseLayerSource(),
62892             overlays = context.background().overlayLayerSources(),
62893             opacity = selectAll('#map .layer-background').style('opacity'),
62894             loadedTiles = context.connection().loadedTiles(),
62895             baseEntities = context.history().graph().base().entities,
62896             countryCode = services.geocoder.countryCode;
62897
62898         // Block saving
62899         context.inIntro(true);
62900
62901         // Load semi-real data used in intro
62902         context.connection().toggle(false).reset();
62903         context.history().reset();
62904         context.history().merge(values(coreGraph$$1().load(introGraph).entities));
62905         context.history().checkpoint('initial');
62906         context.background().bing();
62907         overlays.forEach(function (d) { context.background().toggleOverlayLayer(d); });
62908
62909         // Mock geocoder
62910         services.geocoder.countryCode = function(location, callback) {
62911             callback(null, t('intro.graph.countrycode'));
62912         };
62913
62914         selectAll('#map .layer-background').style('opacity', 1);
62915
62916         var curtain = uiCurtain();
62917         selection$$1.call(curtain);
62918
62919         var chapters = chapterFlow.map(function(chapter, i) {
62920             var s = chapterUi[chapter](context, curtain.reveal)
62921                 .on('done', function() {
62922                     context.presets().init();  // clear away "recent" presets
62923
62924                     buttons.filter(function(d) {
62925                         return d.title === s.title;
62926                     }).classed('finished', true);
62927
62928                     if (i < chapterFlow.length - 1) {
62929                         var next = chapterFlow[i + 1];
62930                         select('button.chapter-' + next)
62931                             .classed('next', true);
62932                     }
62933                 });
62934             return s;
62935         });
62936
62937         chapters[chapters.length - 1].on('startEditing', function() {
62938             curtain.remove();
62939             navwrap.remove();
62940             selectAll('#map .layer-background').style('opacity', opacity);
62941             context.connection().toggle(true).reset().loadedTiles(loadedTiles);
62942             context.history().reset().merge(values(baseEntities));
62943             context.background().baseLayerSource(background);
62944             overlays.forEach(function (d) { context.background().toggleOverlayLayer(d); });
62945             if (history) context.history().fromJSON(history, false);
62946             context.map().centerZoom(center, zoom$$1);
62947             window.location.replace(hash);
62948             services.geocoder.countryCode = countryCode;
62949             context.inIntro(false);
62950         });
62951
62952         var navwrap = selection$$1
62953             .append('div')
62954             .attr('class', 'intro-nav-wrap fillD');
62955
62956         navwrap
62957             .append('svg')
62958             .attr('class', 'intro-nav-wrap-logo')
62959             .append('use')
62960             .attr('xlink:href', '#logo-walkthrough');
62961
62962         var buttonwrap = navwrap
62963             .append('div')
62964             .attr('class', 'joined')
62965             .selectAll('button.chapter');
62966
62967         var buttons = buttonwrap
62968             .data(chapters)
62969             .enter()
62970             .append('button')
62971             .attr('class', function(d, i) { return 'chapter chapter-' + chapterFlow[i]; })
62972             .on('click', enterChapter);
62973
62974         buttons
62975             .append('span')
62976             .text(function(d) { return t(d.title); });
62977
62978         buttons
62979             .append('span')
62980             .attr('class', 'status')
62981             .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'));
62982
62983         enterChapter(chapters[0]);
62984
62985
62986         function enterChapter(newChapter) {
62987             if (currChapter) { currChapter.exit(); }
62988             context.enter(modeBrowse(context));
62989
62990             currChapter = newChapter;
62991             currChapter.enter();
62992
62993             buttons
62994                 .classed('next', false)
62995                 .classed('active', function(d) {
62996                     return d.title === currChapter.title;
62997                 });
62998         }
62999     }
63000
63001
63002     return intro;
63003 }
63004
63005 function uiShortcuts() {
63006     var key = '?';
63007     var detected = utilDetect();
63008     var activeTab = 0;
63009     var modalSelection;
63010     var savedSelection;
63011
63012
63013     var keybinding = d3keybinding('shortcuts')
63014         .on([key], function () {
63015             if (selectAll('.modal-shortcuts').size()) {  // already showing
63016                 if (modalSelection) {
63017                     modalSelection.close();
63018                     modalSelection = null;
63019                 }
63020             } else {
63021                 modalSelection = uiModal(savedSelection);
63022                 shortcutsModal(modalSelection);
63023             }
63024         });
63025
63026     select(document)
63027         .call(keybinding);
63028
63029
63030
63031     function shortcutsModal(modalSelection) {
63032         modalSelection.select('.modal')
63033             .classed('modal-shortcuts', true);
63034
63035         var shortcutsModal = modalSelection.select('.content');
63036
63037         shortcutsModal
63038             .append('div')
63039             .attr('class', 'modal-section')
63040             .append('h3')
63041             .text(t('shortcuts.title'));
63042
63043         shortcutsModal
63044             .call(render);
63045     }
63046
63047
63048     function render(selection$$1) {
63049         var wrapper = selection$$1
63050             .selectAll('.wrapper')
63051             .data([0]);
63052
63053         var wrapperEnter = wrapper
63054             .enter()
63055             .append('div')
63056             .attr('class', 'wrapper modal-section');
63057
63058         var tabsBar = wrapperEnter
63059             .append('div')
63060             .attr('class', 'tabs-bar');
63061
63062         var shortcutsList = wrapperEnter
63063             .append('div')
63064             .attr('class', 'shortcuts-list');
63065
63066         wrapper = wrapper.merge(wrapperEnter);
63067
63068         var tabs = tabsBar
63069             .selectAll('.tab')
63070             .data(dataShortcuts);
63071
63072         var tabsEnter = tabs
63073             .enter()
63074             .append('div')
63075             .attr('class', 'tab')
63076             .on('click', function (d, i) {
63077                 activeTab = i;
63078                 render(selection$$1);
63079             });
63080
63081         tabsEnter
63082             .append('span')
63083             .text(function (d) { return t(d.text); });
63084
63085         tabs = tabs
63086             .merge(tabsEnter);
63087
63088         // Update
63089         wrapper.selectAll('.tab')
63090             .classed('active', function (d, i) {
63091                 return i === activeTab;
63092             });
63093
63094
63095         var shortcuts = shortcutsList
63096             .selectAll('.shortcut-tab')
63097             .data(dataShortcuts);
63098
63099         var shortcutsEnter = shortcuts
63100             .enter()
63101             .append('div')
63102             .attr('class', 'shortcut-tab');
63103
63104         var columnsEnter = shortcutsEnter
63105             .selectAll('.shortcut-column')
63106             .data(function (d) { return d.columns; })
63107             .enter()
63108             .append('table')
63109             .attr('class', 'shortcut-column');
63110
63111         var rowsEnter = columnsEnter
63112             .selectAll('.shortcut-row')
63113             .data(function (d) { return d.rows; })
63114             .enter()
63115             .append('tr')
63116             .attr('class', 'shortcut-row');
63117
63118
63119         var sectionRows = rowsEnter
63120             .filter(function (d) { return !d.shortcuts; });
63121
63122         sectionRows
63123             .append('td');
63124
63125         sectionRows
63126             .append('td')
63127             .attr('class', 'shortcut-section')
63128             .append('h3')
63129             .text(function (d) { return t(d.text); });
63130
63131
63132         var shortcutRows = rowsEnter
63133             .filter(function (d) { return d.shortcuts; });
63134
63135         var shortcutKeys = shortcutRows
63136             .append('td')
63137             .attr('class', 'shortcut-keys');
63138
63139         var modifierKeys = shortcutKeys
63140             .filter(function (d) { return d.modifiers; });
63141
63142         modifierKeys
63143             .selectAll('kbd.modifier')
63144             .data(function (d) {
63145                 if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
63146                     return ['⌘'];
63147                 } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
63148                     return [];
63149                 } else {
63150                     return d.modifiers;
63151                 }
63152             })
63153             .enter()
63154             .each(function () {
63155                 var selection$$1 = select(this);
63156
63157                 selection$$1
63158                     .append('kbd')
63159                     .attr('class', 'modifier')
63160                     .text(function (d) { return uiCmd.display(d); });
63161
63162                 selection$$1
63163                     .append('span')
63164                     .text('+');
63165             });
63166
63167
63168         shortcutKeys
63169             .selectAll('kbd.shortcut')
63170             .data(function (d) {
63171                 var arr = d.shortcuts;
63172                 if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
63173                     arr = ['Y'];
63174                 } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
63175                     arr = ['F11'];
63176                 }
63177
63178                 return arr.map(function(s) {
63179                     return {
63180                         shortcut: s,
63181                         separator: d.separator
63182                     };
63183                 });
63184             })
63185             .enter()
63186             .each(function (d, i, nodes) {
63187                 var selection$$1 = select(this);
63188                 var click = d.shortcut.toLowerCase().match(/(.*).click/);
63189
63190                 if (click && click[1]) {
63191                     selection$$1
63192                         .call(svgIcon('#walkthrough-mouse', 'mouseclick', click[1]));
63193                 } else {
63194                     selection$$1
63195                         .append('kbd')
63196                         .attr('class', 'shortcut')
63197                         .text(function (d) {
63198                             var key = d.shortcut;
63199                             return key.indexOf('.') !== -1 ? uiCmd.display(t(key)) : uiCmd.display(key);
63200                         });
63201                 }
63202
63203                 if (i < nodes.length - 1) {
63204                     selection$$1
63205                         .append('span')
63206                         .text(d.separator || '\u00a0' + t('shortcuts.or') + '\u00a0');
63207                 }
63208             });
63209
63210
63211         shortcutKeys
63212             .filter(function(d) { return d.gesture; })
63213             .each(function () {
63214                 var selection$$1 = select(this);
63215
63216                 selection$$1
63217                     .append('span')
63218                     .text('+');
63219
63220                 selection$$1
63221                     .append('span')
63222                     .attr('class', 'gesture')
63223                     .text(function (d) { return t(d.gesture); });
63224             });
63225
63226
63227         shortcutRows
63228             .append('td')
63229             .attr('class', 'shortcut-desc')
63230             .text(function (d) { return d.text ? t(d.text) : '\u00a0'; });
63231
63232
63233         shortcuts = shortcuts
63234             .merge(shortcutsEnter);
63235
63236         // Update
63237         wrapper.selectAll('.shortcut-tab')
63238             .style('display', function (d, i) {
63239                 return i === activeTab ? 'flex' : 'none';
63240             });
63241     }
63242
63243
63244     return function(selection$$1, show) {
63245         savedSelection = selection$$1;
63246         if (show) {
63247             modalSelection = uiModal(selection$$1);
63248             shortcutsModal(modalSelection);
63249         }
63250     };
63251 }
63252
63253 function uiHelp(context) {
63254     var key = 'H';
63255
63256     var docKeys = [
63257         'help.help',
63258         'help.editing_saving',
63259         'help.roads',
63260         'help.gps',
63261         'help.imagery',
63262         'help.addresses',
63263         'help.inspector',
63264         'help.buildings',
63265         'help.relations'];
63266
63267     var docs = docKeys.map(function(key) {
63268         var text$$1 = t(key);
63269         return {
63270             title: text$$1.split('\n')[0].replace('#', '').trim(),
63271             html: marked(text$$1.split('\n').slice(1).join('\n'))
63272         };
63273     });
63274
63275
63276     function help(selection$$1) {
63277
63278         function hide() {
63279             setVisible(false);
63280         }
63281
63282
63283         function toggle() {
63284             if (event) event.preventDefault();
63285             tooltipBehavior.hide(button);
63286             setVisible(!button.classed('active'));
63287         }
63288
63289
63290         function setVisible(show) {
63291             if (show !== shown) {
63292                 button.classed('active', show);
63293                 shown = show;
63294
63295                 if (show) {
63296                     selection$$1.on('mousedown.help-inside', function() {
63297                         return event.stopPropagation();
63298                     });
63299                     pane.style('display', 'block')
63300                         .style('right', '-500px')
63301                         .transition()
63302                         .duration(200)
63303                         .style('right', '0px');
63304                 } else {
63305                     pane.style('right', '0px')
63306                         .transition()
63307                         .duration(200)
63308                         .style('right', '-500px')
63309                         .on('end', function() {
63310                             select(this).style('display', 'none');
63311                         });
63312                     selection$$1.on('mousedown.help-inside', null);
63313                 }
63314             }
63315         }
63316
63317
63318         function clickHelp(d, i) {
63319             var rtl = (textDirection === 'rtl');
63320             pane.property('scrollTop', 0);
63321             doctitle.html(d.title);
63322
63323             body.html(d.html);
63324             body.selectAll('a')
63325                 .attr('target', '_blank');
63326             menuItems.classed('selected', function(m) {
63327                 return m.title === d.title;
63328             });
63329
63330             nav.html('');
63331             if (rtl) {
63332                 nav.call(drawNext).call(drawPrevious);
63333             } else {
63334                 nav.call(drawPrevious).call(drawNext);
63335             }
63336
63337
63338             function drawNext(selection$$1) {
63339                 if (i < docs.length - 1) {
63340                     var nextLink = selection$$1
63341                         .append('a')
63342                         .attr('class', 'next')
63343                         .on('click', function() {
63344                             clickHelp(docs[i + 1], i + 1);
63345                         });
63346
63347                     nextLink
63348                         .append('span')
63349                         .text(docs[i + 1].title)
63350                         .call(svgIcon((rtl ? '#icon-backward' : '#icon-forward'), 'inline'));
63351                 }
63352             }
63353
63354
63355             function drawPrevious(selection$$1) {
63356                 if (i > 0) {
63357                     var prevLink = selection$$1
63358                         .append('a')
63359                         .attr('class', 'previous')
63360                         .on('click', function() {
63361                             clickHelp(docs[i - 1], i - 1);
63362                         });
63363
63364                     prevLink
63365                         .call(svgIcon((rtl ? '#icon-forward' : '#icon-backward'), 'inline'))
63366                         .append('span')
63367                         .text(docs[i - 1].title);
63368                 }
63369             }
63370         }
63371
63372
63373         function clickWalkthrough() {
63374             if (context.inIntro()) return;
63375             context.container().call(uiIntro(context));
63376             setVisible(false);
63377         }
63378
63379
63380         function clickShortcuts() {
63381             context.container().call(uiShortcuts(context), true);
63382         }
63383
63384
63385         var pane = selection$$1.append('div')
63386                 .attr('class', 'help-wrap map-overlay fillL col5 content hide'),
63387             tooltipBehavior = tooltip()
63388                 .placement((textDirection === 'rtl') ? 'right' : 'left')
63389                 .html(true)
63390                 .title(uiTooltipHtml(t('help.title'), key)),
63391             button = selection$$1.append('button')
63392                 .attr('tabindex', -1)
63393                 .on('click', toggle)
63394                 .call(svgIcon('#icon-help', 'light'))
63395                 .call(tooltipBehavior),
63396             shown = false;
63397
63398
63399         var toc = pane.append('ul')
63400             .attr('class', 'toc');
63401
63402         var menuItems = toc.selectAll('li')
63403             .data(docs)
63404             .enter()
63405             .append('li')
63406             .append('a')
63407             .html(function(d) { return d.title; })
63408             .on('click', clickHelp);
63409
63410         var shortcuts = toc
63411             .append('li')
63412             .attr('class', 'shortcuts')
63413             .call(tooltip()
63414                 .html(true)
63415                 .title(uiTooltipHtml(t('shortcuts.tooltip'), '?'))
63416                 .placement('top')
63417             )
63418             .append('a')
63419             .on('click', clickShortcuts);
63420
63421         shortcuts
63422             .append('div')
63423             .text(t('shortcuts.title'));
63424
63425         var walkthrough = toc
63426             .append('li')
63427             .attr('class', 'walkthrough')
63428             .append('a')
63429             .on('click', clickWalkthrough);
63430
63431         walkthrough
63432             .append('svg')
63433             .attr('class', 'logo logo-walkthrough')
63434             .append('use')
63435             .attr('xlink:href', '#logo-walkthrough');
63436
63437         walkthrough
63438             .append('div')
63439             .text(t('splash.walkthrough'));
63440
63441
63442         var content = pane.append('div')
63443             .attr('class', 'left-content');
63444
63445         var doctitle = content.append('h2')
63446             .text(t('help.title'));
63447
63448         var body = content.append('div')
63449             .attr('class', 'body');
63450
63451         var nav = content.append('div')
63452             .attr('class', 'nav');
63453
63454         clickHelp(docs[0], 0);
63455
63456         var keybinding = d3keybinding('help')
63457             .on(key, toggle)
63458             .on('B', hide)
63459             .on('F', hide);
63460
63461         select(document)
63462             .call(keybinding);
63463
63464         context.surface().on('mousedown.help-outside', hide);
63465         context.container().on('mousedown.help-outside', hide);
63466     }
63467
63468     return help;
63469 }
63470
63471 function uiInfo(context) {
63472     var key = uiCmd('⌘I'),
63473         isImperial = (utilDetect().locale.toLowerCase() === 'en-us'),
63474         isHidden = true;
63475
63476
63477     function info(selection$$1) {
63478
63479         function radiansToMeters(r) {
63480             // using WGS84 authalic radius (6371007.1809 m)
63481             return r * 6371007.1809;
63482         }
63483
63484         function steradiansToSqmeters(r) {
63485             // http://gis.stackexchange.com/a/124857/40446
63486             return r / (4 * Math.PI) * 510065621724000;
63487         }
63488
63489
63490         function toLineString(feature) {
63491             if (feature.type === 'LineString') return feature;
63492
63493             var result = { type: 'LineString', coordinates: [] };
63494             if (feature.type === 'Polygon') {
63495                 result.coordinates = feature.coordinates[0];
63496             } else if (feature.type === 'MultiPolygon') {
63497                 result.coordinates = feature.coordinates[0][0];
63498             }
63499
63500             return result;
63501         }
63502
63503
63504         function displayLength(m) {
63505             var d = m * (isImperial ? 3.28084 : 1),
63506                 p, unit;
63507
63508             if (isImperial) {
63509                 if (d >= 5280) {
63510                     d /= 5280;
63511                     unit = 'mi';
63512                 } else {
63513                     unit = 'ft';
63514                 }
63515             } else {
63516                 if (d >= 1000) {
63517                     d /= 1000;
63518                     unit = 'km';
63519                 } else {
63520                     unit = 'm';
63521                 }
63522             }
63523
63524             // drop unnecessary precision
63525             p = d > 1000 ? 0 : d > 100 ? 1 : 2;
63526
63527             return String(d.toFixed(p)) + ' ' + unit;
63528         }
63529
63530
63531         function displayArea(m2) {
63532             var d = m2 * (isImperial ? 10.7639111056 : 1),
63533                 d1, d2, p1, p2, unit1, unit2;
63534
63535             if (isImperial) {
63536                 if (d >= 6969600) {     // > 0.25mi² show mi²
63537                     d1 = d / 27878400;
63538                     unit1 = 'mi²';
63539                 } else {
63540                     d1 = d;
63541                     unit1 = 'ft²';
63542                 }
63543
63544                 if (d > 4356 && d < 43560000) {   // 0.1 - 1000 acres
63545                     d2 = d / 43560;
63546                     unit2 = 'ac';
63547                 }
63548
63549             } else {
63550                 if (d >= 250000) {    // > 0.25km² show km²
63551                     d1 = d / 1000000;
63552                     unit1 = 'km²';
63553                 } else {
63554                     d1 = d;
63555                     unit1 = 'm²';
63556                 }
63557
63558                 if (d > 1000 && d < 10000000) {   // 0.1 - 1000 hectares
63559                     d2 = d / 10000;
63560                     unit2 = 'ha';
63561                 }
63562             }
63563
63564             // drop unnecessary precision
63565             p1 = d1 > 1000 ? 0 : d1 > 100 ? 1 : 2;
63566             p2 = d2 > 1000 ? 0 : d2 > 100 ? 1 : 2;
63567
63568             return String(d1.toFixed(p1)) + ' ' + unit1 +
63569                 (d2 ? ' (' + String(d2.toFixed(p2)) + ' ' + unit2 + ')' : '');
63570         }
63571
63572
63573         function redraw() {
63574             if (isHidden) return;
63575
63576             var resolver = context.graph(),
63577                 selected = lodash.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
63578                 singular = selected.length === 1 ? selected[0] : null,
63579                 extent$$1 = geoExtent$$1(),
63580                 entity;
63581
63582             wrap.html('');
63583             wrap.append('h4')
63584                 .attr('class', 'infobox-heading fillD')
63585                 .text(singular || t('infobox.selected', { n: selected.length }));
63586
63587             if (!selected.length) return;
63588
63589             var center;
63590             for (var i = 0; i < selected.length; i++) {
63591                 entity = context.entity(selected[i]);
63592                 extent$$1._extend(entity.extent(resolver));
63593             }
63594             center = extent$$1.center();
63595
63596
63597             var list = wrap.append('ul');
63598
63599             // multiple features, just display extent center..
63600             if (!singular) {
63601                 list.append('li')
63602                     .text(t('infobox.center') + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
63603                 return;
63604             }
63605
63606             // single feature, display details..
63607             if (!entity) return;
63608             var geometry = entity.geometry(resolver);
63609
63610             if (geometry === 'line' || geometry === 'area') {
63611                 var closed = (entity.type === 'relation') || (entity.isClosed() && !entity.isDegenerate()),
63612                     feature = entity.asGeoJSON(resolver),
63613                     length = radiansToMeters(d3GeoLength(toLineString(feature))),
63614                     lengthLabel = t('infobox.' + (closed ? 'perimeter' : 'length')),
63615                     centroid = d3GeoCentroid(feature);
63616
63617                 list.append('li')
63618                     .text(t('infobox.geometry') + ': ' +
63619                         (closed ? t('infobox.closed') + ' ' : '') + t('geometry.' + geometry) );
63620
63621                 if (closed) {
63622                     var area$$1 = steradiansToSqmeters(entity.area(resolver));
63623                     list.append('li')
63624                         .text(t('infobox.area') + ': ' + displayArea(area$$1));
63625                 }
63626
63627                 list.append('li')
63628                     .text(lengthLabel + ': ' + displayLength(length));
63629
63630                 list.append('li')
63631                     .text(t('infobox.centroid') + ': ' + centroid[0].toFixed(5) + ', ' + centroid[1].toFixed(5));
63632
63633
63634                 var toggle  = isImperial ? 'imperial' : 'metric';
63635                 wrap.append('a')
63636                     .text(t('infobox.' + toggle))
63637                     .attr('href', '#')
63638                     .attr('class', 'button')
63639                     .on('click', function() {
63640                         event.preventDefault();
63641                         isImperial = !isImperial;
63642                         redraw();
63643                     });
63644
63645             } else {
63646                 var centerLabel = t('infobox.' + (entity.type === 'node' ? 'location' : 'center'));
63647
63648                 list.append('li')
63649                     .text(t('infobox.geometry') + ': ' + t('geometry.' + geometry));
63650
63651                 list.append('li')
63652                     .text(centerLabel + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
63653             }
63654         }
63655
63656
63657         function toggle() {
63658             if (event) {
63659                 event.preventDefault();
63660             }
63661
63662             isHidden = !isHidden;
63663
63664             if (isHidden) {
63665                 wrap
63666                     .style('display', 'block')
63667                     .style('opacity', 1)
63668                     .transition()
63669                     .duration(200)
63670                     .style('opacity', 0)
63671                     .on('end', function() {
63672                         select(this).style('display', 'none');
63673                     });
63674             } else {
63675                 wrap
63676                     .style('display', 'block')
63677                     .style('opacity', 0)
63678                     .transition()
63679                     .duration(200)
63680                     .style('opacity', 1)
63681                     .on('end', function() {
63682                         redraw();
63683                     });
63684             }
63685         }
63686
63687
63688         var wrap = selection$$1.selectAll('.infobox')
63689             .data([0]);
63690
63691         wrap = wrap.enter()
63692             .append('div')
63693             .attr('class', 'infobox fillD2')
63694             .style('display', (isHidden ? 'none' : 'block'))
63695             .merge(wrap);
63696
63697         context.map()
63698             .on('drawn.info', redraw);
63699
63700         redraw();
63701
63702         var keybinding = d3keybinding('info')
63703             .on(key, toggle);
63704
63705         select(document)
63706             .call(keybinding);
63707     }
63708
63709     return info;
63710 }
63711
63712 function uiMapData(context) {
63713     var key = 'F',
63714         features = context.features().keys(),
63715         layers = context.layers(),
63716         fills = ['wireframe', 'partial', 'full'],
63717         fillDefault = context.storage('area-fill') || 'partial',
63718         fillSelected = fillDefault;
63719
63720
63721     function map_data(selection$$1) {
63722
63723         function showsFeature(d) {
63724             return context.features().enabled(d);
63725         }
63726
63727
63728         function autoHiddenFeature(d) {
63729             return context.features().autoHidden(d);
63730         }
63731
63732
63733         function clickFeature(d) {
63734             context.features().toggle(d);
63735             update();
63736         }
63737
63738
63739         function showsFill(d) {
63740             return fillSelected === d;
63741         }
63742
63743
63744         function setFill(d) {
63745             lodash.each(fills, function(opt) {
63746                 context.surface().classed('fill-' + opt, Boolean(opt === d));
63747             });
63748
63749             fillSelected = d;
63750             if (d !== 'wireframe') {
63751                 fillDefault = d;
63752                 context.storage('area-fill', d);
63753             }
63754             update();
63755         }
63756
63757
63758         function showsLayer(which) {
63759             var layer = layers.layer(which);
63760             if (layer) {
63761                 return layer.enabled();
63762             }
63763             return false;
63764         }
63765
63766
63767         function setLayer(which, enabled) {
63768             var layer = layers.layer(which);
63769             if (layer) {
63770                 layer.enabled(enabled);
63771                 update();
63772             }
63773         }
63774
63775
63776         function toggleLayer(which) {
63777             setLayer(which, !showsLayer(which));
63778         }
63779
63780
63781         function clickGpx() {
63782             toggleLayer('gpx');
63783         }
63784
63785
63786         function clickMapillaryImages() {
63787             toggleLayer('mapillary-images');
63788             if (!showsLayer('mapillary-images')) {
63789                 setLayer('mapillary-signs', false);
63790             }
63791         }
63792
63793
63794         function clickMapillarySigns() {
63795             toggleLayer('mapillary-signs');
63796         }
63797
63798
63799         function drawMapillaryItems(selection$$1) {
63800             var mapillaryImages = layers.layer('mapillary-images'),
63801                 mapillarySigns = layers.layer('mapillary-signs'),
63802                 supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
63803                 supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
63804                 showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
63805                 showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
63806
63807             var mapillaryList = selection$$1
63808                 .selectAll('.layer-list-mapillary')
63809                 .data([0]);
63810
63811             mapillaryList = mapillaryList.enter()
63812                 .append('ul')
63813                 .attr('class', 'layer-list layer-list-mapillary')
63814                 .merge(mapillaryList);
63815
63816
63817             var mapillaryImageLayerItem = mapillaryList
63818                 .selectAll('.list-item-mapillary-images')
63819                 .data(supportsMapillaryImages ? [0] : []);
63820
63821             mapillaryImageLayerItem.exit()
63822                 .remove();
63823
63824             var enterImages = mapillaryImageLayerItem.enter()
63825                 .append('li')
63826                 .attr('class', 'list-item-mapillary-images');
63827
63828             var labelImages = enterImages
63829                 .append('label')
63830                 .call(tooltip()
63831                     .title(t('mapillary_images.tooltip'))
63832                     .placement('top'));
63833
63834             labelImages
63835                 .append('input')
63836                 .attr('type', 'checkbox')
63837                 .on('change', clickMapillaryImages);
63838
63839             labelImages
63840                 .append('span')
63841                 .text(t('mapillary_images.title'));
63842
63843
63844             var mapillarySignLayerItem = mapillaryList
63845                 .selectAll('.list-item-mapillary-signs')
63846                 .data(supportsMapillarySigns ? [0] : []);
63847
63848             mapillarySignLayerItem.exit()
63849                 .remove();
63850
63851             var enterSigns = mapillarySignLayerItem.enter()
63852                 .append('li')
63853                 .attr('class', 'list-item-mapillary-signs');
63854
63855             var labelSigns = enterSigns
63856                 .append('label')
63857                 .call(tooltip()
63858                     .title(t('mapillary_signs.tooltip'))
63859                     .placement('top'));
63860
63861             labelSigns
63862                 .append('input')
63863                 .attr('type', 'checkbox')
63864                 .on('change', clickMapillarySigns);
63865
63866             labelSigns
63867                 .append('span')
63868                 .text(t('mapillary_signs.title'));
63869
63870
63871             // Updates
63872             mapillaryImageLayerItem = mapillaryImageLayerItem
63873                 .merge(enterImages);
63874
63875             mapillaryImageLayerItem
63876                 .classed('active', showsMapillaryImages)
63877                 .selectAll('input')
63878                 .property('checked', showsMapillaryImages);
63879
63880
63881             mapillarySignLayerItem = mapillarySignLayerItem
63882                 .merge(enterSigns);
63883
63884             mapillarySignLayerItem
63885                 .classed('active', showsMapillarySigns)
63886                 .selectAll('input')
63887                 .property('disabled', !showsMapillaryImages)
63888                 .property('checked', showsMapillarySigns);
63889
63890             mapillarySignLayerItem
63891                 .selectAll('label')
63892                 .classed('deemphasize', !showsMapillaryImages);
63893         }
63894
63895
63896         function drawGpxItem(selection$$1) {
63897             var gpx = layers.layer('gpx'),
63898                 hasGpx = gpx && gpx.hasGpx(),
63899                 showsGpx = hasGpx && gpx.enabled();
63900
63901             var gpxLayerItem = selection$$1
63902                 .selectAll('.layer-list-gpx')
63903                 .data(gpx ? [0] : []);
63904
63905             // Exit
63906             gpxLayerItem.exit()
63907                 .remove();
63908
63909             // Enter
63910             var enter = gpxLayerItem.enter()
63911                 .append('ul')
63912                 .attr('class', 'layer-list layer-list-gpx')
63913                 .append('li')
63914                 .classed('list-item-gpx', true);
63915
63916             enter
63917                 .append('button')
63918                 .attr('class', 'list-item-gpx-extent')
63919                 .call(tooltip()
63920                     .title(t('gpx.zoom'))
63921                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
63922                 .on('click', function() {
63923                     event.preventDefault();
63924                     event.stopPropagation();
63925                     gpx.fitZoom();
63926                 })
63927                 .call(svgIcon('#icon-search'));
63928
63929             enter
63930                 .append('button')
63931                 .attr('class', 'list-item-gpx-browse')
63932                 .call(tooltip()
63933                     .title(t('gpx.browse'))
63934                     .placement((textDirection === 'rtl') ? 'right' : 'left'))
63935                 .on('click', function() {
63936                     select(document.createElement('input'))
63937                         .attr('type', 'file')
63938                         .on('change', function() {
63939                             gpx.files(event.target.files);
63940                         })
63941                         .node().click();
63942                 })
63943                 .call(svgIcon('#icon-geolocate'));
63944
63945             var labelGpx = enter
63946                 .append('label')
63947                 .call(tooltip().title(t('gpx.drag_drop')).placement('top'));
63948
63949             labelGpx
63950                 .append('input')
63951                 .attr('type', 'checkbox')
63952                 .on('change', clickGpx);
63953
63954             labelGpx
63955                 .append('span')
63956                 .text(t('gpx.local_layer'));
63957
63958
63959             // Update
63960             gpxLayerItem = gpxLayerItem
63961                 .merge(enter);
63962
63963             gpxLayerItem
63964                 .classed('active', showsGpx)
63965                 .selectAll('input')
63966                 .property('disabled', !hasGpx)
63967                 .property('checked', showsGpx);
63968
63969             gpxLayerItem
63970                 .selectAll('label')
63971                 .classed('deemphasize', !hasGpx);
63972         }
63973
63974
63975         function drawList(selection$$1, data, type, name, change, active$$1) {
63976             var items = selection$$1.selectAll('li')
63977                 .data(data);
63978
63979             // Exit
63980             items.exit()
63981                 .remove();
63982
63983             // Enter
63984             var enter = items.enter()
63985                 .append('li')
63986                 .attr('class', 'layer')
63987                 .call(tooltip()
63988                     .html(true)
63989                     .title(function(d) {
63990                         var tip = t(name + '.' + d + '.tooltip'),
63991                             key = (d === 'wireframe' ? 'W' : null);
63992
63993                         if (name === 'feature' && autoHiddenFeature(d)) {
63994                             tip += '<div>' + t('map_data.autohidden') + '</div>';
63995                         }
63996                         return uiTooltipHtml(tip, key);
63997                     })
63998                     .placement('top')
63999                 );
64000
64001             var label = enter
64002                 .append('label');
64003
64004             label
64005                 .append('input')
64006                 .attr('type', type)
64007                 .attr('name', name)
64008                 .on('change', change);
64009
64010             label
64011                 .append('span')
64012                 .text(function(d) { return t(name + '.' + d + '.description'); });
64013
64014             // Update
64015             items = items
64016                 .merge(enter);
64017
64018             items
64019                 .classed('active', active$$1)
64020                 .selectAll('input')
64021                 .property('checked', active$$1)
64022                 .property('indeterminate', function(d) {
64023                     return (name === 'feature' && autoHiddenFeature(d));
64024                 });
64025         }
64026
64027
64028         function update() {
64029             dataLayerContainer.call(drawMapillaryItems);
64030             dataLayerContainer.call(drawGpxItem);
64031
64032             fillList.call(drawList, fills, 'radio', 'area_fill', setFill, showsFill);
64033             featureList.call(drawList, features, 'checkbox', 'feature', clickFeature, showsFeature);
64034         }
64035
64036
64037         function hidePanel() {
64038             setVisible(false);
64039         }
64040
64041
64042         function togglePanel() {
64043             if (event) event.preventDefault();
64044             tooltipBehavior.hide(button);
64045             setVisible(!button.classed('active'));
64046         }
64047
64048
64049         function toggleWireframe() {
64050             if (event) {
64051                 event.preventDefault();
64052                 event.stopPropagation();
64053             }
64054             setFill((fillSelected === 'wireframe' ? fillDefault : 'wireframe'));
64055             context.map().pan([0,0]);  // trigger a redraw
64056         }
64057
64058
64059         function setVisible(show) {
64060             if (show !== shown) {
64061                 button.classed('active', show);
64062                 shown = show;
64063
64064                 if (show) {
64065                     update();
64066                     selection$$1.on('mousedown.map_data-inside', function() {
64067                         return event.stopPropagation();
64068                     });
64069                     content.style('display', 'block')
64070                         .style('right', '-300px')
64071                         .transition()
64072                         .duration(200)
64073                         .style('right', '0px');
64074                 } else {
64075                     content.style('display', 'block')
64076                         .style('right', '0px')
64077                         .transition()
64078                         .duration(200)
64079                         .style('right', '-300px')
64080                         .on('end', function() {
64081                             select(this).style('display', 'none');
64082                         });
64083                     selection$$1.on('mousedown.map_data-inside', null);
64084                 }
64085             }
64086         }
64087
64088
64089         var content = selection$$1
64090                 .append('div')
64091                 .attr('class', 'fillL map-overlay col3 content hide'),
64092             tooltipBehavior = tooltip()
64093                 .placement((textDirection === 'rtl') ? 'right' : 'left')
64094                 .html(true)
64095                 .title(uiTooltipHtml(t('map_data.description'), key)),
64096             button = selection$$1
64097                 .append('button')
64098                 .attr('tabindex', -1)
64099                 .on('click', togglePanel)
64100                 .call(svgIcon('#icon-data', 'light'))
64101                 .call(tooltipBehavior),
64102             shown = false;
64103
64104         content
64105             .append('h4')
64106             .text(t('map_data.title'));
64107
64108
64109         // data layers
64110         content
64111             .append('a')
64112             .text(t('map_data.data_layers'))
64113             .attr('href', '#')
64114             .classed('hide-toggle', true)
64115             .classed('expanded', true)
64116             .on('click', function() {
64117                 var exp = select(this).classed('expanded');
64118                 dataLayerContainer.style('display', exp ? 'none' : 'block');
64119                 select(this).classed('expanded', !exp);
64120                 event.preventDefault();
64121             });
64122
64123         var dataLayerContainer = content
64124             .append('div')
64125             .attr('class', 'data-data-layers')
64126             .style('display', 'block');
64127
64128
64129         // area fills
64130         content
64131             .append('a')
64132             .text(t('map_data.fill_area'))
64133             .attr('href', '#')
64134             .classed('hide-toggle', true)
64135             .classed('expanded', false)
64136             .on('click', function() {
64137                 var exp = select(this).classed('expanded');
64138                 fillContainer.style('display', exp ? 'none' : 'block');
64139                 select(this).classed('expanded', !exp);
64140                 event.preventDefault();
64141             });
64142
64143         var fillContainer = content
64144             .append('div')
64145             .attr('class', 'data-area-fills')
64146             .style('display', 'none');
64147
64148         var fillList = fillContainer
64149             .append('ul')
64150             .attr('class', 'layer-list layer-fill-list');
64151
64152
64153         // feature filters
64154         content
64155             .append('a')
64156             .text(t('map_data.map_features'))
64157             .attr('href', '#')
64158             .classed('hide-toggle', true)
64159             .classed('expanded', false)
64160             .on('click', function() {
64161                 var exp = select(this).classed('expanded');
64162                 featureContainer.style('display', exp ? 'none' : 'block');
64163                 select(this).classed('expanded', !exp);
64164                 event.preventDefault();
64165             });
64166
64167         var featureContainer = content
64168             .append('div')
64169             .attr('class', 'data-feature-filters')
64170             .style('display', 'none');
64171
64172         var featureList = featureContainer
64173             .append('ul')
64174             .attr('class', 'layer-list layer-feature-list');
64175
64176
64177         context.features()
64178             .on('change.map_data-update', update);
64179
64180         setFill(fillDefault);
64181
64182         var keybinding = d3keybinding('features')
64183             .on(key, togglePanel)
64184             .on('W', toggleWireframe)
64185             .on('B', hidePanel)
64186             .on('H', hidePanel);
64187
64188         select(document)
64189             .call(keybinding);
64190
64191         context.surface().on('mousedown.map_data-outside', hidePanel);
64192         context.container().on('mousedown.map_data-outside', hidePanel);
64193     }
64194
64195
64196     return map_data;
64197 }
64198
64199 function uiModes(context) {
64200     var modes = [
64201         modeAddPoint$$1(context),
64202         modeAddLine$$1(context),
64203         modeAddArea$$1(context)
64204     ];
64205
64206
64207     function editable() {
64208         return context.editable() && context.mode().id !== 'save';
64209     }
64210
64211
64212     return function(selection$$1) {
64213         var buttons = selection$$1.selectAll('button.add-button')
64214             .data(modes);
64215
64216         buttons = buttons.enter()
64217             .append('button')
64218             .attr('tabindex', -1)
64219             .attr('class', function(mode) { return mode.id + ' add-button col4'; })
64220             .on('click.mode-buttons', function(mode) {
64221                 if (mode.id === context.mode().id) {
64222                     context.enter(modeBrowse(context));
64223                 } else {
64224                     context.enter(mode);
64225                 }
64226             })
64227             .call(tooltip()
64228                 .placement('bottom')
64229                 .html(true)
64230                 .title(function(mode) {
64231                     return uiTooltipHtml(mode.description, mode.key);
64232                 })
64233             );
64234
64235         context.map()
64236             .on('move.modes', lodash.debounce(update, 500));
64237
64238         context
64239             .on('enter.modes', update);
64240
64241         buttons
64242             .each(function(d) {
64243                 select(this)
64244                     .call(svgIcon('#icon-' + d.button, 'pre-text'));
64245             });
64246
64247         buttons
64248             .append('span')
64249             .attr('class', 'label')
64250             .text(function(mode) { return mode.title; });
64251
64252         context
64253             .on('enter.editor', function(entered) {
64254                 selection$$1.selectAll('button.add-button')
64255                     .classed('active', function(mode) { return entered.button === mode.button; });
64256                 context.container()
64257                     .classed('mode-' + entered.id, true);
64258             });
64259
64260         context
64261             .on('exit.editor', function(exited) {
64262                 context.container()
64263                     .classed('mode-' + exited.id, false);
64264             });
64265
64266         var keybinding = d3keybinding('mode-buttons');
64267
64268         modes.forEach(function(mode) {
64269             keybinding.on(mode.key, function() {
64270                 if (editable()) {
64271                     if (mode.id === context.mode().id) {
64272                         context.enter(modeBrowse(context));
64273                     } else {
64274                         context.enter(mode);
64275                     }
64276                 }
64277             });
64278         });
64279
64280         select(document)
64281             .call(keybinding);
64282
64283
64284         function update() {
64285             selection$$1.selectAll('button.add-button')
64286                 .property('disabled', !editable());
64287         }
64288     };
64289 }
64290
64291 function uiRestore(context) {
64292
64293     return function(selection) {
64294         if (!context.history().lock() || !context.history().restorableChanges())
64295             return;
64296
64297         var modalSelection = uiModal(selection, true);
64298
64299         modalSelection.select('.modal')
64300             .attr('class', 'modal fillL col6');
64301
64302         var introModal = modalSelection.select('.content');
64303
64304         introModal
64305             .attr('class','cf');
64306
64307         introModal
64308             .append('div')
64309             .attr('class', 'modal-section')
64310             .append('h3')
64311             .text(t('restore.heading'));
64312
64313         introModal
64314             .append('div')
64315             .attr('class','modal-section')
64316             .append('p')
64317             .text(t('restore.description'));
64318
64319         var buttonWrap = introModal
64320             .append('div')
64321             .attr('class', 'modal-actions cf');
64322
64323         var restore = buttonWrap
64324             .append('button')
64325             .attr('class', 'restore col6')
64326             .on('click', function() {
64327                 context.history().restore();
64328                 modalSelection.remove();
64329             });
64330
64331         restore
64332             .append('svg')
64333             .attr('class', 'logo logo-restore')
64334             .append('use')
64335             .attr('xlink:href', '#logo-restore');
64336
64337         restore
64338             .append('div')
64339             .text(t('restore.restore'));
64340
64341         var reset = buttonWrap
64342             .append('button')
64343             .attr('class', 'reset col6')
64344             .on('click', function() {
64345                 context.history().clearSaved();
64346                 modalSelection.remove();
64347             });
64348
64349         reset
64350             .append('svg')
64351             .attr('class', 'logo logo-reset')
64352             .append('use')
64353             .attr('xlink:href', '#logo-reset');
64354
64355         reset
64356             .append('div')
64357             .text(t('restore.reset'));
64358
64359         restore.node().focus();
64360     };
64361 }
64362
64363 function uiSave(context) {
64364     var history = context.history(),
64365         key = uiCmd('⌘S');
64366
64367
64368     function saving() {
64369         return context.mode().id === 'save';
64370     }
64371
64372
64373     function save() {
64374         event.preventDefault();
64375         if (!context.inIntro() && !saving() && history.hasChanges()) {
64376             context.enter(modeSave$$1(context));
64377         }
64378     }
64379
64380
64381     function getBackground(numChanges) {
64382         var step$$1;
64383         if (numChanges === 0) {
64384             return null;
64385         } else if (numChanges <= 50) {
64386             step$$1 = numChanges / 50;
64387             return interpolateRgb('#fff', '#ff8')(step$$1);  // white -> yellow
64388         } else {
64389             step$$1 = Math.min((numChanges - 50) / 50, 1.0);
64390             return interpolateRgb('#ff8', '#f88')(step$$1);  // yellow -> red
64391         }
64392     }
64393
64394
64395     return function(selection$$1) {
64396         var numChanges = 0;
64397
64398         function updateCount() {
64399             var _ = history.difference().summary().length;
64400             if (_ === numChanges) return;
64401             numChanges = _;
64402
64403             tooltipBehavior
64404                 .title(uiTooltipHtml(
64405                     t(numChanges > 0 ? 'save.help' : 'save.no_changes'), key)
64406                 );
64407
64408             var background = getBackground(numChanges);
64409
64410             button
64411                 .classed('disabled', numChanges === 0)
64412                 .classed('has-count', numChanges > 0)
64413                 .style('background', background);
64414
64415             button.select('span.count')
64416                 .text(numChanges)
64417                 .style('background', background)
64418                 .style('border-color', background);
64419         }
64420
64421
64422         var tooltipBehavior = tooltip()
64423             .placement('bottom')
64424             .html(true)
64425             .title(uiTooltipHtml(t('save.no_changes'), key));
64426
64427         var button = selection$$1
64428             .append('button')
64429             .attr('class', 'save col12 disabled')
64430             .attr('tabindex', -1)
64431             .on('click', save)
64432             .call(tooltipBehavior);
64433
64434         button
64435             .call(svgIcon('#icon-save', 'pre-text'))
64436             .append('span')
64437             .attr('class', 'label')
64438             .text(t('save.title'));
64439
64440         button
64441             .append('span')
64442             .attr('class', 'count')
64443             .text('0');
64444
64445         updateCount();
64446
64447
64448         var keybinding = d3keybinding('save')
64449             .on(key, save, true);
64450
64451         select(document)
64452             .call(keybinding);
64453
64454         context.history()
64455             .on('change.save', updateCount);
64456
64457         context
64458             .on('enter.save', function() {
64459                 button.property('disabled', saving());
64460                 if (saving()) button.call(tooltipBehavior.hide);
64461             });
64462     };
64463 }
64464
64465 function uiScale(context) {
64466     var projection = context.projection,
64467         isImperial = (utilDetect().locale.toLowerCase() === 'en-us'),
64468         maxLength = 180,
64469         tickHeight = 8;
64470
64471
64472     function scaleDefs(loc1, loc2) {
64473         var lat = (loc2[1] + loc1[1]) / 2,
64474             conversion = (isImperial ? 3.28084 : 1),
64475             dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
64476             scale = { dist: 0, px: 0, text: '' },
64477             buckets, i, val, dLon;
64478
64479         if (isImperial) {
64480             buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
64481         } else {
64482             buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
64483         }
64484
64485         // determine a user-friendly endpoint for the scale
64486         for (i = 0; i < buckets.length; i++) {
64487             val = buckets[i];
64488             if (dist >= val) {
64489                 scale.dist = Math.floor(dist / val) * val;
64490                 break;
64491             } else {
64492                 scale.dist = +dist.toFixed(2);
64493             }
64494         }
64495
64496         dLon = geoMetersToLon(scale.dist / conversion, lat);
64497         scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
64498
64499         if (isImperial) {
64500             if (scale.dist >= 5280) {
64501                 scale.dist /= 5280;
64502                 scale.text = String(scale.dist) + ' mi';
64503             } else {
64504                 scale.text = String(scale.dist) + ' ft';
64505             }
64506         } else {
64507             if (scale.dist >= 1000) {
64508                 scale.dist /= 1000;
64509                 scale.text = String(scale.dist) + ' km';
64510             } else {
64511                 scale.text = String(scale.dist) + ' m';
64512             }
64513         }
64514
64515         return scale;
64516     }
64517
64518
64519     function update(selection) {
64520         // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
64521         var dims = context.map().dimensions(),
64522             loc1 = projection.invert([0, dims[1]]),
64523             loc2 = projection.invert([maxLength, dims[1]]),
64524             scale = scaleDefs(loc1, loc2);
64525
64526         selection.select('#scale-path')
64527             .attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
64528
64529         selection.select('#scale-textgroup')
64530             .attr('transform', 'translate(' + (scale.px + 8) + ',' + tickHeight + ')');
64531
64532         selection.select('#scale-text')
64533             .text(scale.text);
64534     }
64535
64536
64537     return function(selection) {
64538         function switchUnits() {
64539             isImperial = !isImperial;
64540             selection.call(update);
64541         }
64542
64543         var scalegroup = selection.append('svg')
64544             .attr('id', 'scale')
64545             .on('click', switchUnits)
64546             .append('g')
64547             .attr('transform', 'translate(10,11)');
64548
64549         scalegroup
64550             .append('path')
64551             .attr('id', 'scale-path');
64552
64553         scalegroup
64554             .append('g')
64555             .attr('id', 'scale-textgroup')
64556             .append('text')
64557             .attr('id', 'scale-text');
64558
64559         selection.call(update);
64560
64561         context.map().on('move.scale', function() {
64562             update(selection);
64563         });
64564     };
64565 }
64566
64567 var pair_1 = pair$1;
64568 function search(x, dims, r) {
64569   if (!dims) dims = 'NSEW';
64570   if (typeof x !== 'string') return { val: null, regex: r };
64571   r = r || /[\s\,]*([\-|\—|\―]?[0-9.]+)°? *(?:([0-9.]+)['’′‘] *)?(?:([0-9.]+)(?:''|"|”|″) *)?([NSEW])?/gi;
64572   var m = r.exec(x);
64573   if (!m) return { val: null, regex: r };
64574   else if (m[4] && dims.indexOf(m[4]) === -1) return { val: null, regex: r };
64575   else return {
64576     val: (((m[1]) ? parseFloat(m[1]) : 0) +
64577           ((m[2] ? parseFloat(m[2]) / 60 : 0)) +
64578           ((m[3] ? parseFloat(m[3]) / 3600 : 0))) *
64579           ((m[4] && m[4] === 'S' || m[4] === 'W') ? -1 : 1),
64580     regex: r,
64581     raw: m[0],
64582     dim: m[4]
64583   };
64584 }
64585
64586 function pair$1(x, dims) {
64587   x = x.trim();
64588   var one = search(x, dims);
64589   if (one.val === null) return null;
64590   var two = search(x, dims, one.regex);
64591   if (two.val === null) return null;
64592   // null if one/two are not contiguous.
64593   if (one.raw + two.raw !== x) return null;
64594   if (one.dim) {
64595     return swapdim(one.val, two.val, one.dim);
64596   } else {
64597     return [one.val, two.val];
64598   }
64599 }
64600
64601 function swapdim(a, b, dim) {
64602   if (dim === 'N' || dim === 'S') return [a, b];
64603   if (dim === 'W' || dim === 'E') return [b, a];
64604 }
64605
64606 function uiFeatureList(context) {
64607     var geocodeResults;
64608
64609
64610     function featureList(selection$$1) {
64611         var header = selection$$1
64612             .append('div')
64613             .attr('class', 'header fillL cf');
64614
64615         header.append('h3')
64616             .text(t('inspector.feature_list'));
64617
64618         var searchWrap = selection$$1
64619             .append('div')
64620             .attr('class', 'search-header');
64621
64622         var search = searchWrap
64623             .append('input')
64624             .attr('placeholder', t('inspector.search'))
64625             .attr('type', 'search')
64626             .call(utilNoAuto)
64627             .on('keypress', keypress)
64628             .on('input', inputevent);
64629
64630         searchWrap
64631             .call(svgIcon('#icon-search', 'pre-text'));
64632
64633         var listWrap = selection$$1
64634             .append('div')
64635             .attr('class', 'inspector-body');
64636
64637         var list = listWrap
64638             .append('div')
64639             .attr('class', 'feature-list cf');
64640
64641         context
64642             .on('exit.feature-list', clearSearch);
64643         context.map()
64644             .on('drawn.feature-list', mapDrawn);
64645
64646
64647         function keypress() {
64648             var q = search.property('value'),
64649                 items = list.selectAll('.feature-list-item');
64650             if (event.keyCode === 13 && q.length && items.size()) {
64651                 click(items.datum());
64652             }
64653         }
64654
64655
64656         function inputevent() {
64657             geocodeResults = undefined;
64658             drawList();
64659         }
64660
64661
64662         function clearSearch() {
64663             search.property('value', '');
64664             drawList();
64665         }
64666
64667
64668         function mapDrawn(e) {
64669             if (e.full) {
64670                 drawList();
64671             }
64672         }
64673
64674
64675         function features() {
64676             var entities = {},
64677                 result = [],
64678                 graph = context.graph(),
64679                 q = search.property('value').toLowerCase();
64680
64681             if (!q) return result;
64682
64683             var idMatch = q.match(/^([nwr])([0-9]+)$/);
64684
64685             if (idMatch) {
64686                 result.push({
64687                     id: idMatch[0],
64688                     geometry: idMatch[1] === 'n' ? 'point' : idMatch[1] === 'w' ? 'line' : 'relation',
64689                     type: idMatch[1] === 'n' ? t('inspector.node') : idMatch[1] === 'w' ? t('inspector.way') : t('inspector.relation'),
64690                     name: idMatch[2]
64691                 });
64692             }
64693
64694             var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
64695
64696             if (locationMatch) {
64697                 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
64698                 result.push({
64699                     id: -1,
64700                     geometry: 'point',
64701                     type: t('inspector.location'),
64702                     name: loc[0].toFixed(6) + ', ' + loc[1].toFixed(6),
64703                     location: loc
64704                 });
64705             }
64706
64707             function addEntity(entity) {
64708                 if (entity.id in entities || result.length > 200)
64709                     return;
64710
64711                 entities[entity.id] = true;
64712
64713                 var name = utilDisplayName(entity) || '';
64714                 if (name.toLowerCase().indexOf(q) >= 0) {
64715                     var matched = context.presets().match(entity, graph),
64716                         type = (matched && matched.name()) || utilDisplayType(entity.id);
64717                     result.push({
64718                         id: entity.id,
64719                         entity: entity,
64720                         geometry: context.geometry(entity.id),
64721                         type: type,
64722                         name: name
64723                     });
64724                 }
64725
64726                 graph.parentRelations(entity).forEach(function(parent) {
64727                     addEntity(parent);
64728                 });
64729             }
64730
64731             var visible = context.surface().selectAll('.point, .line, .area').nodes();
64732             for (var i = 0; i < visible.length && result.length <= 200; i++) {
64733                 addEntity(visible[i].__data__);
64734             }
64735
64736             (geocodeResults || []).forEach(function(d) {
64737                 // https://github.com/openstreetmap/iD/issues/1890
64738                 if (d.osm_type && d.osm_id) {
64739                     result.push({
64740                         id: osmEntity$$1.id.fromOSM(d.osm_type, d.osm_id),
64741                         geometry: d.osm_type === 'relation' ? 'relation' : d.osm_type === 'way' ? 'line' : 'point',
64742                         type: d.type !== 'yes' ? (d.type.charAt(0).toUpperCase() + d.type.slice(1)).replace('_', ' ')
64743                                                : (d.class.charAt(0).toUpperCase() + d.class.slice(1)).replace('_', ' '),
64744                         name: d.display_name,
64745                         extent: new geoExtent$$1(
64746                             [parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])],
64747                             [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
64748                     });
64749                 }
64750             });
64751
64752             return result;
64753         }
64754
64755
64756         function drawList() {
64757             var value = search.property('value'),
64758                 results = features();
64759
64760             list.classed('filtered', value.length);
64761
64762             var noResultsWorldwide = geocodeResults && geocodeResults.length === 0;
64763
64764             var resultsIndicator = list.selectAll('.no-results-item')
64765                 .data([0])
64766                 .enter().append('button')
64767                 .property('disabled', true)
64768                 .attr('class', 'no-results-item')
64769                 .call(svgIcon('#icon-alert', 'pre-text'));
64770
64771             resultsIndicator.append('span')
64772                 .attr('class', 'entity-name');
64773
64774             list.selectAll('.no-results-item .entity-name')
64775                 .text(noResultsWorldwide ? t('geocoder.no_results_worldwide') : t('geocoder.no_results_visible'));
64776
64777             if (services.geocoder) {
64778               list.selectAll('.geocode-item')
64779                   .data([0])
64780                   .enter().append('button')
64781                   .attr('class', 'geocode-item')
64782                   .on('click', geocoderSearch)
64783                   .append('div')
64784                   .attr('class', 'label')
64785                   .append('span')
64786                   .attr('class', 'entity-name')
64787                   .text(t('geocoder.search'));
64788             }
64789
64790             list.selectAll('.no-results-item')
64791                 .style('display', (value.length && !results.length) ? 'block' : 'none');
64792
64793             list.selectAll('.geocode-item')
64794                 .style('display', (value && geocodeResults === undefined) ? 'block' : 'none');
64795
64796             list.selectAll('.feature-list-item')
64797                 .data([-1])
64798                 .remove();
64799
64800             var items = list.selectAll('.feature-list-item')
64801                 .data(results, function(d) { return d.id; });
64802
64803             var enter = items.enter()
64804                 .insert('button', '.geocode-item')
64805                 .attr('class', 'feature-list-item')
64806                 .on('mouseover', mouseover)
64807                 .on('mouseout', mouseout)
64808                 .on('click', click);
64809
64810             var label = enter
64811                 .append('div')
64812                 .attr('class', 'label');
64813
64814             label.each(function(d) {
64815                 select(this)
64816                     .call(svgIcon('#icon-' + d.geometry, 'pre-text'));
64817             });
64818
64819             label.append('span')
64820                 .attr('class', 'entity-type')
64821                 .text(function(d) { return d.type; });
64822
64823             label.append('span')
64824                 .attr('class', 'entity-name')
64825                 .text(function(d) { return d.name; });
64826
64827             enter.style('opacity', 0)
64828                 .transition()
64829                 .style('opacity', 1);
64830
64831             items.order();
64832
64833             items.exit()
64834                 .remove();
64835         }
64836
64837
64838         function mouseover(d) {
64839             if (d.id === -1) return;
64840
64841             context.surface().selectAll(utilEntityOrMemberSelector([d.id], context.graph()))
64842                 .classed('hover', true);
64843         }
64844
64845
64846         function mouseout() {
64847             context.surface().selectAll('.hover')
64848                 .classed('hover', false);
64849         }
64850
64851
64852         function click(d) {
64853             event.preventDefault();
64854             if (d.location) {
64855                 context.map().centerZoom([d.location[1], d.location[0]], 20);
64856             }
64857             else if (d.entity) {
64858                 if (d.entity.type === 'node') {
64859                     context.map().center(d.entity.loc);
64860                 } else if (d.entity.type === 'way') {
64861                     var center = context.projection(context.map().center()),
64862                         edge = geoChooseEdge(context.childNodes(d.entity), center, context.projection);
64863                     context.map().center(edge.loc);
64864                 }
64865                 context.enter(modeSelect(context, [d.entity.id]));
64866             } else {
64867                 context.zoomToEntity(d.id);
64868             }
64869         }
64870
64871
64872         function geocoderSearch() {
64873             services.geocoder.search(search.property('value'), function (err, resp) {
64874                 geocodeResults = resp || [];
64875                 drawList();
64876             });
64877         }
64878     }
64879
64880
64881     return featureList;
64882 }
64883
64884 function uiPresetIcon() {
64885     var preset, geometry;
64886
64887
64888     function presetIcon(selection$$1) {
64889         selection$$1.each(render);
64890     }
64891
64892
64893     function getIcon(p, geom) {
64894         if (p.icon)
64895             return p.icon;
64896         else if (geom === 'line')
64897             return 'other-line';
64898         else if (geom === 'vertex')
64899             return p.isFallback() ? '' : 'poi-vertex';
64900         else
64901             return 'marker-stroked';
64902     }
64903
64904
64905     function render() {
64906         var selection$$1 = select(this),
64907             p = preset.apply(this, arguments),
64908             geom = geometry.apply(this, arguments),
64909             picon = getIcon(p, geom),
64910             isPoi = picon.match(/^poi-/) !== null,
64911             isMaki = dataFeatureIcons.indexOf(picon) !== -1,
64912             isFramed = (geom === 'area' || geom === 'verex');
64913
64914
64915         function tag_classes(p) {
64916             var s = '';
64917             for (var i in p.tags) {
64918                 s += ' tag-' + i;
64919                 if (p.tags[i] !== '*') {
64920                     s += ' tag-' + i + '-' + p.tags[i];
64921                 }
64922             }
64923             return s;
64924         }
64925
64926
64927         var fill = selection$$1.selectAll('.preset-icon-fill')
64928             .data([0]);
64929
64930         fill = fill.enter()
64931             .append('div')
64932             .merge(fill);
64933
64934         fill
64935             .attr('class', function() {
64936                 return 'preset-icon-fill preset-icon-fill-' + geom + tag_classes(p);
64937             });
64938
64939
64940         var areaFrame = selection$$1.selectAll('.preset-icon-frame')
64941             .data((geom === 'area') ? [0] : []);
64942
64943         areaFrame.exit()
64944             .remove();
64945
64946         areaFrame = areaFrame.enter()
64947             .append('div')
64948             .attr('class', 'preset-icon-frame')
64949             .call(svgIcon('#preset-icon-frame'));
64950
64951
64952         var icon = selection$$1.selectAll('.preset-icon')
64953             .data([0]);
64954
64955         icon = icon.enter()
64956             .append('div')
64957             .attr('class', 'preset-icon')
64958             .call(svgIcon(''))
64959             .merge(icon);
64960
64961         icon
64962             .attr('class', 'preset-icon preset-icon-' +
64963                 ((isMaki || isPoi) ? (isFramed ? '24' : '28') : (isFramed ? '44' : '60'))
64964             );
64965
64966         icon.selectAll('svg')
64967             .attr('class', function() {
64968                 return 'icon ' + picon + (isMaki || isPoi ? '' : tag_classes(p));
64969             });
64970
64971         icon.selectAll('use')
64972             .attr('href', '#' + picon + (isMaki ? '-15' : ''));
64973     }
64974
64975
64976     presetIcon.preset = function(_) {
64977         if (!arguments.length) return preset;
64978         preset = utilFunctor(_);
64979         return presetIcon;
64980     };
64981
64982
64983     presetIcon.geometry = function(_) {
64984         if (!arguments.length) return geometry;
64985         geometry = utilFunctor(_);
64986         return presetIcon;
64987     };
64988
64989     return presetIcon;
64990 }
64991
64992 function d3combobox() {
64993     var dispatch$$1 = dispatch('accept'),
64994         container = select(document.body),
64995         data = [],
64996         suggestions = [],
64997         minItems = 2,
64998         caseSensitive = false;
64999
65000     var fetcher = function(val, cb) {
65001         cb(data.filter(function(d) {
65002             return d.value
65003                 .toString()
65004                 .toLowerCase()
65005                 .indexOf(val.toLowerCase()) !== -1;
65006         }));
65007     };
65008
65009     var combobox = function(input, attachTo) {
65010         var idx = -1,
65011             wrapper = container
65012                 .selectAll('div.combobox')
65013                 .filter(function(d) { return d === input.node(); }),
65014             shown = !wrapper.empty();
65015
65016         input
65017             .classed('combobox-input', true)
65018             .on('focus.typeahead', focus)
65019             .on('blur.typeahead', blur)
65020             .on('keydown.typeahead', keydown)
65021             .on('keyup.typeahead', keyup)
65022             .on('input.typeahead', change)
65023             .each(function() {
65024                 var parent = this.parentNode,
65025                     sibling = this.nextSibling;
65026
65027                 var caret = select(parent).selectAll('.combobox-caret')
65028                     .filter(function(d) { return d === input.node(); })
65029                     .data([input.node()]);
65030
65031                 caret = caret.enter()
65032                   .insert('div', function() { return sibling; })
65033                     .attr('class', 'combobox-caret')
65034                   .merge(caret);
65035
65036                 caret
65037                     .on('mousedown', function () {
65038                         // prevent the form element from blurring. it blurs
65039                         // on mousedown
65040                         event.stopPropagation();
65041                         event.preventDefault();
65042                         if (!shown) {
65043                             input.node().focus();
65044                             fetch('', render);
65045                         } else {
65046                             hide();
65047                         }
65048                     });
65049             });
65050
65051         function focus() {
65052             fetch(value(), render);
65053         }
65054
65055         function blur() {
65056             window.setTimeout(hide, 150);
65057         }
65058
65059         function show() {
65060             if (!shown) {
65061                 wrapper = container
65062                     .insert('div', ':first-child')
65063                     .datum(input.node())
65064                     .attr('class', 'combobox')
65065                     .style('position', 'absolute')
65066                     .style('display', 'block')
65067                     .style('left', '0px')
65068                     .on('mousedown', function () {
65069                         // prevent moving focus out of the text field
65070                         event.preventDefault();
65071                     });
65072
65073                 select('body')
65074                     .on('scroll.combobox', render, true);
65075
65076                 shown = true;
65077             }
65078         }
65079
65080         function hide() {
65081             if (shown) {
65082                 idx = -1;
65083                 wrapper.remove();
65084
65085                 select('body')
65086                     .on('scroll.combobox', null);
65087
65088                 shown = false;
65089             }
65090         }
65091
65092         function keydown() {
65093            switch (event.keyCode) {
65094                // backspace, delete
65095                case 8:
65096                case 46:
65097                    input.on('input.typeahead', function() {
65098                        idx = -1;
65099                        render();
65100                        var start = input.property('selectionStart');
65101                        input.node().setSelectionRange(start, start);
65102                        input.on('input.typeahead', change);
65103                    });
65104                    break;
65105                // tab
65106                case 9:
65107                    wrapper.selectAll('a.selected').each(function (d) {
65108                        dispatch$$1.call('accept', this, d);
65109                    });
65110                    hide();
65111                    break;
65112                // return
65113                case 13:
65114                    event.preventDefault();
65115                    break;
65116                // up arrow
65117                case 38:
65118                    nav(-1);
65119                    event.preventDefault();
65120                    break;
65121                // down arrow
65122                case 40:
65123                    nav(+1);
65124                    event.preventDefault();
65125                    break;
65126            }
65127            event.stopPropagation();
65128         }
65129
65130         function keyup() {
65131             switch (event.keyCode) {
65132                 // escape
65133                 case 27:
65134                     hide();
65135                     break;
65136                 // return
65137                 case 13:
65138                     wrapper.selectAll('a.selected').each(function (d) {
65139                        dispatch$$1.call('accept', this, d);
65140                     });
65141                     hide();
65142                     break;
65143             }
65144         }
65145
65146         function change() {
65147             fetch(value(), function() {
65148                 if (input.property('selectionEnd') === input.property('value').length) {
65149                     autocomplete();
65150                 }
65151                 render();
65152             });
65153         }
65154
65155         function nav(dir) {
65156             if (!suggestions.length) return;
65157             idx = Math.max(Math.min(idx + dir, suggestions.length - 1), 0);
65158             input.property('value', suggestions[idx].value);
65159             render();
65160             ensureVisible();
65161         }
65162
65163         function value() {
65164             var value = input.property('value'),
65165                 start = input.property('selectionStart'),
65166                 end = input.property('selectionEnd');
65167
65168             if (start && end) {
65169                 value = value.substring(0, start);
65170             }
65171
65172             return value;
65173         }
65174
65175         function fetch(v, cb) {
65176             fetcher.call(input, v, function(_) {
65177                 suggestions = _;
65178                 cb();
65179             });
65180         }
65181
65182         function autocomplete() {
65183             var v = caseSensitive ? value() : value().toLowerCase();
65184             idx = -1;
65185             if (!v) return;
65186
65187             for (var i = 0; i < suggestions.length; i++) {
65188                 var suggestion = suggestions[i].value,
65189                     compare = caseSensitive ? suggestion : suggestion.toLowerCase();
65190
65191                 if (compare.indexOf(v) === 0) {
65192                     idx = i;
65193                     input.property('value', suggestion);
65194                     input.node().setSelectionRange(v.length, suggestion.length);
65195                     return;
65196                 }
65197             }
65198         }
65199
65200         function render() {
65201             if (suggestions.length >= minItems && document.activeElement === input.node()) {
65202                 show();
65203             } else {
65204                 hide();
65205                 return;
65206             }
65207
65208             var options = wrapper
65209                 .selectAll('a.combobox-option')
65210                 .data(suggestions, function(d) { return d.value; });
65211
65212             options.exit()
65213                 .remove();
65214
65215             options.enter()
65216                 .append('a')
65217                 .attr('class', 'combobox-option')
65218                 .text(function(d) { return d.value; })
65219                 .merge(options)
65220                 .attr('title', function(d) { return d.title; })
65221                 .classed('selected', function(d, i) { return i === idx; })
65222                 .on('mouseover', select$$1)
65223                 .on('click', accept)
65224                 .order();
65225
65226
65227             var node = attachTo ? attachTo.node() : input.node(),
65228                 rect = node.getBoundingClientRect();
65229
65230             wrapper
65231                 .style('left', rect.left + 'px')
65232                 .style('width', rect.width + 'px')
65233                 .style('top', rect.height + rect.top + 'px');
65234         }
65235
65236         function select$$1(d, i) {
65237             idx = i;
65238             render();
65239         }
65240
65241         function ensureVisible() {
65242             var node = wrapper.selectAll('a.selected').node();
65243             if (node) node.scrollIntoView();
65244         }
65245
65246         function accept(d) {
65247             if (!shown) return;
65248             input.property('value', d.value);
65249             utilTriggerEvent(input, 'change');
65250             dispatch$$1.call('accept', this, d);
65251             hide();
65252         }
65253     };
65254
65255     combobox.fetcher = function(_) {
65256         if (!arguments.length) return fetcher;
65257         fetcher = _;
65258         return combobox;
65259     };
65260
65261     combobox.data = function(_) {
65262         if (!arguments.length) return data;
65263         data = _;
65264         return combobox;
65265     };
65266
65267     combobox.minItems = function(_) {
65268         if (!arguments.length) return minItems;
65269         minItems = _;
65270         return combobox;
65271     };
65272
65273     combobox.caseSensitive = function(_) {
65274         if (!arguments.length) return caseSensitive;
65275         caseSensitive = _;
65276         return combobox;
65277     };
65278
65279     combobox.container = function(_) {
65280         if (!arguments.length) return container;
65281         container = _;
65282         return combobox;
65283     };
65284
65285     return utilRebind(combobox, dispatch$$1, 'on');
65286 }
65287
65288
65289 d3combobox.off = function(input) {
65290     input
65291         .on('focus.typeahead', null)
65292         .on('blur.typeahead', null)
65293         .on('keydown.typeahead', null)
65294         .on('keyup.typeahead', null)
65295         .on('input.typeahead', null)
65296         .each(function() {
65297             select(this.parentNode).selectAll('.combobox-caret')
65298                 .filter(function(d) { return d === input.node(); })
65299                 .on('mousedown', null);
65300         });
65301
65302     select('body')
65303         .on('scroll.combobox', null);
65304 };
65305
65306 function uiDisclosure() {
65307     var dispatch$$1 = dispatch('toggled'),
65308         title,
65309         expanded = false,
65310         content = function () {};
65311
65312
65313     var disclosure = function(selection$$1) {
65314         var hideToggle = selection$$1.selectAll('.hide-toggle')
65315             .data([0]);
65316
65317         hideToggle = hideToggle.enter()
65318             .append('a')
65319             .attr('href', '#')
65320             .attr('class', 'hide-toggle')
65321             .merge(hideToggle);
65322
65323         hideToggle
65324             .text(title)
65325             .on('click', toggle)
65326             .classed('expanded', expanded);
65327
65328
65329         var wrap = selection$$1.selectAll('div')
65330             .data([0]);
65331
65332         wrap = wrap.enter()
65333             .append('div')
65334             .merge(wrap);
65335
65336         wrap
65337             .classed('hide', !expanded)
65338             .call(content);
65339
65340
65341         function toggle() {
65342             expanded = !expanded;
65343             hideToggle.classed('expanded', expanded);
65344             wrap.call(uiToggle(expanded));
65345             dispatch$$1.call('toggled', this, expanded);
65346         }
65347     };
65348
65349
65350     disclosure.title = function(_) {
65351         if (!arguments.length) return title;
65352         title = _;
65353         return disclosure;
65354     };
65355
65356
65357     disclosure.expanded = function(_) {
65358         if (!arguments.length) return expanded;
65359         expanded = _;
65360         return disclosure;
65361     };
65362
65363
65364     disclosure.content = function(_) {
65365         if (!arguments.length) return content;
65366         content = _;
65367         return disclosure;
65368     };
65369
65370
65371     return utilRebind(disclosure, dispatch$$1, 'on');
65372 }
65373
65374 function uiRawMemberEditor(context) {
65375     var id,
65376         taginfo = services.taginfo;
65377
65378
65379     function selectMember(d) {
65380         event.preventDefault();
65381         context.enter(modeSelect(context, [d.id]));
65382     }
65383
65384
65385     function changeRole(d) {
65386         var role = select(this).property('value');
65387         var member = { id: d.id, type: d.type, role: role };
65388         context.perform(
65389             actionChangeMember(d.relation.id, member, d.index),
65390             t('operations.change_role.annotation')
65391         );
65392     }
65393
65394
65395     function deleteMember(d) {
65396         context.perform(
65397             actionDeleteMember(d.relation.id, d.index),
65398             t('operations.delete_member.annotation')
65399         );
65400
65401         if (!context.hasEntity(d.relation.id)) {
65402             context.enter(modeBrowse(context));
65403         }
65404     }
65405
65406
65407     function rawMemberEditor(selection$$1) {
65408         var entity = context.entity(id),
65409             memberships = [];
65410
65411         entity.members.slice(0, 1000).forEach(function(member, index) {
65412             memberships.push({
65413                 index: index,
65414                 id: member.id,
65415                 type: member.type,
65416                 role: member.role,
65417                 relation: entity,
65418                 member: context.hasEntity(member.id)
65419             });
65420         });
65421
65422         var gt = entity.members.length > 1000 ? '>' : '';
65423         selection$$1.call(uiDisclosure()
65424             .title(t('inspector.all_members') + ' (' + gt + memberships.length + ')')
65425             .expanded(true)
65426             .on('toggled', toggled)
65427             .content(content)
65428         );
65429
65430
65431         function toggled(expanded) {
65432             if (expanded) {
65433                 selection$$1.node().parentNode.scrollTop += 200;
65434             }
65435         }
65436
65437
65438         function content(wrap) {
65439             var list = wrap.selectAll('.member-list')
65440                 .data([0]);
65441
65442             list = list.enter()
65443                 .append('ul')
65444                 .attr('class', 'member-list')
65445                 .merge(list);
65446
65447
65448             var items = list.selectAll('li')
65449                 .data(memberships, function(d) {
65450                     return osmEntity$$1.key(d.relation) + ',' + d.index + ',' +
65451                         (d.member ? osmEntity$$1.key(d.member) : 'incomplete');
65452                 });
65453
65454             items.exit()
65455                 .each(unbind)
65456                 .remove();
65457
65458             var enter = items.enter()
65459                 .append('li')
65460                 .attr('class', 'member-row form-field')
65461                 .classed('member-incomplete', function(d) { return !d.member; });
65462
65463             enter
65464                 .each(function(d) {
65465                     if (d.member) {
65466                         var label = select(this).append('label')
65467                             .attr('class', 'form-label')
65468                             .append('a')
65469                             .attr('href', '#')
65470                             .on('click', selectMember);
65471
65472                         label.append('span')
65473                             .attr('class', 'member-entity-type')
65474                             .text(function(d) {
65475                                 var matched = context.presets().match(d.member, context.graph());
65476                                 return (matched && matched.name()) || utilDisplayType(d.member.id);
65477                             });
65478
65479                         label.append('span')
65480                             .attr('class', 'member-entity-name')
65481                             .text(function(d) { return utilDisplayName(d.member); });
65482
65483                     } else {
65484                         select(this).append('label')
65485                             .attr('class', 'form-label')
65486                             .text(t('inspector.incomplete', { id: d.id }));
65487                     }
65488                 });
65489
65490             enter
65491                 .append('input')
65492                 .attr('class', 'member-role')
65493                 .property('type', 'text')
65494                 .attr('maxlength', 255)
65495                 .attr('placeholder', t('inspector.role'))
65496                 .call(utilNoAuto)
65497                 .property('value', function(d) { return d.role; })
65498                 .on('change', changeRole);
65499
65500             enter
65501                 .append('button')
65502                 .attr('tabindex', -1)
65503                 .attr('class', 'remove button-input-action member-delete minor')
65504                 .on('click', deleteMember)
65505                 .call(svgIcon('#operation-delete'));
65506
65507             if (taginfo) {
65508                 enter.each(bindTypeahead);
65509             }
65510
65511
65512             function bindTypeahead(d) {
65513                 var row = select(this),
65514                     role = row.selectAll('input.member-role');
65515
65516                 function sort(value, data) {
65517                     var sameletter = [],
65518                         other = [];
65519                     for (var i = 0; i < data.length; i++) {
65520                         if (data[i].value.substring(0, value.length) === value) {
65521                             sameletter.push(data[i]);
65522                         } else {
65523                             other.push(data[i]);
65524                         }
65525                     }
65526                     return sameletter.concat(other);
65527                 }
65528
65529                 role.call(d3combobox()
65530                     .container(context.container())
65531                     .fetcher(function(role, callback) {
65532                         var rtype = entity.tags.type;
65533                         taginfo.roles({
65534                             debounce: true,
65535                             rtype: rtype || '',
65536                             geometry: context.geometry(d.member.id),
65537                             query: role
65538                         }, function(err, data) {
65539                             if (!err) callback(sort(role, data));
65540                         });
65541                     }));
65542             }
65543
65544
65545             function unbind() {
65546                 var row = select(this);
65547
65548                 row.selectAll('input.member-role')
65549                     .call(d3combobox.off);
65550             }
65551         }
65552     }
65553
65554
65555     rawMemberEditor.entityID = function(_) {
65556         if (!arguments.length) return id;
65557         id = _;
65558         return rawMemberEditor;
65559     };
65560
65561
65562     return rawMemberEditor;
65563 }
65564
65565 function uiRawMembershipEditor(context) {
65566     var taginfo = services.taginfo,
65567         id, showBlank;
65568
65569
65570     function selectRelation(d) {
65571         event.preventDefault();
65572         context.enter(modeSelect(context, [d.relation.id]));
65573     }
65574
65575
65576     function changeRole(d) {
65577         var role = select(this).property('value');
65578         context.perform(
65579             actionChangeMember(d.relation.id, lodash.extend({}, d.member, { role: role }), d.index),
65580             t('operations.change_role.annotation')
65581         );
65582     }
65583
65584
65585     function addMembership(d, role) {
65586         showBlank = false;
65587
65588         if (d.relation) {
65589             context.perform(
65590                 actionAddMember(d.relation.id, { id: id, type: context.entity(id).type, role: role }),
65591                 t('operations.add_member.annotation')
65592             );
65593
65594         } else {
65595             var relation = osmRelation();
65596             context.perform(
65597                 actionAddEntity(relation),
65598                 actionAddMember(relation.id, { id: id, type: context.entity(id).type, role: role }),
65599                 t('operations.add.annotation.relation')
65600             );
65601
65602             context.enter(modeSelect(context, [relation.id]));
65603         }
65604     }
65605
65606
65607     function deleteMembership(d) {
65608         context.perform(
65609             actionDeleteMember(d.relation.id, d.index),
65610             t('operations.delete_member.annotation')
65611         );
65612     }
65613
65614
65615     function relations(q) {
65616         var newRelation = {
65617                 relation: null,
65618                 value: t('inspector.new_relation')
65619             },
65620             result = [],
65621             graph = context.graph();
65622
65623         context.intersects(context.extent()).forEach(function(entity) {
65624             if (entity.type !== 'relation' || entity.id === id)
65625                 return;
65626
65627             var matched = context.presets().match(entity, graph),
65628                 presetName = (matched && matched.name()) || t('inspector.relation'),
65629                 entityName = utilDisplayName(entity) || '';
65630
65631             var value = presetName + ' ' + entityName;
65632             if (q && value.toLowerCase().indexOf(q.toLowerCase()) === -1)
65633                 return;
65634
65635             result.push({
65636                 relation: entity,
65637                 value: value
65638             });
65639         });
65640
65641         result.sort(function(a, b) {
65642             return osmRelation.creationOrder(a.relation, b.relation);
65643         });
65644
65645         // Dedupe identical names by appending relation id - see #2891
65646         var dupeGroups = lodash(result)
65647             .groupBy('value')
65648             .filter(function(v) { return v.length > 1; })
65649             .value();
65650
65651         dupeGroups.forEach(function(group) {
65652             group.forEach(function(obj) {
65653                 obj.value += ' ' + obj.relation.id;
65654             });
65655         });
65656
65657         result.unshift(newRelation);
65658         return result;
65659     }
65660
65661
65662     function rawMembershipEditor(selection$$1) {
65663         var entity = context.entity(id),
65664             parents = context.graph().parentRelations(entity),
65665             memberships = [];
65666
65667         parents.slice(0, 1000).forEach(function(relation) {
65668             relation.members.forEach(function(member, index) {
65669                 if (member.id === entity.id) {
65670                     memberships.push({ relation: relation, member: member, index: index });
65671                 }
65672             });
65673         });
65674
65675         var gt = parents.length > 1000 ? '>' : '';
65676         selection$$1.call(uiDisclosure()
65677             .title(t('inspector.all_relations') + ' (' + gt + memberships.length + ')')
65678             .expanded(true)
65679             .on('toggled', toggled)
65680             .content(content)
65681         );
65682
65683
65684         function toggled(expanded) {
65685             if (expanded) {
65686                 selection$$1.node().parentNode.scrollTop += 200;
65687             }
65688         }
65689
65690
65691         function content(wrap) {
65692             var list = wrap.selectAll('.member-list')
65693                 .data([0]);
65694
65695             list = list.enter()
65696                 .append('ul')
65697                 .attr('class', 'member-list')
65698                 .merge(list);
65699
65700
65701             var items = list.selectAll('li.member-row-normal')
65702                 .data(memberships, function(d) {
65703                     return osmEntity$$1.key(d.relation) + ',' + d.index;
65704                 });
65705
65706             items.exit()
65707                 .each(unbind)
65708                 .remove();
65709
65710             var enter = items.enter()
65711                 .append('li')
65712                 .attr('class', 'member-row member-row-normal form-field');
65713
65714             var label = enter
65715                 .append('label')
65716                 .attr('class', 'form-label')
65717                 .append('a')
65718                 .attr('href', '#')
65719                 .on('click', selectRelation);
65720
65721             label
65722                 .append('span')
65723                 .attr('class', 'member-entity-type')
65724                 .text(function(d) {
65725                     var matched = context.presets().match(d.relation, context.graph());
65726                     return (matched && matched.name()) || t('inspector.relation');
65727                 });
65728
65729             label
65730                 .append('span')
65731                 .attr('class', 'member-entity-name')
65732                 .text(function(d) { return utilDisplayName(d.relation); });
65733
65734             enter
65735                 .append('input')
65736                 .attr('class', 'member-role')
65737                 .property('type', 'text')
65738                 .attr('maxlength', 255)
65739                 .attr('placeholder', t('inspector.role'))
65740                 .call(utilNoAuto)
65741                 .property('value', function(d) { return d.member.role; })
65742                 .on('change', changeRole);
65743
65744             enter
65745                 .append('button')
65746                 .attr('tabindex', -1)
65747                 .attr('class', 'remove button-input-action member-delete minor')
65748                 .on('click', deleteMembership)
65749                 .call(svgIcon('#operation-delete'));
65750
65751             if (taginfo) {
65752                 enter.each(bindTypeahead);
65753             }
65754
65755
65756             var newrow = list.selectAll('.member-row-new')
65757                 .data(showBlank ? [0] : []);
65758
65759             newrow.exit()
65760                 .remove();
65761
65762             enter = newrow.enter()
65763                 .append('li')
65764                 .attr('class', 'member-row member-row-new form-field');
65765
65766             enter
65767                 .append('input')
65768                 .attr('type', 'text')
65769                 .attr('class', 'member-entity-input')
65770                 .call(utilNoAuto);
65771
65772             enter
65773                 .append('input')
65774                 .attr('class', 'member-role')
65775                 .property('type', 'text')
65776                 .attr('maxlength', 255)
65777                 .attr('placeholder', t('inspector.role'))
65778                 .call(utilNoAuto)
65779                 .on('change', changeRole);
65780
65781             enter
65782                 .append('button')
65783                 .attr('tabindex', -1)
65784                 .attr('class', 'remove button-input-action member-delete minor')
65785                 .on('click', deleteMembership)
65786                 .call(svgIcon('#operation-delete'));
65787
65788             newrow = newrow
65789                 .merge(enter);
65790
65791             newrow.selectAll('.member-entity-input')
65792                 .call(d3combobox()
65793                     .container(context.container())
65794                     .minItems(1)
65795                     .fetcher(function(value, callback) { callback(relations(value)); })
65796                     .on('accept', onAccept)
65797                 );
65798
65799
65800             var addrel = wrap.selectAll('.add-relation')
65801                 .data([0]);
65802
65803             addrel = addrel.enter()
65804                 .append('button')
65805                 .attr('class', 'add-relation')
65806                 .merge(addrel);
65807
65808             addrel
65809                 .call(svgIcon('#icon-plus', 'light'))
65810                 .on('click', function() {
65811                     showBlank = true;
65812                     content(wrap);
65813                     list.selectAll('.member-entity-input').node().focus();
65814                 });
65815
65816
65817             function onAccept(d) {
65818                 var role = list.selectAll('.member-row-new .member-role').property('value');
65819                 addMembership(d, role);
65820             }
65821
65822
65823             function bindTypeahead(d) {
65824                 var row = select(this),
65825                     role = row.selectAll('input.member-role');
65826
65827                 function sort(value, data) {
65828                     var sameletter = [],
65829                         other = [];
65830                     for (var i = 0; i < data.length; i++) {
65831                         if (data[i].value.substring(0, value.length) === value) {
65832                             sameletter.push(data[i]);
65833                         } else {
65834                             other.push(data[i]);
65835                         }
65836                     }
65837                     return sameletter.concat(other);
65838                 }
65839
65840                 role.call(d3combobox()
65841                     .container(context.container())
65842                     .fetcher(function(role, callback) {
65843                         var rtype = d.relation.tags.type;
65844                         taginfo.roles({
65845                             debounce: true,
65846                             rtype: rtype || '',
65847                             geometry: context.geometry(id),
65848                             query: role
65849                         }, function(err, data) {
65850                             if (!err) callback(sort(role, data));
65851                         });
65852                     }));
65853             }
65854
65855
65856             function unbind() {
65857                 var row = select(this);
65858
65859                 row.selectAll('input.member-role')
65860                     .call(d3combobox.off);
65861             }
65862         }
65863     }
65864
65865
65866     rawMembershipEditor.entityID = function(_) {
65867         if (!arguments.length) return id;
65868         id = _;
65869         return rawMembershipEditor;
65870     };
65871
65872
65873     return rawMembershipEditor;
65874 }
65875
65876 function uiTagReference(tag) {
65877     var taginfo = services.taginfo,
65878         tagReference = {},
65879         button,
65880         body,
65881         loaded,
65882         showing;
65883
65884
65885     function findLocal(data) {
65886         var locale = utilDetect().locale.toLowerCase(),
65887             localized;
65888
65889         if (locale !== 'pt-br') {  // see #3776, prefer 'pt' over 'pt-br'
65890             localized = lodash.find(data, function(d) {
65891                 return d.lang.toLowerCase() === locale;
65892             });
65893             if (localized) return localized;
65894         }
65895
65896         // try the non-regional version of a language, like
65897         // 'en' if the language is 'en-US'
65898         if (locale.indexOf('-') !== -1) {
65899             var first = locale.split('-')[0];
65900             localized = lodash.find(data, function(d) {
65901                 return d.lang.toLowerCase() === first;
65902             });
65903             if (localized) return localized;
65904         }
65905
65906         // finally fall back to english
65907         return lodash.find(data, function(d) {
65908             return d.lang.toLowerCase() === 'en';
65909         });
65910     }
65911
65912
65913     function load(param) {
65914         if (!taginfo) return;
65915
65916         button.classed('tag-reference-loading', true);
65917
65918         taginfo.docs(param, function show(err, data) {
65919             var docs;
65920             if (!err && data) {
65921                 docs = findLocal(data);
65922             }
65923
65924             body.html('');
65925
65926
65927             if (!docs || !docs.title) {
65928                 if (param.hasOwnProperty('value')) {
65929                     load(lodash.omit(param, 'value'));   // retry with key only
65930                 } else {
65931                     body.append('p').text(t('inspector.no_documentation_key'));
65932                     done();
65933                 }
65934                 return;
65935             }
65936
65937
65938             if (docs.image && docs.image.thumb_url_prefix) {
65939                 body
65940                     .append('img')
65941                     .attr('class', 'wiki-image')
65942                     .attr('src', docs.image.thumb_url_prefix + '100' + docs.image.thumb_url_suffix)
65943                     .on('load', function() { done(); })
65944                     .on('error', function() { select(this).remove(); done(); });
65945             } else {
65946                 done();
65947             }
65948
65949             body
65950                 .append('p')
65951                 .text(docs.description || t('inspector.documentation_redirect'));
65952
65953             body
65954                 .append('a')
65955                 .attr('target', '_blank')
65956                 .attr('tabindex', -1)
65957                 .attr('href', 'https://wiki.openstreetmap.org/wiki/' + docs.title)
65958                 .call(svgIcon('#icon-out-link', 'inline'))
65959                 .append('span')
65960                 .text(t('inspector.reference'));
65961         });
65962     }
65963
65964
65965     function done() {
65966         loaded = true;
65967
65968         button.classed('tag-reference-loading', false);
65969
65970         body.transition()
65971             .duration(200)
65972             .style('max-height', '200px')
65973             .style('opacity', '1');
65974
65975         showing = true;
65976     }
65977
65978
65979     function hide(selection$$1) {
65980         selection$$1 = selection$$1 || body.transition().duration(200);
65981
65982         selection$$1
65983             .style('max-height', '0px')
65984             .style('opacity', '0');
65985
65986         showing = false;
65987     }
65988
65989
65990     tagReference.button = function(selection$$1) {
65991         button = selection$$1.selectAll('.tag-reference-button')
65992             .data([0]);
65993
65994         button = button.enter()
65995             .append('button')
65996             .attr('class', 'tag-reference-button')
65997             .attr('tabindex', -1)
65998             .call(svgIcon('#icon-inspect'))
65999             .merge(button);
66000
66001         button
66002             .on('click', function () {
66003                 event.stopPropagation();
66004                 event.preventDefault();
66005                 if (showing) {
66006                     hide();
66007                 } else if (loaded) {
66008                     done();
66009                 } else {
66010                     load(tag);
66011                 }
66012             });
66013     };
66014
66015
66016     tagReference.body = function(selection$$1) {
66017         body = selection$$1.selectAll('.tag-reference-body')
66018             .data([0]);
66019
66020         body = body.enter()
66021             .append('div')
66022             .attr('class', 'tag-reference-body cf')
66023             .style('max-height', '0')
66024             .style('opacity', '0')
66025             .merge(body);
66026
66027         if (showing === false) {
66028             hide(body);
66029         }
66030     };
66031
66032
66033     tagReference.showing = function(_) {
66034         if (!arguments.length) return showing;
66035         showing = _;
66036         return tagReference;
66037     };
66038
66039
66040     return tagReference;
66041 }
66042
66043 function uiRawTagEditor(context) {
66044     var taginfo = services.taginfo,
66045         dispatch$$1 = dispatch('change'),
66046         expanded = context.storage('raw_tag_editor.expanded') === 'true',
66047         readOnlyTags = [],
66048         updatePreference = true,
66049         showBlank = false,
66050         newRow,
66051         state,
66052         preset,
66053         tags,
66054         id;
66055
66056
66057     function rawTagEditor(selection$$1) {
66058         var count = Object.keys(tags).filter(function(d) { return d; }).length;
66059
66060         selection$$1.call(uiDisclosure()
66061             .title(t('inspector.all_tags') + ' (' + count + ')')
66062             .expanded(expanded)
66063             .on('toggled', toggled)
66064             .content(content)
66065         );
66066
66067         function toggled(expanded) {
66068             if (updatePreference) {
66069                 context.storage('raw_tag_editor.expanded', expanded);
66070             }
66071             if (expanded) {
66072                 selection$$1.node().parentNode.scrollTop += 200;
66073             }
66074         }
66075     }
66076
66077
66078     function content(wrap) {
66079         var entries$$1 = entries(tags);
66080
66081         if (!entries$$1.length || showBlank) {
66082             showBlank = false;
66083             entries$$1.push({key: '', value: ''});
66084             newRow = '';
66085         }
66086
66087         var list = wrap.selectAll('.tag-list')
66088             .data([0]);
66089
66090         list = list.enter()
66091             .append('ul')
66092             .attr('class', 'tag-list')
66093             .merge(list);
66094
66095         var newTag = wrap.selectAll('.add-tag')
66096             .data([0]);
66097
66098         newTag.enter()
66099             .append('button')
66100             .attr('class', 'add-tag')
66101             .on('click', addTag)
66102             .call(svgIcon('#icon-plus', 'light'));
66103
66104
66105         var items = list.selectAll('.tag-row')
66106             .data(entries$$1, function(d) { return d.key; });
66107
66108         items.exit()
66109             .each(unbind)
66110             .remove();
66111
66112         // Enter
66113
66114         var enter = items.enter()
66115             .append('li')
66116             .attr('class', 'tag-row cf')
66117             .classed('readonly', isReadOnly);
66118
66119         enter
66120             .append('div')
66121             .attr('class', 'key-wrap')
66122             .append('input')
66123             .property('type', 'text')
66124             .attr('class', 'key')
66125             .attr('maxlength', 255)
66126             .call(utilNoAuto)
66127             .on('blur', keyChange)
66128             .on('change', keyChange);
66129
66130         enter
66131             .append('div')
66132             .attr('class', 'input-wrap-position')
66133             .append('input')
66134             .property('type', 'text')
66135             .attr('class', 'value')
66136             .attr('maxlength', 255)
66137             .call(utilNoAuto)
66138             .on('blur', valueChange)
66139             .on('change', valueChange)
66140             .on('keydown.push-more', pushMore);
66141
66142         enter
66143             .append('button')
66144             .attr('tabindex', -1)
66145             .attr('class', 'remove minor')
66146             .call(svgIcon('#operation-delete'));
66147
66148
66149         // Update
66150
66151         items = items
66152             .merge(enter)
66153             .sort(function(a, b) {
66154                 return (a.key === newRow && b.key !== newRow) ? 1
66155                     : (a.key !== newRow && b.key === newRow) ? -1
66156                     : ascending(a.key, b.key);
66157             });
66158
66159         items
66160             .each(function(tag) {
66161                 var row = select(this),
66162                     key = row.select('input.key'),      // propagate bound data to child
66163                     value = row.select('input.value');  // propagate bound data to child
66164
66165                 if (id && taginfo) {
66166                     bindTypeahead(key, value);
66167                 }
66168
66169                 var isRelation = (id && context.entity(id).type === 'relation'),
66170                     reference;
66171
66172                 if (isRelation && tag.key === 'type') {
66173                     reference = uiTagReference({ rtype: tag.value }, context);
66174                 } else {
66175                     reference = uiTagReference({ key: tag.key, value: tag.value }, context);
66176                 }
66177
66178                 if (state === 'hover') {
66179                     reference.showing(false);
66180                 }
66181
66182                 row
66183                     .call(reference.button)
66184                     .call(reference.body);
66185             });
66186
66187         items.selectAll('input.key')
66188             .attr('title', function(d) { return d.key; })
66189             .call(utilGetSetValue, function(d) { return d.key; })
66190             .property('disabled', isReadOnly);
66191
66192         items.selectAll('input.value')
66193             .attr('title', function(d) { return d.value; })
66194             .call(utilGetSetValue, function(d) { return d.value; })
66195             .property('disabled', isReadOnly);
66196
66197         items.selectAll('button.remove')
66198             .on('click', removeTag);
66199
66200
66201
66202         function isReadOnly(d) {
66203             return readOnlyTags.indexOf(d.key) !== -1;
66204         }
66205
66206
66207         function pushMore() {
66208             if (event.keyCode === 9 && !event.shiftKey &&
66209                 list.selectAll('li:last-child input.value').node() === this) {
66210                 addTag();
66211             }
66212         }
66213
66214
66215         function bindTypeahead(key, value) {
66216             if (isReadOnly({ key: key })) return;
66217             var geometry = context.geometry(id);
66218
66219             key.call(d3combobox()
66220                 .container(context.container())
66221                 .fetcher(function(value, callback) {
66222                     taginfo.keys({
66223                         debounce: true,
66224                         geometry: geometry,
66225                         query: value
66226                     }, function(err, data) {
66227                         if (!err) callback(sort(value, data));
66228                     });
66229                 }));
66230
66231             value.call(d3combobox()
66232                 .container(context.container())
66233                 .fetcher(function(value, callback) {
66234                     taginfo.values({
66235                         debounce: true,
66236                         key: utilGetSetValue(key),
66237                         geometry: geometry,
66238                         query: value
66239                     }, function(err, data) {
66240                         if (!err) callback(sort(value, data));
66241                     });
66242                 }));
66243
66244
66245             function sort(value, data) {
66246                 var sameletter = [],
66247                     other = [];
66248                 for (var i = 0; i < data.length; i++) {
66249                     if (data[i].value.substring(0, value.length) === value) {
66250                         sameletter.push(data[i]);
66251                     } else {
66252                         other.push(data[i]);
66253                     }
66254                 }
66255                 return sameletter.concat(other);
66256             }
66257         }
66258
66259
66260         function unbind() {
66261             var row = select(this);
66262
66263             row.selectAll('input.key')
66264                 .call(d3combobox.off);
66265
66266             row.selectAll('input.value')
66267                 .call(d3combobox.off);
66268         }
66269
66270
66271         function keyChange(d) {
66272             var kOld = d.key,
66273                 kNew = this.value.trim(),
66274                 tag = {};
66275
66276
66277             if (isReadOnly({ key: kNew })) {
66278                 this.value = kOld;
66279                 return;
66280             }
66281
66282             if (kNew && kNew !== kOld) {
66283                 var match = kNew.match(/^(.*?)(?:_(\d+))?$/),
66284                     base = match[1],
66285                     suffix = +(match[2] || 1);
66286                 while (tags[kNew]) {  // rename key if already in use
66287                     kNew = base + '_' + suffix++;
66288                 }
66289             }
66290             tag[kOld] = undefined;
66291             tag[kNew] = d.value;
66292
66293             d.key = kNew; // Maintain DOM identity through the subsequent update.
66294
66295             if (newRow === kOld) {  // see if this row is still a new row
66296                 newRow = ((d.value === '' || kNew === '') ? kNew : undefined);
66297             }
66298
66299             this.value = kNew;
66300             dispatch$$1.call('change', this, tag);
66301         }
66302
66303
66304         function valueChange(d) {
66305             if (isReadOnly(d)) return;
66306             var tag = {};
66307             tag[d.key] = this.value;
66308
66309             if (newRow === d.key && d.key !== '' && d.value !== '') {   // not a new row anymore
66310                 newRow = undefined;
66311             }
66312
66313             dispatch$$1.call('change', this, tag);
66314         }
66315
66316
66317         function removeTag(d) {
66318             if (isReadOnly(d)) return;
66319             var tag = {};
66320             tag[d.key] = undefined;
66321             dispatch$$1.call('change', this, tag);
66322             select(this.parentNode).remove();
66323         }
66324
66325
66326         function addTag() {
66327             // Wrapped in a setTimeout in case it's being called from a blur
66328             // handler. Without the setTimeout, the call to `content` would
66329             // wipe out the pending value change.
66330             setTimeout(function() {
66331                 showBlank = true;
66332                 content(wrap);
66333                 list.selectAll('li:last-child input.key').node().focus();
66334             }, 0);
66335         }
66336     }
66337
66338
66339     rawTagEditor.state = function(_) {
66340         if (!arguments.length) return state;
66341         state = _;
66342         return rawTagEditor;
66343     };
66344
66345
66346     rawTagEditor.preset = function(_) {
66347         if (!arguments.length) return preset;
66348         preset = _;
66349         if (preset.isFallback()) {
66350             expanded = true;
66351             updatePreference = false;
66352         } else {
66353             expanded = context.storage('raw_tag_editor.expanded') === 'true';
66354             updatePreference = true;
66355         }
66356         return rawTagEditor;
66357     };
66358
66359
66360     rawTagEditor.tags = function(_) {
66361         if (!arguments.length) return tags;
66362         tags = _;
66363         return rawTagEditor;
66364     };
66365
66366
66367     rawTagEditor.entityID = function(_) {
66368         if (!arguments.length) return id;
66369         id = _;
66370         return rawTagEditor;
66371     };
66372
66373
66374     rawTagEditor.expanded = function(_) {
66375         if (!arguments.length) return expanded;
66376         expanded = _;
66377         updatePreference = false;
66378         return rawTagEditor;
66379     };
66380
66381
66382     rawTagEditor.readOnlyTags = function(_) {
66383         if (!arguments.length) return readOnlyTags;
66384         readOnlyTags = _;
66385         return rawTagEditor;
66386     };
66387
66388
66389     return utilRebind(rawTagEditor, dispatch$$1, 'on');
66390 }
66391
66392 function uiFieldCheck(field, context) {
66393     var dispatch$$1 = dispatch('change'),
66394         options = field.strings && field.strings.options,
66395         values$$1 = [],
66396         texts = [],
66397         input = select(null),
66398         text$$1 = select(null),
66399         label = select(null),
66400         reverser = select(null),
66401         impliedYes,
66402         entityId,
66403         value;
66404
66405
66406     if (options) {
66407         for (var k in options) {
66408             values$$1.push(k === 'undefined' ? undefined : k);
66409             texts.push(field.t('options.' + k, { 'default': options[k] }));
66410         }
66411     } else {
66412         values$$1 = [undefined, 'yes'];
66413         texts = [t('inspector.unknown'), t('inspector.check.yes')];
66414         if (field.type !== 'defaultCheck') {
66415             values$$1.push('no');
66416             texts.push(t('inspector.check.no'));
66417         }
66418     }
66419
66420
66421     // Checks tags to see whether an undefined value is "Assumed to be Yes"
66422     function checkImpliedYes() {
66423         impliedYes = (field.id === 'oneway_yes');
66424
66425         // hack: pretend `oneway` field is a `oneway_yes` field
66426         // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
66427         if (field.id === 'oneway') {
66428             var entity = context.entity(entityId);
66429             for (var key in entity.tags) {
66430                 if (key in osmOneWayTags && (entity.tags[key] in osmOneWayTags[key])) {
66431                     impliedYes = true;
66432                     texts[0] = t('presets.fields.oneway_yes.options.undefined');
66433                     break;
66434                 }
66435             }
66436         }
66437     }
66438
66439
66440     function reverserHidden() {
66441         if (!select('div.inspector-hover').empty()) return true;
66442         return !(value === 'yes' || (impliedYes && !value));
66443     }
66444
66445
66446     function reverserSetText(selection$$1) {
66447         var entity = context.hasEntity(entityId);
66448         if (reverserHidden() || !entity) return selection$$1;
66449
66450         var first = entity.first(),
66451             last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last(),
66452             pseudoDirection = first < last,
66453             icon = pseudoDirection ? '#icon-forward' : '#icon-backward';
66454
66455         selection$$1.selectAll('.reverser-span')
66456             .text(t('inspector.check.reverser'))
66457             .call(svgIcon(icon, 'inline'));
66458
66459         return selection$$1;
66460     }
66461
66462
66463     var check = function(selection$$1) {
66464         checkImpliedYes();
66465         selection$$1.classed('checkselect', 'true');
66466
66467         label = selection$$1.selectAll('.preset-input-wrap')
66468             .data([0]);
66469
66470         var enter = label.enter()
66471             .append('label')
66472             .attr('class', 'preset-input-wrap');
66473
66474         enter
66475             .append('input')
66476             .property('indeterminate', field.type !== 'defaultCheck')
66477             .attr('type', 'checkbox')
66478             .attr('id', 'preset-input-' + field.id);
66479
66480         enter
66481             .append('span')
66482             .text(texts[0])
66483             .attr('class', 'value');
66484
66485         if (field.type === 'onewayCheck') {
66486             enter
66487                 .append('a')
66488                 .attr('id', 'preset-input-' + field.id + '-reverser')
66489                 .attr('class', 'reverser button' + (reverserHidden() ? ' hide' : ''))
66490                 .attr('href', '#')
66491                 .append('span')
66492                 .attr('class', 'reverser-span');
66493         }
66494
66495         label = label.merge(enter);
66496         input = label.selectAll('input');
66497         text$$1 = label.selectAll('span.value');
66498
66499         input
66500             .on('click', function() {
66501                 var t$$1 = {};
66502                 t$$1[field.key] = values$$1[(values$$1.indexOf(value) + 1) % values$$1.length];
66503                 dispatch$$1.call('change', this, t$$1);
66504                 event.stopPropagation();
66505             });
66506
66507         if (field.type === 'onewayCheck') {
66508             reverser = label.selectAll('.reverser');
66509
66510             reverser
66511                 .call(reverserSetText)
66512                 .on('click', function() {
66513                     event.preventDefault();
66514                     event.stopPropagation();
66515                     context.perform(
66516                         actionReverse(entityId),
66517                         t('operations.reverse.annotation')
66518                     );
66519                     select(this)
66520                         .call(reverserSetText);
66521                 });
66522         }
66523     };
66524
66525
66526     check.entity = function(_) {
66527         if (!arguments.length) return context.hasEntity(entityId);
66528         entityId = _.id;
66529         return check;
66530     };
66531
66532
66533     check.tags = function(tags) {
66534         checkImpliedYes();
66535         value = tags[field.key] && tags[field.key].toLowerCase();
66536
66537         if (field.type === 'onewayCheck' && (value === '1' || value === '-1')) {
66538             value = 'yes';
66539         }
66540
66541         input
66542             .property('indeterminate', field.type !== 'defaultCheck' && !value)
66543             .property('checked', value === 'yes');
66544
66545         text$$1
66546             .text(texts[values$$1.indexOf(value)]);
66547
66548         label
66549             .classed('set', !!value);
66550
66551         if (field.type === 'onewayCheck') {
66552             reverser
66553                 .classed('hide', reverserHidden())
66554                 .call(reverserSetText);
66555         }
66556     };
66557
66558
66559     check.focus = function() {
66560         input.node().focus();
66561     };
66562
66563     return utilRebind(check, dispatch$$1, 'on');
66564 }
66565
66566 function uiFieldCombo(field, context) {
66567     var dispatch$$1 = dispatch('change'),
66568         nominatim = services.geocoder,
66569         taginfo = services.taginfo,
66570         isMulti = (field.type === 'multiCombo'),
66571         isNetwork = (field.type === 'networkCombo'),
66572         isSemi = (field.type === 'semiCombo'),
66573         optstrings = field.strings && field.strings.options,
66574         optarray = field.options,
66575         snake_case = (field.snake_case || (field.snake_case === undefined)),
66576         combobox = d3combobox()
66577             .container(context.container())
66578             .minItems(isMulti || isSemi ? 1 : 2),
66579         comboData = [],
66580         multiData = [],
66581         container,
66582         input,
66583         entity,
66584         country;
66585
66586     // ensure multiCombo field.key ends with a ':'
66587     if (isMulti && field.key.match(/:$/) === null) {
66588         field.key += ':';
66589     }
66590
66591
66592     function snake(s) {
66593         return s.replace(/\s+/g, '_');
66594     }
66595
66596     function unsnake(s) {
66597         return s.replace(/_+/g, ' ');
66598     }
66599
66600     function clean(s) {
66601         return s.split(';')
66602             .map(function(s) { return s.trim(); })
66603             .join(';');
66604     }
66605
66606
66607     // returns the tag value for a display value
66608     // (for multiCombo, dval should be the key suffix, not the entire key)
66609     function tagValue(dval) {
66610         dval = clean(dval || '');
66611
66612         if (optstrings) {
66613             var match = lodash.find(comboData, function(o) {
66614                 return o.key && clean(o.value) === dval;
66615             });
66616             if (match) {
66617                 return match.key;
66618             }
66619         }
66620
66621         if (field.type === 'typeCombo' && !dval) {
66622             return 'yes';
66623         }
66624
66625         return (snake_case ? snake(dval) : dval) || undefined;
66626     }
66627
66628
66629     // returns the display value for a tag value
66630     // (for multiCombo, tval should be the key suffix, not the entire key)
66631     function displayValue(tval) {
66632         tval = tval || '';
66633
66634         if (optstrings) {
66635             var match = lodash.find(comboData, function(o) { return o.key === tval && o.value; });
66636             if (match) {
66637                 return match.value;
66638             }
66639         }
66640
66641         if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
66642             return '';
66643         }
66644
66645         return snake_case ? unsnake(tval) : tval;
66646     }
66647
66648
66649     function objectDifference(a, b) {
66650         return lodash.reject(a, function(d1) {
66651             return lodash.some(b, function(d2) { return d1.value === d2.value; });
66652         });
66653     }
66654
66655
66656     function initCombo(selection$$1, attachTo) {
66657         if (optstrings) {
66658             selection$$1.attr('readonly', 'readonly');
66659             selection$$1.call(combobox, attachTo);
66660             setStaticValues(setPlaceholder);
66661
66662         } else if (optarray) {
66663             selection$$1.call(combobox, attachTo);
66664             setStaticValues(setPlaceholder);
66665
66666         } else if (taginfo) {
66667             selection$$1.call(combobox.fetcher(setTaginfoValues), attachTo);
66668             setTaginfoValues('', setPlaceholder);
66669         }
66670     }
66671
66672
66673     function setStaticValues(callback) {
66674         if (!(optstrings || optarray)) return;
66675
66676         if (optstrings) {
66677             comboData = Object.keys(optstrings).map(function(k) {
66678                 var v = field.t('options.' + k, { 'default': optstrings[k] });
66679                 return {
66680                     key: k,
66681                     value: v,
66682                     title: v
66683                 };
66684             });
66685
66686         } else if (optarray) {
66687             comboData = optarray.map(function(k) {
66688                 var v = snake_case ? unsnake(k) : k;
66689                 return {
66690                     key: k,
66691                     value: v,
66692                     title: v
66693                 };
66694             });
66695         }
66696
66697         combobox.data(objectDifference(comboData, multiData));
66698         if (callback) callback(comboData);
66699     }
66700
66701
66702     function setTaginfoValues(q, callback) {
66703         var fn = isMulti ? 'multikeys' : 'values';
66704         var query = (isMulti ? field.key : '') + q;
66705         var hasCountryPrefix = isNetwork && country && country.indexOf(q.toLowerCase()) === 0;
66706         if (hasCountryPrefix) {
66707             query = country + ':';
66708         }
66709
66710         taginfo[fn]({
66711             debounce: (q !== ''),
66712             key: field.key,
66713             geometry: context.geometry(entity.id),
66714             query: query
66715         }, function(err, data) {
66716             if (err) return;
66717             if (hasCountryPrefix) {
66718                 data = lodash.filter(data, function(d) {
66719                     return d.value.toLowerCase().indexOf(country + ':') === 0;
66720                 });
66721             }
66722
66723             comboData = lodash.map(data, function(d) {
66724                 var k = d.value;
66725                 if (isMulti) k = k.replace(field.key, '');
66726                 var v = snake_case ? unsnake(k) : k;
66727                 return {
66728                     key: k,
66729                     value: v,
66730                     title: isMulti ? v : d.title
66731                 };
66732             });
66733
66734             comboData = objectDifference(comboData, multiData);
66735             if (callback) callback(comboData);
66736         });
66737     }
66738
66739
66740     function setPlaceholder(d) {
66741         var ph;
66742
66743         if (isMulti || isSemi) {
66744             ph = field.placeholder() || t('inspector.add');
66745         } else {
66746             var vals = lodash.map(d, 'value').filter(function(s) { return s.length < 20; }),
66747                 placeholders = vals.length > 1 ? vals : lodash.map(d, 'key');
66748             ph = field.placeholder() || placeholders.slice(0, 3).join(', ');
66749         }
66750
66751         if (ph.match(/(…|\.\.\.)$/) === null) {
66752             ph += '…';
66753         }
66754
66755         container.selectAll('input')
66756             .attr('placeholder', ph);
66757     }
66758
66759
66760     function change() {
66761         var val = tagValue(utilGetSetValue(input)),
66762             t$$1 = {};
66763
66764         if (isMulti || isSemi) {
66765             if (!val) return;
66766             container.classed('active', false);
66767             utilGetSetValue(input, '');
66768             if (isMulti) {
66769                 field.keys.push(field.key + val);
66770                 t$$1[field.key + val] = 'yes';
66771             } else if (isSemi) {
66772                 var arr = multiData.map(function(d) { return d.key; });
66773                 arr.push(val);
66774                 t$$1[field.key] = lodash.compact(lodash.uniq(arr)).join(';');
66775             }
66776             window.setTimeout(function() { input.node().focus(); }, 10);
66777
66778         } else {
66779             t$$1[field.key] = val;
66780         }
66781
66782         dispatch$$1.call('change', this, t$$1);
66783     }
66784
66785
66786     function removeMultikey(d) {
66787         event.stopPropagation();
66788         var t$$1 = {};
66789         if (isMulti) {
66790             t$$1[d.key] = undefined;
66791         } else if (isSemi) {
66792             lodash.remove(multiData, function(md) { return md.key === d.key; });
66793             var arr = multiData.map(function(md) { return md.key; });
66794             arr = lodash.compact(lodash.uniq(arr));
66795             t$$1[field.key] = arr.length ? arr.join(';') : undefined;
66796         }
66797         dispatch$$1.call('change', this, t$$1);
66798     }
66799
66800
66801     function combo(selection$$1) {
66802         if (isMulti || isSemi) {
66803             container = selection$$1.selectAll('ul').data([0]);
66804
66805             container = container.enter()
66806                 .append('ul')
66807                 .attr('class', 'form-field-multicombo')
66808                 .on('click', function() {
66809                     window.setTimeout(function() { input.node().focus(); }, 10);
66810                 })
66811                 .merge(container);
66812
66813         } else {
66814             container = selection$$1;
66815         }
66816
66817         input = container.selectAll('input')
66818             .data([0]);
66819
66820         input = input.enter()
66821             .append('input')
66822             .attr('type', 'text')
66823             .attr('id', 'preset-input-' + field.id)
66824             .call(utilNoAuto)
66825             .call(initCombo, selection$$1)
66826             .merge(input);
66827
66828         if (isNetwork && nominatim && entity) {
66829             var center = entity.extent(context.graph()).center();
66830             nominatim.countryCode(center, function (err, code) {
66831                 country = code;
66832             });
66833         }
66834
66835         input
66836             .on('change', change)
66837             .on('blur', change);
66838
66839         if (isMulti || isSemi) {
66840             combobox
66841                 .on('accept', function() {
66842                     input.node().blur();
66843                     input.node().focus();
66844                 });
66845
66846             input
66847                 .on('focus', function() { container.classed('active', true); });
66848         }
66849     }
66850
66851
66852     combo.tags = function(tags) {
66853         if (isMulti || isSemi) {
66854             multiData = [];
66855
66856             if (isMulti) {
66857                 // Build multiData array containing keys already set..
66858                 Object.keys(tags).forEach(function(key) {
66859                     if (key.indexOf(field.key) !== 0 || tags[key].toLowerCase() !== 'yes') return;
66860
66861                     var suffix = key.substring(field.key.length);
66862                     multiData.push({
66863                         key: key,
66864                         value: displayValue(suffix)
66865                     });
66866                 });
66867
66868                 // Set keys for form-field modified (needed for undo and reset buttons)..
66869                 field.keys = lodash.map(multiData, 'key');
66870
66871             } else if (isSemi) {
66872                 var arr = lodash.compact(lodash.uniq((tags[field.key] || '').split(';')));
66873                 multiData = arr.map(function(key) {
66874                     return {
66875                         key: key,
66876                         value: displayValue(key)
66877                     };
66878                 });
66879             }
66880
66881             // Exclude existing multikeys from combo options..
66882             var available = objectDifference(comboData, multiData);
66883             combobox.data(available);
66884
66885             // Hide 'Add' button if this field uses fixed set of
66886             // translateable optstrings and they're all currently used..
66887             container.selectAll('.combobox-input, .combobox-caret')
66888                 .classed('hide', optstrings && !available.length);
66889
66890
66891             // Render chips
66892             var chips = container.selectAll('.chips')
66893                 .data(multiData);
66894
66895             chips.exit()
66896                 .remove();
66897
66898             var enter = chips.enter()
66899                 .insert('li', 'input')
66900                 .attr('class', 'chips');
66901
66902             enter.append('span');
66903             enter.append('a');
66904
66905             chips = chips.merge(enter);
66906
66907             chips.select('span')
66908                 .text(function(d) { return d.value; });
66909
66910             chips.select('a')
66911                 .on('click', removeMultikey)
66912                 .attr('class', 'remove')
66913                 .text('×');
66914
66915         } else {
66916             utilGetSetValue(input, displayValue(tags[field.key]));
66917         }
66918     };
66919
66920
66921     combo.focus = function() {
66922         input.node().focus();
66923     };
66924
66925
66926     combo.entity = function(_) {
66927         if (!arguments.length) return entity;
66928         entity = _;
66929         return combo;
66930     };
66931
66932
66933     return utilRebind(combo, dispatch$$1, 'on');
66934 }
66935
66936 function uiFieldText(field, context) {
66937     var dispatch$$1 = dispatch('change'),
66938         nominatim = services.geocoder,
66939         input,
66940         entity;
66941
66942
66943     function i(selection$$1) {
66944         var fieldId = 'preset-input-' + field.id;
66945
66946         input = selection$$1.selectAll('input')
66947             .data([0]);
66948
66949         input = input.enter()
66950             .append('input')
66951             .attr('type', field.type)
66952             .attr('id', fieldId)
66953             .attr('placeholder', field.placeholder() || t('inspector.unknown'))
66954             .call(utilNoAuto)
66955             .merge(input);
66956
66957         input
66958             .on('input', change(true))
66959             .on('blur', change())
66960             .on('change', change());
66961
66962         if (field.type === 'tel' && nominatim && entity) {
66963             var center = entity.extent(context.graph()).center();
66964             nominatim.countryCode(center, function (err, countryCode) {
66965                 if (err || !dataPhoneFormats[countryCode]) return;
66966                 selection$$1.selectAll('#' + fieldId)
66967                     .attr('placeholder', dataPhoneFormats[countryCode]);
66968             });
66969
66970         } else if (field.type === 'number') {
66971             input.attr('type', 'text');
66972
66973             var spinControl = selection$$1.selectAll('.spin-control')
66974                 .data([0]);
66975
66976             var enter = spinControl.enter()
66977                 .append('div')
66978                 .attr('class', 'spin-control');
66979
66980             enter
66981                 .append('button')
66982                 .datum(-1)
66983                 .attr('class', 'decrement')
66984                 .attr('tabindex', -1);
66985
66986             enter
66987                 .append('button')
66988                 .datum(1)
66989                 .attr('class', 'increment')
66990                 .attr('tabindex', -1);
66991
66992             spinControl = spinControl
66993                 .merge(enter);
66994
66995             spinControl.selectAll('button')
66996                 .on('click', function(d) {
66997                     event.preventDefault();
66998                     var num = parseInt(input.node().value || 0, 10);
66999                     if (!isNaN(num)) input.node().value = num + d;
67000                     change()();
67001                 });
67002         }
67003     }
67004
67005
67006     function change(onInput) {
67007         return function() {
67008             var t$$1 = {};
67009             t$$1[field.key] = utilGetSetValue(input) || undefined;
67010             dispatch$$1.call('change', this, t$$1, onInput);
67011         };
67012     }
67013
67014
67015     i.entity = function(_) {
67016         if (!arguments.length) return entity;
67017         entity = _;
67018         return i;
67019     };
67020
67021
67022     i.tags = function(tags) {
67023         utilGetSetValue(input, tags[field.key] || '');
67024     };
67025
67026
67027     i.focus = function() {
67028         var node = input.node();
67029         if (node) node.focus();
67030     };
67031
67032     return utilRebind(i, dispatch$$1, 'on');
67033 }
67034
67035 function uiFieldAccess(field, context) {
67036     var dispatch$$1 = dispatch('change'),
67037         items;
67038
67039     function access(selection$$1) {
67040         var wrap = selection$$1.selectAll('.preset-input-wrap')
67041             .data([0]);
67042
67043         wrap = wrap.enter()
67044             .append('div')
67045             .attr('class', 'cf preset-input-wrap')
67046             .append('ul')
67047             .merge(wrap);
67048
67049         var list = wrap.selectAll('ul')
67050             .data([0]);
67051
67052         list = list.enter()
67053             .append('ul')
67054             .merge(list);
67055
67056
67057         items = list.selectAll('li')
67058             .data(field.keys);
67059
67060         // Enter
67061         var enter = items.enter()
67062             .append('li')
67063             .attr('class', function(d) { return 'cf preset-access-' + d; });
67064
67065         enter
67066             .append('span')
67067             .attr('class', 'col6 label preset-label-access')
67068             .attr('for', function(d) { return 'preset-input-access-' + d; })
67069             .text(function(d) { return field.t('types.' + d); });
67070
67071         enter
67072             .append('div')
67073             .attr('class', 'col6 preset-input-access-wrap')
67074             .append('input')
67075             .attr('type', 'text')
67076             .attr('class', 'preset-input-access')
67077             .attr('id', function(d) { return 'preset-input-access-' + d; })
67078             .call(utilNoAuto)
67079             .each(function(d) {
67080                 select(this)
67081                     .call(d3combobox()
67082                         .container(context.container())
67083                         .data(access.options(d))
67084                     );
67085             });
67086
67087
67088         // Update
67089         items = items.merge(enter);
67090
67091         wrap.selectAll('.preset-input-access')
67092             .on('change', change)
67093             .on('blur', change);
67094     }
67095
67096
67097     function change(d) {
67098         var tag = {};
67099         tag[d] = utilGetSetValue(select(this)) || undefined;
67100         dispatch$$1.call('change', this, tag);
67101     }
67102
67103
67104     access.options = function(type) {
67105         var options = ['no', 'permissive', 'private', 'destination'];
67106
67107         if (type !== 'access') {
67108             options.unshift('yes');
67109             options.push('designated');
67110
67111             if (type === 'bicycle') {
67112                 options.push('dismount');
67113             }
67114         }
67115
67116         return options.map(function(option) {
67117             return {
67118                 title: field.t('options.' + option + '.description'),
67119                 value: option
67120             };
67121         });
67122     };
67123
67124
67125     var placeholders = {
67126         footway: {
67127             foot: 'designated',
67128             motor_vehicle: 'no'
67129         },
67130         steps: {
67131             foot: 'yes',
67132             motor_vehicle: 'no',
67133             bicycle: 'no',
67134             horse: 'no'
67135         },
67136         pedestrian: {
67137             foot: 'yes',
67138             motor_vehicle: 'no'
67139         },
67140         cycleway: {
67141             motor_vehicle: 'no',
67142             bicycle: 'designated'
67143         },
67144         bridleway: {
67145             motor_vehicle: 'no',
67146             horse: 'designated'
67147         },
67148         path: {
67149             foot: 'yes',
67150             motor_vehicle: 'no',
67151             bicycle: 'yes',
67152             horse: 'yes'
67153         },
67154         motorway: {
67155             foot: 'no',
67156             motor_vehicle: 'yes',
67157             bicycle: 'no',
67158             horse: 'no'
67159         },
67160         trunk: {
67161             motor_vehicle: 'yes'
67162         },
67163         primary: {
67164             foot: 'yes',
67165             motor_vehicle: 'yes',
67166             bicycle: 'yes',
67167             horse: 'yes'
67168         },
67169         secondary: {
67170             foot: 'yes',
67171             motor_vehicle: 'yes',
67172             bicycle: 'yes',
67173             horse: 'yes'
67174         },
67175         tertiary: {
67176             foot: 'yes',
67177             motor_vehicle: 'yes',
67178             bicycle: 'yes',
67179             horse: 'yes'
67180         },
67181         residential: {
67182             foot: 'yes',
67183             motor_vehicle: 'yes',
67184             bicycle: 'yes',
67185             horse: 'yes'
67186         },
67187         unclassified: {
67188             foot: 'yes',
67189             motor_vehicle: 'yes',
67190             bicycle: 'yes',
67191             horse: 'yes'
67192         },
67193         service: {
67194             foot: 'yes',
67195             motor_vehicle: 'yes',
67196             bicycle: 'yes',
67197             horse: 'yes'
67198         },
67199         motorway_link: {
67200             foot: 'no',
67201             motor_vehicle: 'yes',
67202             bicycle: 'no',
67203             horse: 'no'
67204         },
67205         trunk_link: {
67206             motor_vehicle: 'yes'
67207         },
67208         primary_link: {
67209             foot: 'yes',
67210             motor_vehicle: 'yes',
67211             bicycle: 'yes',
67212             horse: 'yes'
67213         },
67214         secondary_link: {
67215             foot: 'yes',
67216             motor_vehicle: 'yes',
67217             bicycle: 'yes',
67218             horse: 'yes'
67219         },
67220         tertiary_link: {
67221             foot: 'yes',
67222             motor_vehicle: 'yes',
67223             bicycle: 'yes',
67224             horse: 'yes'
67225         }
67226     };
67227
67228
67229     access.tags = function(tags) {
67230         utilGetSetValue(items.selectAll('.preset-input-access'),
67231             function(d) { return tags[d] || ''; })
67232             .attr('placeholder', function() {
67233                 return tags.access ? tags.access : field.placeholder();
67234             });
67235
67236         items.selectAll('#preset-input-access-access')
67237             .attr('placeholder', 'yes');
67238
67239         lodash.forEach(placeholders[tags.highway], function(v, k) {
67240             items.selectAll('#preset-input-access-' + k)
67241                 .attr('placeholder', function() { return (tags.access || v); });
67242         });
67243     };
67244
67245
67246     access.focus = function() {
67247         items.selectAll('.preset-input-access')
67248             .node().focus();
67249     };
67250
67251
67252     return utilRebind(access, dispatch$$1, 'on');
67253 }
67254
67255 function uiFieldAddress(field, context) {
67256     var dispatch$$1 = dispatch('init', 'change'),
67257         nominatim = services.geocoder,
67258         wrap = select(null),
67259         isInitialized = false,
67260         entity;
67261
67262     function getNearStreets() {
67263         var extent$$1 = entity.extent(context.graph()),
67264             l = extent$$1.center(),
67265             box = geoExtent$$1(l).padByMeters(200);
67266
67267         var streets = context.intersects(box)
67268             .filter(isAddressable)
67269             .map(function(d) {
67270                 var loc = context.projection([
67271                     (extent$$1[0][0] + extent$$1[1][0]) / 2,
67272                     (extent$$1[0][1] + extent$$1[1][1]) / 2]),
67273                     choice = geoChooseEdge(context.childNodes(d), loc, context.projection);
67274                 return {
67275                     title: d.tags.name,
67276                     value: d.tags.name,
67277                     dist: choice.distance
67278                 };
67279             })
67280             .sort(function(a, b) {
67281                 return a.dist - b.dist;
67282             });
67283
67284         return lodash.uniqBy(streets, 'value');
67285
67286         function isAddressable(d) {
67287             return d.tags.highway && d.tags.name && d.type === 'way';
67288         }
67289     }
67290
67291
67292     function getNearCities() {
67293         var extent$$1 = entity.extent(context.graph()),
67294             l = extent$$1.center(),
67295             box = geoExtent$$1(l).padByMeters(200);
67296
67297         var cities = context.intersects(box)
67298             .filter(isAddressable)
67299             .map(function(d) {
67300                 return {
67301                     title: d.tags['addr:city'] || d.tags.name,
67302                     value: d.tags['addr:city'] || d.tags.name,
67303                     dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
67304                 };
67305             })
67306             .sort(function(a, b) {
67307                 return a.dist - b.dist;
67308             });
67309
67310         return lodash.uniqBy(cities, 'value');
67311
67312
67313         function isAddressable(d) {
67314             if (d.tags.name &&
67315                 (d.tags.admin_level === '8' || d.tags.border_type === 'city'))
67316                 return true;
67317
67318             if (d.tags.place && d.tags.name && (
67319                     d.tags.place === 'city' ||
67320                     d.tags.place === 'town' ||
67321                     d.tags.place === 'village'))
67322                 return true;
67323
67324             if (d.tags['addr:city']) return true;
67325
67326             return false;
67327         }
67328     }
67329
67330     function getNearValues(key) {
67331         var extent$$1 = entity.extent(context.graph()),
67332             l = extent$$1.center(),
67333             box = geoExtent$$1(l).padByMeters(200);
67334
67335         var results = context.intersects(box)
67336             .filter(function hasTag(d) {
67337                 return d.tags[key];
67338             })
67339             .map(function(d) {
67340                 return {
67341                     title: d.tags[key],
67342                     value: d.tags[key],
67343                     dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
67344                 };
67345             })
67346             .sort(function(a, b) {
67347                 return a.dist - b.dist;
67348             });
67349
67350         return lodash.uniqBy(results, 'value');
67351     }
67352
67353
67354     function initCallback(err, countryCode) {
67355         if (err) return;
67356
67357         var addressFormat = lodash.find(dataAddressFormats, function (a) {
67358             return a && a.countryCodes && lodash.includes(a.countryCodes, countryCode.toLowerCase());
67359         }) || lodash.first(dataAddressFormats);
67360
67361         var widths = addressFormat.widths || {
67362             housenumber: 1/3, street: 2/3,
67363             city: 2/3, state: 1/4, postcode: 1/3
67364         };
67365
67366         function row(r) {
67367             // Normalize widths.
67368             var total = lodash.reduce(r, function(sum$$1, field) {
67369                 return sum$$1 + (widths[field] || 0.5);
67370             }, 0);
67371
67372             return r.map(function (field) {
67373                 return {
67374                     id: field,
67375                     width: (widths[field] || 0.5) / total
67376                 };
67377             });
67378         }
67379
67380         wrap.selectAll('div.addr-row')
67381             .data(addressFormat.format)
67382             .enter()
67383             .append('div')
67384             .attr('class', 'addr-row')
67385             .selectAll('input')
67386             .data(row)
67387             .enter()
67388             .append('input')
67389             .property('type', 'text')
67390             .attr('placeholder', function (d) {
67391                 var localkey = d.id + '!' + countryCode.toLowerCase(),
67392                     tkey = field.strings.placeholders[localkey] ? localkey : d.id;
67393                 return field.t('placeholders.' + tkey);
67394             })
67395             .attr('class', function (d) { return 'addr-' + d.id; })
67396             .call(utilNoAuto)
67397             .style('width', function (d) { return d.width * 100 + '%'; });
67398
67399         // Update
67400
67401         // setup dropdowns for common address tags
67402         var dropdowns = addressFormat.dropdowns || [
67403             'city', 'county', 'country', 'district', 'hamlet',
67404             'neighbourhood', 'place', 'postcode', 'province',
67405             'quarter', 'state', 'street', 'subdistrict', 'suburb'
67406         ];
67407
67408         // If fields exist for any of these tags, create dropdowns to pick nearby values..
67409         dropdowns.forEach(function(tag) {
67410             var nearValues = (tag === 'street') ? getNearStreets
67411                     : (tag === 'city') ? getNearCities
67412                     : getNearValues;
67413
67414             wrap.selectAll('input.addr-' + tag)
67415                 .call(d3combobox()
67416                     .container(context.container())
67417                     .minItems(1)
67418                     .fetcher(function(value, callback) {
67419                         callback(nearValues('addr:' + tag));
67420                     })
67421                 );
67422         });
67423
67424         wrap.selectAll('input')
67425             .on('blur', change())
67426             .on('change', change());
67427
67428         wrap.selectAll('input:not(.combobox-input)')
67429             .on('input', change(true));
67430
67431         dispatch$$1.call('init');
67432         isInitialized = true;
67433     }
67434
67435
67436     function address(selection$$1) {
67437         isInitialized = false;
67438
67439         wrap = selection$$1.selectAll('.preset-input-wrap')
67440             .data([0]);
67441
67442         wrap = wrap.enter()
67443             .append('div')
67444             .attr('class', 'preset-input-wrap')
67445             .merge(wrap);
67446
67447         if (nominatim && entity) {
67448             var center = entity.extent(context.graph()).center();
67449             nominatim.countryCode(center, initCallback);
67450         }
67451     }
67452
67453
67454     function change(onInput) {
67455         return function() {
67456             var tags = {};
67457
67458             wrap.selectAll('input')
67459                 .each(function (field) {
67460                     tags['addr:' + field.id] = this.value || undefined;
67461                 });
67462
67463             dispatch$$1.call('change', this, tags, onInput);
67464         };
67465     }
67466
67467
67468     function updateTags(tags) {
67469         utilGetSetValue(wrap.selectAll('input'), function (field) {
67470             return tags['addr:' + field.id] || '';
67471         });
67472     }
67473
67474
67475     address.entity = function(_) {
67476         if (!arguments.length) return entity;
67477         entity = _;
67478         return address;
67479     };
67480
67481
67482     address.tags = function(tags) {
67483         if (isInitialized) {
67484             updateTags(tags);
67485         } else {
67486             dispatch$$1.on('init', function () {
67487                 dispatch$$1.on('init', null);
67488                 updateTags(tags);
67489             });
67490         }
67491     };
67492
67493
67494     address.focus = function() {
67495         var node = wrap.selectAll('input').node();
67496         if (node) node.focus();
67497     };
67498
67499
67500     return utilRebind(address, dispatch$$1, 'on');
67501 }
67502
67503 function uiFieldCycleway(field, context) {
67504     var dispatch$$1 = dispatch('change'),
67505         items = select(null);
67506
67507
67508     function cycleway(selection$$1) {
67509
67510         function stripcolon(s) {
67511             return s.replace(':', '');
67512         }
67513
67514
67515         var wrap = selection$$1.selectAll('.preset-input-wrap')
67516             .data([0]);
67517
67518         wrap = wrap.enter()
67519             .append('div')
67520             .attr('class', 'cf preset-input-wrap')
67521             .merge(wrap);
67522
67523
67524         var div = wrap.selectAll('ul')
67525             .data([0]);
67526
67527         div = div.enter()
67528             .append('ul')
67529             .merge(div);
67530
67531
67532         items = div.selectAll('li')
67533             .data(field.keys);
67534
67535         var enter = items.enter()
67536             .append('li')
67537             .attr('class', function(d) { return 'cf preset-cycleway-' + stripcolon(d); });
67538
67539         enter
67540             .append('span')
67541             .attr('class', 'col6 label preset-label-cycleway')
67542             .attr('for', function(d) { return 'preset-input-cycleway-' + stripcolon(d); })
67543             .text(function(d) { return field.t('types.' + d); });
67544
67545         enter
67546             .append('div')
67547             .attr('class', 'col6 preset-input-cycleway-wrap')
67548             .append('input')
67549             .attr('type', 'text')
67550             .attr('class', function(d) { return 'preset-input-cycleway preset-input-' + stripcolon(d); })
67551             .call(utilNoAuto)
67552             .each(function(d) {
67553                 select(this)
67554                     .call(d3combobox()
67555                         .container(context.container())
67556                         .data(cycleway.options(d))
67557                     );
67558             });
67559
67560
67561         // Update
67562         wrap.selectAll('.preset-input-cycleway')
67563             .on('change', change)
67564             .on('blur', change);
67565     }
67566
67567
67568     function change() {
67569         var left = utilGetSetValue(select('.preset-input-cyclewayleft')),
67570             right = utilGetSetValue(select('.preset-input-cyclewayright')),
67571             tag = {};
67572
67573         if (left === 'none' || left === '') { left = undefined; }
67574         if (right === 'none' || right === '') { right = undefined; }
67575
67576         // Always set both left and right as changing one can affect the other
67577         tag = {
67578             cycleway: undefined,
67579             'cycleway:left': left,
67580             'cycleway:right': right
67581         };
67582
67583         // If the left and right tags match, use the cycleway tag to tag both
67584         // sides the same way
67585         if (left === right) {
67586             tag = {
67587                 cycleway: left,
67588                 'cycleway:left': undefined,
67589                 'cycleway:right': undefined
67590             };
67591         }
67592
67593         dispatch$$1.call('change', this, tag);
67594     }
67595
67596
67597     cycleway.options = function() {
67598         return keys(field.strings.options).map(function(option) {
67599             return {
67600                 title: field.t('options.' + option + '.description'),
67601                 value: option
67602             };
67603         });
67604     };
67605
67606
67607     cycleway.tags = function(tags) {
67608         utilGetSetValue(items.selectAll('.preset-input-cycleway'), function(d) {
67609                 // If cycleway is set, always return that
67610                 if (tags.cycleway) {
67611                     return tags.cycleway;
67612                 }
67613                 return tags[d] || '';
67614             })
67615             .attr('placeholder', field.placeholder());
67616     };
67617
67618
67619     cycleway.focus = function() {
67620         items.selectAll('.preset-input-cycleway')
67621             .node().focus();
67622     };
67623
67624
67625     return utilRebind(cycleway, dispatch$$1, 'on');
67626 }
67627
67628 function uiFieldLanes(field, context) {
67629     var dispatch$$1 = dispatch('change'),
67630         LANE_WIDTH = 40,
67631         LANE_HEIGHT = 200,
67632         wayID,
67633         lanesData;
67634
67635     function lanes(selection$$1) {
67636         lanesData = context.entity(wayID).lanes();
67637
67638         if (!select('.inspector-wrap.inspector-hidden').empty() || !selection$$1.node().parentNode) {
67639             selection$$1.call(lanes.off);
67640             return;
67641         }
67642
67643         var wrap = selection$$1.selectAll('.preset-input-wrap')
67644             .data([0]);
67645
67646         wrap = wrap.enter()
67647             .append('div')
67648             .attr('class', 'preset-input-wrap')
67649             .merge(wrap);
67650
67651         var surface =  wrap.selectAll('.surface')
67652             .data([0]);
67653
67654         var d = utilGetDimensions(wrap);
67655         var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
67656
67657         surface = surface.enter()
67658             .append('svg')
67659             .attr('width', d[0])
67660             .attr('height', 300)
67661             .attr('class', 'surface')
67662             .merge(surface);
67663
67664
67665         var lanesSelection = surface.selectAll('.lanes')
67666             .data([0]);
67667
67668         lanesSelection = lanesSelection.enter()
67669             .append('g')
67670             .attr('class', 'lanes')
67671             .merge(lanesSelection);
67672
67673         lanesSelection
67674             .attr('transform', function () {
67675                 return 'translate(' + (freeSpace / 2) + ', 0)';
67676             });
67677
67678
67679         var lane = lanesSelection.selectAll('.lane')
67680            .data(lanesData.lanes);
67681
67682         lane.exit()
67683             .remove();
67684
67685         var enter = lane.enter()
67686             .append('g')
67687             .attr('class', 'lane');
67688
67689         enter
67690             .append('g')
67691             .append('rect')
67692             .attr('y', 50)
67693             .attr('width', LANE_WIDTH)
67694             .attr('height', LANE_HEIGHT);
67695
67696         enter
67697             .append('g')
67698             .attr('class', 'forward')
67699             .append('text')
67700             .attr('y', 40)
67701             .attr('x', 14)
67702             .text('▲');
67703
67704         enter
67705             .append('g')
67706             .attr('class', 'bothways')
67707             .append('text')
67708             .attr('y', 40)
67709             .attr('x', 14)
67710             .text('▲▼');
67711
67712         enter
67713             .append('g')
67714             .attr('class', 'backward')
67715             .append('text')
67716             .attr('y', 40)
67717             .attr('x', 14)
67718             .text('▼');
67719
67720
67721         lane = lane
67722             .merge(enter);
67723
67724         lane
67725             .attr('transform', function(d) {
67726                 return 'translate(' + (LANE_WIDTH * d.index * 1.5) + ', 0)';
67727             });
67728
67729         lane.select('.forward')
67730             .style('visibility', function(d) {
67731                 return d.direction === 'forward' ? 'visible' : 'hidden';
67732             });
67733
67734         lane.select('.bothways')
67735             .style('visibility', function(d) {
67736                 return d.direction === 'bothways' ? 'visible' : 'hidden';
67737             });
67738
67739         lane.select('.backward')
67740             .style('visibility', function(d) {
67741                 return d.direction === 'backward' ? 'visible' : 'hidden';
67742             });
67743     }
67744
67745
67746     lanes.entity = function(_) {
67747         if (!wayID || wayID !== _.id) {
67748             wayID = _.id;
67749         }
67750     };
67751
67752     lanes.tags = function() {};
67753     lanes.focus = function() {};
67754     lanes.off = function() {};
67755
67756     return utilRebind(lanes, dispatch$$1, 'on');
67757 }
67758
67759 function uiFieldLocalized(field, context) {
67760     var dispatch$$1 = dispatch('change', 'input'),
67761         wikipedia = services.wikipedia,
67762         input = select(null),
67763         localizedInputs = select(null),
67764         wikiTitles,
67765         entity;
67766
67767
67768     function localized(selection$$1) {
67769         input = selection$$1.selectAll('.localized-main')
67770             .data([0]);
67771
67772         input = input.enter()
67773             .append('input')
67774             .attr('type', 'text')
67775             .attr('id', 'preset-input-' + field.id)
67776             .attr('class', 'localized-main')
67777             .attr('placeholder', field.placeholder())
67778             .call(utilNoAuto)
67779             .merge(input);
67780
67781         if (field.id === 'name') {
67782             var preset = context.presets().match(entity, context.graph());
67783             input
67784                 .call(d3combobox()
67785                     .container(context.container())
67786                     .fetcher(utilSuggestNames(preset, dataSuggestions))
67787                 );
67788         }
67789
67790         input
67791             .on('input', change(true))
67792             .on('blur', change())
67793             .on('change', change());
67794
67795
67796         var translateButton = selection$$1.selectAll('.localized-add')
67797             .data([0]);
67798
67799         translateButton = translateButton.enter()
67800             .append('button')
67801             .attr('class', 'button-input-action localized-add minor')
67802             .attr('tabindex', -1)
67803             .call(svgIcon('#icon-plus'))
67804             .call(tooltip()
67805                 .title(t('translate.translate'))
67806                 .placement('left'))
67807             .merge(translateButton);
67808
67809         translateButton
67810             .on('click', addNew);
67811
67812
67813         localizedInputs = selection$$1.selectAll('.localized-wrap')
67814             .data([0]);
67815
67816         localizedInputs = localizedInputs.enter().append('div')
67817             .attr('class', 'localized-wrap')
67818             .merge(localizedInputs);
67819     }
67820
67821
67822     function addNew() {
67823         event.preventDefault();
67824         var data$$1 = localizedInputs.selectAll('div.entry').data();
67825         var defaultLang = utilDetect().locale.toLowerCase().split('-')[0];
67826         var langExists = lodash.find(data$$1, function(datum) { return datum.lang === defaultLang;});
67827         var isLangEn = defaultLang.indexOf('en') > -1;
67828         if (isLangEn || langExists) {
67829             defaultLang = '';
67830         }
67831         data$$1.push({ lang: defaultLang, value: '' });
67832         localizedInputs.call(render, data$$1);
67833     }
67834
67835
67836     function change(onInput) {
67837         return function() {
67838             var t$$1 = {};
67839             t$$1[field.key] = utilGetSetValue(select(this)) || undefined;
67840             dispatch$$1.call('change', this, t$$1, onInput);
67841         };
67842     }
67843
67844
67845     function key(lang) {
67846         return field.key + ':' + lang;
67847     }
67848
67849
67850     function changeLang(d) {
67851         var lang = utilGetSetValue(select(this)),
67852             t$$1 = {},
67853             language = lodash.find(dataWikipedia, function(d) {
67854                 return d[0].toLowerCase() === lang.toLowerCase() ||
67855                     d[1].toLowerCase() === lang.toLowerCase();
67856             });
67857
67858         if (language) lang = language[2];
67859
67860         if (d.lang && d.lang !== lang) {
67861             t$$1[key(d.lang)] = undefined;
67862         }
67863
67864         var value = utilGetSetValue(select(this.parentNode)
67865             .selectAll('.localized-value'));
67866
67867         if (lang && value) {
67868             t$$1[key(lang)] = value;
67869         } else if (lang && wikiTitles && wikiTitles[d.lang]) {
67870             t$$1[key(lang)] = wikiTitles[d.lang];
67871         }
67872
67873         d.lang = lang;
67874         dispatch$$1.call('change', this, t$$1);
67875     }
67876
67877
67878     function changeValue(d) {
67879         if (!d.lang) return;
67880         var t$$1 = {};
67881         t$$1[key(d.lang)] = utilGetSetValue(select(this)) || undefined;
67882         dispatch$$1.call('change', this, t$$1);
67883     }
67884
67885
67886     function fetcher(value, cb) {
67887         var v = value.toLowerCase();
67888
67889         cb(dataWikipedia.filter(function(d) {
67890             return d[0].toLowerCase().indexOf(v) >= 0 ||
67891             d[1].toLowerCase().indexOf(v) >= 0 ||
67892             d[2].toLowerCase().indexOf(v) >= 0;
67893         }).map(function(d) {
67894             return { value: d[1] };
67895         }));
67896     }
67897
67898
67899     function render(selection$$1, data$$1) {
67900         var wraps = selection$$1.selectAll('div.entry').
67901             data(data$$1, function(d) { return d.lang; });
67902
67903         wraps.exit()
67904             .transition()
67905             .duration(200)
67906             .style('max-height','0px')
67907             .style('opacity', '0')
67908             .style('top','-10px')
67909             .remove();
67910
67911         var innerWrap = wraps.enter()
67912             .insert('div', ':first-child');
67913
67914         innerWrap.attr('class', 'entry')
67915             .each(function() {
67916                 var wrap = select(this);
67917                 var langcombo = d3combobox()
67918                     .container(context.container())
67919                     .fetcher(fetcher)
67920                     .minItems(0);
67921
67922                 var label = wrap
67923                     .append('label')
67924                     .attr('class','form-label')
67925                     .text(t('translate.localized_translation_label'))
67926                     .attr('for','localized-lang');
67927
67928                 label
67929                     .append('button')
67930                     .attr('class', 'minor remove')
67931                     .on('click', function(d){
67932                         event.preventDefault();
67933                         var t$$1 = {};
67934                         t$$1[key(d.lang)] = undefined;
67935                         dispatch$$1.call('change', this, t$$1);
67936                         select(this.parentNode.parentNode)
67937                             .style('top','0')
67938                             .style('max-height','240px')
67939                             .transition()
67940                             .style('opacity', '0')
67941                             .style('max-height','0px')
67942                             .remove();
67943                     })
67944                     .call(svgIcon('#operation-delete'));
67945
67946                 wrap
67947                     .append('input')
67948                     .attr('class', 'localized-lang')
67949                     .attr('type', 'text')
67950                     .attr('placeholder',t('translate.localized_translation_language'))
67951                     .on('blur', changeLang)
67952                     .on('change', changeLang)
67953                     .call(langcombo);
67954
67955                 wrap
67956                     .append('input')
67957                     .on('blur', changeValue)
67958                     .on('change', changeValue)
67959                     .attr('type', 'text')
67960                     .attr('placeholder', t('translate.localized_translation_name'))
67961                     .attr('class', 'localized-value');
67962             });
67963
67964         innerWrap
67965             .style('margin-top', '0px')
67966             .style('max-height', '0px')
67967             .style('opacity', '0')
67968             .transition()
67969             .duration(200)
67970             .style('margin-top', '10px')
67971             .style('max-height', '240px')
67972             .style('opacity', '1')
67973             .on('end', function() {
67974                 select(this)
67975                     .style('max-height', '')
67976                     .style('overflow', 'visible');
67977             });
67978
67979
67980         var entry = selection$$1.selectAll('.entry');
67981
67982         utilGetSetValue(entry.select('.localized-lang'), function(d) {
67983                 var lang = lodash.find(dataWikipedia, function(lang) { return lang[2] === d.lang; });
67984                 return lang ? lang[1] : d.lang;
67985             });
67986
67987         utilGetSetValue(entry.select('.localized-value'),
67988             function(d) { return d.value; });
67989     }
67990
67991
67992     localized.tags = function(tags) {
67993         // Fetch translations from wikipedia
67994         if (tags.wikipedia && !wikiTitles) {
67995             wikiTitles = {};
67996             var wm = tags.wikipedia.match(/([^:]+):(.+)/);
67997             if (wm && wm[0] && wm[1]) {
67998                 wikipedia.translations(wm[1], wm[2], function(d) {
67999                     wikiTitles = d;
68000                 });
68001             }
68002         }
68003
68004         utilGetSetValue(input, tags[field.key] || '');
68005
68006         var postfixed = [], k, m;
68007         for (k in tags) {
68008             m = k.match(/^(.*):([a-zA-Z_-]+)$/);
68009             if (m && m[1] === field.key && m[2]) {
68010                 postfixed.push({ lang: m[2], value: tags[k] });
68011             }
68012         }
68013
68014         localizedInputs.call(render, postfixed.reverse());
68015     };
68016
68017
68018     localized.focus = function() {
68019         input.node().focus();
68020     };
68021
68022
68023     localized.entity = function(_) {
68024         if (!arguments.length) return entity;
68025         entity = _;
68026         return localized;
68027     };
68028
68029     return utilRebind(localized, dispatch$$1, 'on');
68030 }
68031
68032 function uiFieldMaxspeed(field, context) {
68033     var dispatch$$1 = dispatch('change'),
68034         entity,
68035         isImperial,
68036         unitInput = select(null),
68037         input = select(null),
68038         combobox;
68039
68040     var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
68041         imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
68042
68043
68044     function maxspeed(selection$$1) {
68045         combobox = d3combobox()
68046             .container(context.container());
68047
68048         var unitCombobox = d3combobox()
68049             .container(context.container())
68050             .data(['km/h', 'mph'].map(comboValues));
68051
68052         input = selection$$1.selectAll('#preset-input-' + field.id)
68053             .data([0]);
68054
68055         input = input.enter()
68056             .append('input')
68057             .attr('type', 'text')
68058             .attr('id', 'preset-input-' + field.id)
68059             .attr('placeholder', field.placeholder())
68060             .call(utilNoAuto)
68061             .call(combobox)
68062             .merge(input);
68063
68064         input
68065             .on('change', change)
68066             .on('blur', change);
68067
68068         var childNodes = context.graph().childNodes(context.entity(entity.id)),
68069             loc = childNodes[~~(childNodes.length/2)].loc;
68070
68071         isImperial = lodash.some(dataImperial.features, function(f) {
68072             return lodash.some(f.geometry.coordinates, function(d) {
68073                 return geoPointInPolygon(loc, d);
68074             });
68075         });
68076
68077         unitInput = selection$$1.selectAll('input.maxspeed-unit')
68078             .data([0]);
68079
68080         unitInput = unitInput.enter()
68081             .append('input')
68082             .attr('type', 'text')
68083             .attr('class', 'maxspeed-unit')
68084             .call(unitCombobox)
68085             .merge(unitInput);
68086
68087         unitInput
68088             .on('blur', changeUnits)
68089             .on('change', changeUnits);
68090
68091
68092         function changeUnits() {
68093             isImperial = utilGetSetValue(unitInput) === 'mph';
68094             utilGetSetValue(unitInput, isImperial ? 'mph' : 'km/h');
68095             setSuggestions();
68096             change();
68097         }
68098     }
68099
68100
68101     function setSuggestions() {
68102         combobox.data((isImperial ? imperialValues : metricValues).map(comboValues));
68103         utilGetSetValue(unitInput, isImperial ? 'mph' : 'km/h');
68104     }
68105
68106
68107     function comboValues(d) {
68108         return {
68109             value: d.toString(),
68110             title: d.toString()
68111         };
68112     }
68113
68114
68115     function change() {
68116         var tag = {},
68117             value = utilGetSetValue(input);
68118
68119         if (!value) {
68120             tag[field.key] = undefined;
68121         } else if (isNaN(value) || !isImperial) {
68122             tag[field.key] = value;
68123         } else {
68124             tag[field.key] = value + ' mph';
68125         }
68126
68127         dispatch$$1.call('change', this, tag);
68128     }
68129
68130
68131     maxspeed.tags = function(tags) {
68132         var value = tags[field.key];
68133
68134         if (value && value.indexOf('mph') >= 0) {
68135             value = parseInt(value, 10);
68136             isImperial = true;
68137         } else if (value) {
68138             isImperial = false;
68139         }
68140
68141         setSuggestions();
68142         utilGetSetValue(input, value || '');
68143     };
68144
68145
68146     maxspeed.focus = function() {
68147         input.node().focus();
68148     };
68149
68150
68151     maxspeed.entity = function(_) {
68152         entity = _;
68153     };
68154
68155
68156     return utilRebind(maxspeed, dispatch$$1, 'on');
68157 }
68158
68159 function uiFieldRadio(field, context) {
68160     var dispatch$$1 = dispatch('change'),
68161         taginfo = services.taginfo,
68162         placeholder = select(null),
68163         wrap = select(null),
68164         labels = select(null),
68165         radios = select(null),
68166         typeInput = select(null),
68167         layerInput = select(null),
68168         oldType = {},
68169         entity;
68170
68171
68172     function selectedKey() {
68173         var selector$$1 = '.form-field-structure .toggle-list label.active input',
68174             node = selectAll(selector$$1);
68175         return !node.empty() && node.datum();
68176     }
68177
68178     // returns the tag value for a display value
68179     function tagValue(dispVal) {
68180         dispVal = snake(clean(dispVal || ''));
68181         return dispVal.toLowerCase() || 'yes';
68182     }
68183
68184     // returns the display value for a tag value
68185     function displayValue(tagVal) {
68186         tagVal = tagVal || '';
68187         return tagVal.toLowerCase() === 'yes' ? '' : unsnake(tagVal);
68188     }
68189
68190     function snake(s) {
68191         return s.replace(/\s+/g, '_');
68192     }
68193
68194     function unsnake(s) {
68195         return s.replace(/_+/g, ' ');
68196     }
68197
68198     function clean(s) {
68199         return s.split(';')
68200             .map(function(s) { return s.trim(); })
68201             .join(';');
68202     }
68203
68204
68205     function radio(selection$$1) {
68206         selection$$1.classed('preset-radio', true);
68207
68208         wrap = selection$$1.selectAll('.preset-input-wrap')
68209             .data([0]);
68210
68211         var enter = wrap.enter()
68212             .append('div')
68213             .attr('class', 'preset-input-wrap toggle-list');
68214
68215         enter
68216             .append('span')
68217             .attr('class', 'placeholder');
68218
68219         wrap = wrap
68220             .merge(enter);
68221
68222
68223         placeholder = wrap.selectAll('.placeholder');
68224
68225         labels = wrap.selectAll('label')
68226             .data(field.options || field.keys);
68227
68228         enter = labels.enter()
68229             .append('label');
68230
68231         enter
68232             .append('input')
68233             .attr('type', 'radio')
68234             .attr('name', field.id)
68235             .attr('value', function(d) { return field.t('options.' + d, { 'default': d }); })
68236             .attr('checked', false);
68237
68238         enter
68239             .append('span')
68240             .text(function(d) { return field.t('options.' + d, { 'default': d }); });
68241
68242         labels = labels
68243             .merge(enter);
68244
68245         radios = labels.selectAll('input')
68246             .on('change', changeRadio);
68247     }
68248
68249
68250     function structureExtras(selection$$1) {
68251         var selected = selectedKey();
68252
68253         var extrasWrap = selection$$1.selectAll('.structure-extras-wrap')
68254                 .data(selected ? [0] : []);
68255
68256         extrasWrap.exit()
68257             .remove();
68258
68259         extrasWrap = extrasWrap.enter()
68260             .append('div')
68261             .attr('class', 'structure-extras-wrap')
68262             .merge(extrasWrap);
68263
68264         var list = extrasWrap.selectAll('ul')
68265             .data([0]);
68266
68267         list = list.enter()
68268             .append('ul')
68269             .merge(list);
68270
68271
68272         // Type
68273         var typeItem = list.selectAll('.structure-type-item')
68274             .data([0]);
68275
68276         var typeEnter = typeItem.enter()
68277             .append('li')
68278             .attr('class', 'cf structure-type-item');
68279
68280         typeEnter
68281             .append('span')
68282             .attr('class', 'col6 label structure-label-type')
68283             .attr('for', 'structure-input-type')
68284             .text(t('inspector.radio.structure.type'));
68285
68286         typeEnter
68287             .append('div')
68288             .attr('class', 'col6 structure-input-type-wrap')
68289             .append('input')
68290             .attr('type', 'text')
68291             .attr('class', 'structure-input-type')
68292             .attr('placeholder', t('inspector.radio.structure.default'))
68293             .call(utilNoAuto);
68294
68295         typeItem = typeItem
68296             .merge(typeEnter);
68297
68298         typeInput = typeItem.selectAll('.structure-input-type');
68299
68300         if (taginfo) {
68301             typeInput
68302                 .call(d3combobox()
68303                     .container(context.container())
68304                     .fetcher(typeFetcher)
68305                 );
68306         }
68307
68308         typeInput
68309             .on('change', changeType)
68310             .on('blur', changeType);
68311
68312
68313         // Layer
68314         var showLayer = (selected === 'bridge' || selected === 'tunnel');
68315
68316         var layerItem = list.selectAll('.structure-layer-item')
68317             .data(showLayer ? [0] : []);
68318
68319         layerItem.exit()
68320             .remove();
68321
68322         var layerEnter = layerItem.enter()
68323             .append('li')
68324             .attr('class', 'cf structure-layer-item');
68325
68326         layerEnter
68327             .append('span')
68328             .attr('class', 'col6 label structure-label-layer')
68329             .attr('for', 'structure-input-layer')
68330             .text(t('inspector.radio.structure.layer'));
68331
68332         layerEnter
68333             .append('div')
68334             .attr('class', 'col6 structure-input-layer-wrap')
68335             .append('input')
68336             .attr('type', 'text')
68337             .attr('class', 'structure-input-layer')
68338             .attr('placeholder', '0')
68339             .call(utilNoAuto);
68340
68341         var spin = layerEnter
68342             .append('div')
68343             .attr('class', 'spin-control');
68344
68345         spin
68346             .append('button')
68347             .datum(-1)
68348             .attr('class', 'decrement')
68349             .attr('tabindex', -1);
68350
68351         spin
68352             .append('button')
68353             .datum(1)
68354             .attr('class', 'increment')
68355             .attr('tabindex', -1);
68356
68357         layerItem = layerItem
68358             .merge(layerEnter);
68359
68360         layerInput = layerItem.selectAll('.structure-input-layer')
68361             .on('change', changeLayer)
68362             .on('blur', changeLayer);
68363
68364         layerItem.selectAll('button')
68365             .on('click', function(d) {
68366                 event.preventDefault();
68367                 var num = parseInt(layerInput.node().value || 0, 10);
68368                 if (!isNaN(num)) layerInput.node().value = num + d;
68369                 changeLayer();
68370             });
68371
68372     }
68373
68374
68375     function typeFetcher(q, callback) {
68376         taginfo.values({
68377             debounce: true,
68378             key: selectedKey(),
68379             query: q
68380         }, function(err, data) {
68381             if (err) return;
68382             var comboData = data.map(function(d) {
68383                 return {
68384                     key: d.value,
68385                     value: unsnake(d.value),
68386                     title: d.title
68387                 };
68388             });
68389             if (callback) callback(comboData);
68390         });
68391     }
68392
68393
68394     function changeType() {
68395         var key = selectedKey(),
68396             t$$1 = {};
68397
68398         if (!key) return;
68399         var val = tagValue(utilGetSetValue(typeInput));
68400         t$$1[key] = val;
68401         if (val !== 'no') oldType[key] = val;
68402         dispatch$$1.call('change', this, t$$1);
68403     }
68404
68405
68406     function changeLayer() {
68407         // note: don't use utilGetSetValue here because we want 0 to be falsy.
68408         var t$$1 = { layer: layerInput.node().value || undefined };
68409         dispatch$$1.call('change', this, t$$1);
68410     }
68411
68412
68413     function changeRadio() {
68414         var t$$1 = {},
68415             activeKey;
68416
68417         if (field.key) {
68418             t$$1[field.key] = undefined;
68419         }
68420
68421         radios.each(function(d) {
68422             var active$$1 = select(this).property('checked');
68423             if (active$$1) activeKey = d;
68424
68425             if (field.key) {
68426                 if (active$$1) t$$1[field.key] = d;
68427             } else {
68428                 var val = oldType[activeKey] || 'yes';
68429                 t$$1[d] = active$$1 ? val : undefined;
68430             }
68431         });
68432
68433         if (field.type === 'structureRadio') {
68434             if (activeKey === 'bridge') {
68435                 t$$1.layer = '1';
68436             } else if (activeKey === 'tunnel') {
68437                 t$$1.layer = '-1';
68438             } else {
68439                 t$$1.layer = undefined;
68440             }
68441         }
68442
68443         dispatch$$1.call('change', this, t$$1);
68444     }
68445
68446
68447     radio.tags = function(tags) {
68448         function checked(d) {
68449             if (field.key) {
68450                 return tags[field.key] === d;
68451             } else {
68452                 return !!(tags[d] && tags[d].toLowerCase() !== 'no');
68453             }
68454         }
68455
68456         labels.classed('active', checked);
68457         radios.property('checked', checked);
68458
68459         var selection$$1 = radios.filter(function() { return this.checked; });
68460         var typeVal = '';
68461
68462         if (selection$$1.empty()) {
68463             placeholder.text(t('inspector.none'));
68464         } else {
68465             placeholder.text(selection$$1.attr('value'));
68466             typeVal = oldType[selection$$1.datum()] = tags[selection$$1.datum()];
68467         }
68468
68469         if (field.type === 'structureRadio') {
68470             wrap.call(structureExtras);
68471             utilGetSetValue(typeInput, displayValue(typeVal) || '');
68472             utilGetSetValue(layerInput, tags.layer || '');
68473         }
68474     };
68475
68476
68477     radio.focus = function() {
68478         radios.node().focus();
68479     };
68480
68481
68482     radio.entity = function(_) {
68483         if (!arguments.length) return entity;
68484         entity = _;
68485         oldType = {};
68486         return radio;
68487     };
68488
68489
68490     return utilRebind(radio, dispatch$$1, 'on');
68491 }
68492
68493 function uiFieldRestrictions(field, context) {
68494     var dispatch$$1 = dispatch('change'),
68495         breathe = behaviorBreathe(context),
68496         hover = behaviorHover(context),
68497         initialized = false,
68498         vertexID,
68499         fromNodeID;
68500
68501
68502     function restrictions(selection$$1) {
68503         // if form field is hidden or has detached from dom, clean up.
68504         if (!select('.inspector-wrap.inspector-hidden').empty() || !selection$$1.node().parentNode) {
68505             selection$$1.call(restrictions.off);
68506             return;
68507         }
68508
68509         var wrap = selection$$1.selectAll('.preset-input-wrap')
68510             .data([0]);
68511
68512         var enter = wrap.enter()
68513             .append('div')
68514             .attr('class', 'preset-input-wrap');
68515
68516         enter
68517             .append('div')
68518             .attr('class', 'restriction-help');
68519
68520
68521         var intersection = osmIntersection(context.graph(), vertexID),
68522             graph = intersection.graph,
68523             vertex = graph.entity(vertexID),
68524             filter = utilFunctor(true),
68525             extent$$1 = geoExtent$$1(),
68526             projection$$1 = geoRawMercator();
68527
68528         var d = utilGetDimensions(wrap.merge(enter)),
68529             c = [d[0] / 2, d[1] / 2],
68530             z = 24;
68531
68532         projection$$1
68533             .scale(256 * Math.pow(2, z) / (2 * Math.PI));
68534
68535         var s = projection$$1(vertex.loc);
68536
68537         projection$$1
68538             .translate([c[0] - s[0], c[1] - s[1]])
68539             .clipExtent([[0, 0], d]);
68540
68541         var drawLayers = svgLayers(projection$$1, context).only('osm').dimensions(d),
68542             drawVertices = svgVertices$$1(projection$$1, context),
68543             drawLines = svgLines$$1(projection$$1, context),
68544             drawTurns = svgTurns(projection$$1, context);
68545
68546         enter
68547             .call(drawLayers);
68548
68549         wrap = wrap
68550             .merge(enter);
68551
68552         var surface = wrap.selectAll('.surface');
68553
68554         if (!enter.empty()) {
68555             initialized = true;
68556             surface
68557                 .call(breathe)
68558                 .call(hover);
68559         }
68560
68561         surface
68562             .call(utilSetDimensions, d)
68563             .call(drawVertices, graph, [vertex], filter, extent$$1, z)
68564             .call(drawLines, graph, intersection.ways, filter)
68565             .call(drawTurns, graph, intersection.turns(fromNodeID));
68566
68567         surface
68568             .on('click.restrictions', click)
68569             .on('mouseover.restrictions', mouseover)
68570             .on('mouseout.restrictions', mouseout);
68571
68572         surface
68573             .selectAll('.selected')
68574             .classed('selected', false);
68575
68576         if (fromNodeID) {
68577             surface
68578                 .selectAll('.' + intersection.highways[fromNodeID].id)
68579                 .classed('selected', true);
68580         }
68581
68582         mouseout();
68583
68584         context.history()
68585             .on('change.restrictions', render);
68586
68587         select(window)
68588             .on('resize.restrictions', function() {
68589                 utilSetDimensions(wrap, null);
68590                 render();
68591             });
68592
68593
68594         function click() {
68595             surface
68596                 .call(breathe.off)
68597                 .call(breathe);
68598
68599             var datum = event.target.__data__;
68600             if (datum instanceof osmEntity$$1) {
68601                 fromNodeID = intersection.adjacentNodeId(datum.id);
68602                 render();
68603             } else if (datum instanceof osmTurn) {
68604                 if (datum.restriction) {
68605                     context.perform(
68606                         actionUnrestrictTurn(datum, projection$$1),
68607                         t('operations.restriction.annotation.delete')
68608                     );
68609                 } else {
68610                     context.perform(
68611                         actionRestrictTurn(datum, projection$$1),
68612                         t('operations.restriction.annotation.create')
68613                     );
68614                 }
68615             }
68616         }
68617
68618
68619         function mouseover() {
68620             var datum = event.target.__data__;
68621             if (datum instanceof osmTurn) {
68622                 var graph = context.graph(),
68623                     presets = context.presets(),
68624                     preset;
68625
68626                 if (datum.restriction) {
68627                     preset = presets.match(graph.entity(datum.restriction), graph);
68628                 } else {
68629                     preset = presets.item('type/restriction/' +
68630                         osmInferRestriction(
68631                             graph,
68632                             datum.from,
68633                             datum.via,
68634                             datum.to,
68635                             projection$$1
68636                         )
68637                     );
68638                 }
68639
68640                 wrap.selectAll('.restriction-help')
68641                     .text(t('operations.restriction.help.' +
68642                         (datum.restriction ? 'toggle_off' : 'toggle_on'),
68643                         { restriction: preset.name() })
68644                     );
68645             }
68646         }
68647
68648
68649         function mouseout() {
68650             wrap.selectAll('.restriction-help')
68651                 .text(t('operations.restriction.help.' +
68652                     (fromNodeID ? 'toggle' : 'select'))
68653                 );
68654         }
68655
68656
68657         function render() {
68658             if (context.hasEntity(vertexID)) {
68659                 restrictions(selection$$1);
68660             }
68661         }
68662     }
68663
68664
68665     restrictions.entity = function(_) {
68666         if (!vertexID || vertexID !== _.id) {
68667             fromNodeID = null;
68668             vertexID = _.id;
68669         }
68670     };
68671
68672
68673     restrictions.tags = function() {};
68674     restrictions.focus = function() {};
68675
68676
68677     restrictions.off = function(selection$$1) {
68678         if (!initialized) return;
68679
68680         selection$$1.selectAll('.surface')
68681             .call(hover.off)
68682             .call(breathe.off)
68683             .on('click.restrictions', null)
68684             .on('mouseover.restrictions', null)
68685             .on('mouseout.restrictions', null);
68686
68687         context.history()
68688             .on('change.restrictions', null);
68689
68690         select(window)
68691             .on('resize.restrictions', null);
68692     };
68693
68694
68695     return utilRebind(restrictions, dispatch$$1, 'on');
68696 }
68697
68698 function uiFieldTextarea(field) {
68699     var dispatch$$1 = dispatch('change'),
68700         input = select(null);
68701
68702
68703     function textarea(selection$$1) {
68704         input = selection$$1.selectAll('textarea')
68705             .data([0]);
68706
68707         input = input.enter()
68708             .append('textarea')
68709             .attr('id', 'preset-input-' + field.id)
68710             .attr('placeholder', field.placeholder() || t('inspector.unknown'))
68711             .attr('maxlength', 255)
68712             .call(utilNoAuto)
68713             .on('input', change(true))
68714             .on('blur', change())
68715             .on('change', change())
68716             .merge(input);
68717     }
68718
68719
68720     function change(onInput) {
68721         return function() {
68722             var t$$1 = {};
68723             t$$1[field.key] = utilGetSetValue(input) || undefined;
68724             dispatch$$1.call('change', this, t$$1, onInput);
68725         };
68726     }
68727
68728
68729     textarea.tags = function(tags) {
68730         utilGetSetValue(input, tags[field.key] || '');
68731     };
68732
68733
68734     textarea.focus = function() {
68735         input.node().focus();
68736     };
68737
68738
68739     return utilRebind(textarea, dispatch$$1, 'on');
68740 }
68741
68742 function uiFieldWikipedia(field, context) {
68743     var dispatch$$1 = dispatch('change'),
68744         wikipedia = services.wikipedia,
68745         wikidata = services.wikidata,
68746         link$$1 = select(null),
68747         lang = select(null),
68748         title = select(null),
68749         wikiURL = '',
68750         entity;
68751
68752
68753     function wiki(selection$$1) {
68754         var langcombo = d3combobox()
68755             .container(context.container())
68756             .fetcher(function(value, cb) {
68757                 var v = value.toLowerCase();
68758
68759                 cb(dataWikipedia.filter(function(d) {
68760                     return d[0].toLowerCase().indexOf(v) >= 0 ||
68761                         d[1].toLowerCase().indexOf(v) >= 0 ||
68762                         d[2].toLowerCase().indexOf(v) >= 0;
68763                 }).map(function(d) {
68764                     return { value: d[1] };
68765                 }));
68766             });
68767
68768         var titlecombo = d3combobox()
68769             .container(context.container())
68770             .fetcher(function(value, cb) {
68771                 if (!value) {
68772                     value = context.entity(entity.id).tags.name || '';
68773                 }
68774
68775                 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
68776                 searchfn(language()[2], value, function(query, data$$1) {
68777                     cb(data$$1.map(function(d) {
68778                         return { value: d };
68779                     }));
68780                 });
68781             });
68782
68783
68784         lang = selection$$1.selectAll('input.wiki-lang')
68785             .data([0]);
68786
68787         lang = lang.enter()
68788             .append('input')
68789             .attr('type', 'text')
68790             .attr('class', 'wiki-lang')
68791             .attr('placeholder', t('translate.localized_translation_language'))
68792             .call(utilNoAuto)
68793             .merge(lang);
68794
68795         utilGetSetValue(lang, language()[1]);
68796
68797         lang
68798             .call(langcombo)
68799             .on('blur', changeLang)
68800             .on('change', changeLang);
68801
68802
68803         title = selection$$1.selectAll('input.wiki-title')
68804             .data([0]);
68805
68806         title = title.enter()
68807             .append('input')
68808             .attr('type', 'text')
68809             .attr('class', 'wiki-title')
68810             .attr('id', 'preset-input-' + field.id)
68811             .call(utilNoAuto)
68812             .merge(title);
68813
68814         title
68815             .call(titlecombo)
68816             .on('blur', blur)
68817             .on('change', change);
68818
68819
68820         link$$1 = selection$$1.selectAll('.wiki-link')
68821             .data([0]);
68822
68823         link$$1 = link$$1.enter()
68824             .append('button')
68825             .attr('class', 'button-input-action wiki-link minor')
68826             .attr('tabindex', -1)
68827             .call(svgIcon('#icon-out-link'))
68828             .merge(link$$1);
68829
68830         link$$1
68831             .on('click', function() {
68832                 event.preventDefault();
68833                 if (wikiURL) window.open(wikiURL, '_blank');
68834             });
68835     }
68836
68837
68838     function language() {
68839         var value = utilGetSetValue(lang).toLowerCase();
68840         var locale = utilDetect().locale.toLowerCase();
68841         var localeLanguage;
68842         return lodash.find(dataWikipedia, function(d) {
68843             if (d[2] === locale) localeLanguage = d;
68844             return d[0].toLowerCase() === value ||
68845                 d[1].toLowerCase() === value ||
68846                 d[2] === value;
68847         }) || localeLanguage || ['English', 'English', 'en'];
68848     }
68849
68850
68851     function changeLang() {
68852         utilGetSetValue(lang, language()[1]);
68853         change(true);
68854     }
68855
68856
68857     function blur() {
68858         change(true);
68859     }
68860
68861
68862     function change(skipWikidata) {
68863         var value = utilGetSetValue(title),
68864             m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/),
68865             l = m && lodash.find(dataWikipedia, function(d) { return m[1] === d[2]; }),
68866             anchor,
68867             syncTags = {};
68868
68869         if (l) {
68870             // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
68871             value = decodeURIComponent(m[2]).replace(/_/g, ' ');
68872             if (m[3]) {
68873                 try {
68874                     // Best-effort `anchordecode:` implementation
68875                     anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
68876                 } catch (e) {
68877                     anchor = decodeURIComponent(m[3]);
68878                 }
68879                 value += '#' + anchor.replace(/_/g, ' ');
68880             }
68881             value = value.slice(0, 1).toUpperCase() + value.slice(1);
68882             utilGetSetValue(lang, l[1]);
68883             utilGetSetValue(title, value);
68884         }
68885
68886         syncTags.wikipedia = value ? language()[2] + ':' + value : undefined;
68887         if (!skipWikidata) {
68888             syncTags.wikidata = undefined;
68889         }
68890
68891         dispatch$$1.call('change', this, syncTags);
68892
68893
68894         if (skipWikidata || !value || !language()[2]) return;
68895
68896         // attempt asynchronous update of wikidata tag..
68897         var initEntityId = entity.id,
68898             initWikipedia = context.entity(initEntityId).tags.wikipedia;
68899
68900         wikidata.itemsByTitle(language()[2], value, function(title, data$$1) {
68901             if (!data$$1 || !Object.keys(data$$1).length) return;
68902             var qids = Object.keys(data$$1);
68903
68904             // 1. most recent change was a tag change
68905             var annotation = t('operations.change_tags.annotation'),
68906                 currAnnotation = context.history().undoAnnotation();
68907             if (currAnnotation !== annotation) return;
68908
68909             // 2. same entity exists and still selected
68910             var selectedIds = context.selectedIDs(),
68911                 currEntityId = selectedIds.length > 0 && selectedIds[0];
68912             if (currEntityId !== initEntityId) return;
68913
68914             // 3. wikipedia value has not changed
68915             var currTags = lodash.clone(context.entity(currEntityId).tags);
68916             if (initWikipedia !== currTags.wikipedia) return;
68917
68918             // ok to coalesce the update of wikidata tag into the previous tag change
68919             currTags.wikidata = qids && lodash.find(qids, function(id) {
68920                 return id.match(/^Q\d+$/);
68921             });
68922
68923             context.overwrite(actionChangeTags(currEntityId, currTags), annotation);
68924             dispatch$$1.call('change', this, currTags);
68925         });
68926     }
68927
68928
68929     wiki.tags = function(tags) {
68930         var value = tags[field.key] || '',
68931             m = value.match(/([^:]+):([^#]+)(?:#(.+))?/),
68932             l = m && lodash.find(dataWikipedia, function(d) { return m[1] === d[2]; }),
68933             anchor = m && m[3];
68934
68935         // value in correct format
68936         if (l) {
68937             utilGetSetValue(lang, l[1]);
68938             utilGetSetValue(title, m[2] + (anchor ? ('#' + anchor) : ''));
68939             if (anchor) {
68940                 try {
68941                     // Best-effort `anchorencode:` implementation
68942                     anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
68943                 } catch (e) {
68944                     anchor = anchor.replace(/ /g, '_');
68945                 }
68946             }
68947             wikiURL = 'https://' + m[1] + '.wikipedia.org/wiki/' +
68948                 m[2].replace(/ /g, '_') + (anchor ? ('#' + anchor) : '');
68949
68950         // unrecognized value format
68951         } else {
68952             utilGetSetValue(title, value);
68953             if (value && value !== '') {
68954                 utilGetSetValue(lang, '');
68955                 wikiURL = 'https://en.wikipedia.org/wiki/Special:Search?search=' + value;
68956             } else {
68957                 wikiURL = '';
68958             }
68959         }
68960     };
68961
68962
68963     wiki.entity = function(_) {
68964         if (!arguments.length) return entity;
68965         entity = _;
68966         return wiki;
68967     };
68968
68969
68970     wiki.focus = function() {
68971         title.node().focus();
68972     };
68973
68974
68975     return utilRebind(wiki, dispatch$$1, 'on');
68976 }
68977
68978 var uiFields = {
68979     access: uiFieldAccess,
68980     address: uiFieldAddress,
68981     check: uiFieldCheck,
68982     combo: uiFieldCombo,
68983     cycleway: uiFieldCycleway,
68984     defaultCheck: uiFieldCheck,
68985     email: uiFieldText,
68986     lanes: uiFieldLanes,
68987     localized: uiFieldLocalized,
68988     maxspeed: uiFieldMaxspeed,
68989     multiCombo: uiFieldCombo,
68990     networkCombo: uiFieldCombo,
68991     number: uiFieldText,
68992     onewayCheck: uiFieldCheck,
68993     radio: uiFieldRadio,
68994     restrictions: uiFieldRestrictions,
68995     semiCombo: uiFieldCombo,
68996     structureRadio: uiFieldRadio,
68997     tel: uiFieldText,
68998     text: uiFieldText,
68999     textarea: uiFieldTextarea,
69000     typeCombo: uiFieldCombo,
69001     url: uiFieldText,
69002     wikipedia: uiFieldWikipedia
69003 };
69004
69005 function uiPreset(context) {
69006     var dispatch$$1 = dispatch('change'),
69007         state,
69008         fieldsArr,
69009         preset,
69010         tags,
69011         id;
69012
69013
69014     // Field Constructor
69015     function UIField(field, entity, show) {
69016         field = lodash.clone(field);
69017
69018         field.input = uiFields[field.type](field, context)
69019             .on('change', function(t$$1, onInput) {
69020                 dispatch$$1.call('change', field, t$$1, onInput);
69021             });
69022
69023         if (field.input.entity) field.input.entity(entity);
69024
69025         field.keys = field.keys || [field.key];
69026
69027         field.show = show;
69028
69029         field.shown = function() {
69030             return field.id === 'name' || field.show || lodash.some(field.keys, function(key) { return !!tags[key]; });
69031         };
69032
69033         field.modified = function() {
69034             var original = context.graph().base().entities[entity.id];
69035             return lodash.some(field.keys, function(key) {
69036                 return original ? tags[key] !== original.tags[key] : tags[key];
69037             });
69038         };
69039
69040         field.revert = function() {
69041             var original = context.graph().base().entities[entity.id],
69042                 t$$1 = {};
69043             field.keys.forEach(function(key) {
69044                 t$$1[key] = original ? original.tags[key] : undefined;
69045             });
69046             return t$$1;
69047         };
69048
69049         field.present = function() {
69050             return lodash.some(field.keys, function(key) {
69051                 return tags[key];
69052             });
69053         };
69054
69055         field.remove = function() {
69056             var t$$1 = {};
69057             field.keys.forEach(function(key) {
69058                 t$$1[key] = undefined;
69059             });
69060             return t$$1;
69061         };
69062
69063         return field;
69064     }
69065
69066
69067     function fieldKey(field) {
69068         return field.id;
69069     }
69070
69071
69072     function presets(selection$$1) {
69073         selection$$1.call(uiDisclosure()
69074             .title(t('inspector.all_fields'))
69075             .expanded(context.storage('preset_fields.expanded') !== 'false')
69076             .on('toggled', toggled)
69077             .content(content)
69078         );
69079
69080         function toggled(expanded) {
69081             context.storage('preset_fields.expanded', expanded);
69082         }
69083     }
69084
69085
69086     function content(selection$$1) {
69087         if (!fieldsArr) {
69088             var entity = context.entity(id),
69089                 geometry = context.geometry(id),
69090                 presets = context.presets();
69091
69092             fieldsArr = [];
69093
69094             if (presets.field('name')) {
69095                 fieldsArr.push(UIField(presets.field('name'), entity));
69096             }
69097
69098             preset.fields.forEach(function(field) {
69099                 if (field.matchGeometry(geometry)) {
69100                     fieldsArr.push(UIField(field, entity, true));
69101                 }
69102             });
69103
69104             if (entity.isHighwayIntersection(context.graph()) && presets.field('restrictions')) {
69105                 fieldsArr.push(UIField(presets.field('restrictions'), entity, true));
69106             }
69107
69108             presets.universal().forEach(function(field) {
69109                 if (preset.fields.indexOf(field) < 0) {
69110                     fieldsArr.push(UIField(field, entity));
69111                 }
69112             });
69113         }
69114
69115         var shown = fieldsArr.filter(function(field) { return field.shown(); }),
69116             notShown = fieldsArr.filter(function(field) { return !field.shown(); });
69117
69118
69119         var form = selection$$1.selectAll('.preset-form')
69120             .data([0]);
69121
69122         form = form.enter()
69123             .append('div')
69124             .attr('class', 'preset-form inspector-inner fillL3')
69125             .merge(form);
69126
69127
69128         var fields = form.selectAll('.form-field')
69129             .data(shown, fieldKey);
69130
69131         fields.exit()
69132             .remove();
69133
69134         // Enter
69135         var enter = fields.enter()
69136             .append('div')
69137             .attr('class', function(field) {
69138                 return 'form-field form-field-' + field.id;
69139             });
69140
69141         var label = enter
69142             .append('label')
69143             .attr('class', 'form-label')
69144             .attr('for', function(field) { return 'preset-input-' + field.id; })
69145             .text(function(field) { return field.label(); });
69146
69147         var wrap = label
69148             .append('div')
69149             .attr('class', 'form-label-button-wrap');
69150
69151         wrap.append('button')
69152             .attr('class', 'remove-icon')
69153             .attr('tabindex', -1)
69154             .call(svgIcon('#operation-delete'));
69155
69156         wrap.append('button')
69157             .attr('class', 'modified-icon')
69158             .attr('tabindex', -1)
69159             .call(
69160                 (textDirection === 'rtl') ? svgIcon('#icon-redo') : svgIcon('#icon-undo')
69161             );
69162
69163
69164         // Update
69165         fields = fields
69166             .merge(enter);
69167
69168         fields.selectAll('.form-label-button-wrap .remove-icon')
69169             .on('click', remove);
69170
69171         fields.selectAll('.modified-icon')
69172             .on('click', revert);
69173
69174         fields
69175             .order()
69176             .classed('modified', function(field) { return field.modified(); })
69177             .classed('present', function(field) { return field.present(); })
69178             .each(function(field) {
69179                 var referenceKey = field.key;
69180                 if (field.type === 'multiCombo') {   // lookup key without the trailing ':'
69181                     referenceKey = referenceKey.replace(/:$/, '');
69182                 }
69183                 var reference = uiTagReference(field.reference || { key: referenceKey }, context);
69184
69185                 if (state === 'hover') {
69186                     reference.showing(false);
69187                 }
69188
69189                 select(this)
69190                     .call(field.input)
69191                     .selectAll('input')
69192                     .on('keydown', function() {
69193                         // if user presses enter, and combobox is not active, accept edits..
69194                         if (event.keyCode === 13 && select('.combobox').empty()) {
69195                             context.enter(modeBrowse(context));
69196                         }
69197                     });
69198
69199                 select(this)
69200                     .call(reference.body)
69201                     .select('.form-label-button-wrap')
69202                     .call(reference.button);
69203
69204                 field.input.tags(tags);
69205             });
69206
69207         notShown = notShown.map(function(field) {
69208             return {
69209                 title: field.label(),
69210                 value: field.label(),
69211                 field: field
69212             };
69213         });
69214
69215
69216         var more = selection$$1.selectAll('.more-fields')
69217             .data((notShown.length > 0) ? [0] : []);
69218
69219         more.exit()
69220             .remove();
69221
69222         more = more.enter()
69223             .append('div')
69224             .attr('class', 'more-fields')
69225             .append('label')
69226             .text(t('inspector.add_fields'))
69227             .merge(more);
69228
69229
69230         var input = more.selectAll('.value')
69231             .data([0]);
69232
69233         input.exit()
69234             .remove();
69235
69236         input = input.enter()
69237             .append('input')
69238             .attr('class', 'value')
69239             .attr('type', 'text')
69240             .call(utilNoAuto)
69241             .merge(input);
69242
69243         input
69244             .call(utilGetSetValue, '')
69245             .attr('placeholder', function() {
69246                 var placeholder = [];
69247                 for (var field in notShown) {
69248                     placeholder.push(notShown[field].title);
69249                 }
69250                 return placeholder.slice(0,3).join(', ') + ((placeholder.length > 3) ? '…' : '');
69251             })
69252             .call(d3combobox()
69253                 .container(context.container())
69254                 .data(notShown)
69255                 .minItems(1)
69256                 .on('accept', show)
69257             );
69258
69259
69260         function show(field) {
69261             field = field.field;
69262             field.show = true;
69263             content(selection$$1);
69264             field.input.focus();
69265         }
69266
69267
69268         function revert(field) {
69269             event.stopPropagation();
69270             event.preventDefault();
69271             dispatch$$1.call('change', field, field.revert());
69272         }
69273
69274
69275         function remove(field) {
69276             event.stopPropagation();
69277             event.preventDefault();
69278             dispatch$$1.call('change', field, field.remove());
69279         }
69280     }
69281
69282
69283     presets.preset = function(_) {
69284         if (!arguments.length) return preset;
69285         if (preset && preset.id === _.id) return presets;
69286         preset = _;
69287         fieldsArr = null;
69288         return presets;
69289     };
69290
69291
69292     presets.state = function(_) {
69293         if (!arguments.length) return state;
69294         state = _;
69295         return presets;
69296     };
69297
69298
69299     presets.tags = function(_) {
69300         if (!arguments.length) return tags;
69301         tags = _;
69302         // Don't reset fieldsArr here.
69303         return presets;
69304     };
69305
69306
69307     presets.entityID = function(_) {
69308         if (!arguments.length) return id;
69309         if (id === _) return presets;
69310         id = _;
69311         fieldsArr = null;
69312         return presets;
69313     };
69314
69315
69316     return utilRebind(presets, dispatch$$1, 'on');
69317 }
69318
69319 function uiEntityEditor(context) {
69320     var dispatch$$1 = dispatch('choose'),
69321         state = 'select',
69322         coalesceChanges = false,
69323         modified = false,
69324         base,
69325         id,
69326         activePreset,
69327         reference;
69328
69329     var presetEditor = uiPreset(context)
69330         .on('change', changeTags);
69331     var rawTagEditor = uiRawTagEditor(context)
69332         .on('change', changeTags);
69333
69334
69335     function entityEditor(selection$$1) {
69336         var entity = context.entity(id),
69337             tags = lodash.clone(entity.tags);
69338
69339         // Header
69340         var header = selection$$1.selectAll('.header')
69341             .data([0]);
69342
69343         // Enter
69344         var enter = header.enter()
69345             .append('div')
69346             .attr('class', 'header fillL cf');
69347
69348         enter
69349             .append('button')
69350             .attr('class', 'fl preset-reset preset-choose')
69351             .call(svgIcon((textDirection === 'rtl') ? '#icon-forward' : '#icon-backward'));
69352
69353         enter
69354             .append('button')
69355             .attr('class', 'fr preset-close')
69356             .on('click', function() { context.enter(modeBrowse(context)); })
69357             .call(svgIcon(modified ? '#icon-apply' : '#icon-close'));
69358
69359         enter
69360             .append('h3')
69361             .text(t('inspector.edit'));
69362
69363         // Update
69364         header = header
69365             .merge(enter);
69366
69367         header.selectAll('.preset-reset')
69368             .on('click', function() { dispatch$$1.call('choose', this, activePreset); });
69369
69370
69371         // Body
69372         var body = selection$$1.selectAll('.inspector-body')
69373             .data([0]);
69374
69375         // Enter
69376         enter = body.enter()
69377             .append('div')
69378             .attr('class', 'inspector-body');
69379
69380         enter
69381             .append('div')
69382             .attr('class', 'preset-list-item inspector-inner')
69383             .append('div')
69384             .attr('class', 'preset-list-button-wrap')
69385             .append('button')
69386             .attr('class', 'preset-list-button preset-reset')
69387             .call(tooltip().title(t('inspector.back_tooltip')).placement('bottom'))
69388             .append('div')
69389             .attr('class', 'label');
69390
69391         enter
69392             .append('div')
69393             .attr('class', 'inspector-border inspector-preset');
69394
69395         enter
69396             .append('div')
69397             .attr('class', 'inspector-border raw-tag-editor inspector-inner');
69398
69399         enter
69400             .append('div')
69401             .attr('class', 'inspector-border raw-member-editor inspector-inner');
69402
69403         enter
69404             .append('div')
69405             .attr('class', 'raw-membership-editor inspector-inner');
69406
69407         // Update
69408         body = body
69409             .merge(enter);
69410
69411         body.selectAll('.preset-list-button-wrap')
69412             .call(reference.button);
69413
69414         body.selectAll('.preset-list-item')
69415             .call(reference.body);
69416
69417         body.selectAll('.preset-reset')
69418             .on('click', function() { dispatch$$1.call('choose', this, activePreset); });
69419
69420         body.select('.preset-list-item button')
69421             .call(uiPresetIcon()
69422                 .geometry(context.geometry(id))
69423                 .preset(activePreset));
69424
69425         body.select('.preset-list-item .label')
69426             .text(activePreset.name());
69427
69428         body.select('.inspector-preset')
69429             .call(presetEditor
69430                 .preset(activePreset)
69431                 .entityID(id)
69432                 .tags(tags)
69433                 .state(state));
69434
69435         body.select('.raw-tag-editor')
69436             .call(rawTagEditor
69437                 .preset(activePreset)
69438                 .entityID(id)
69439                 .tags(tags)
69440                 .state(state));
69441
69442         if (entity.type === 'relation') {
69443             body.select('.raw-member-editor')
69444                 .style('display', 'block')
69445                 .call(uiRawMemberEditor(context)
69446                     .entityID(id));
69447         } else {
69448             body.select('.raw-member-editor')
69449                 .style('display', 'none');
69450         }
69451
69452         body.select('.raw-membership-editor')
69453             .call(uiRawMembershipEditor(context)
69454                 .entityID(id));
69455
69456
69457         context.history()
69458             .on('change.entity-editor', historyChanged);
69459
69460
69461         function historyChanged() {
69462             if (state === 'hide') return;
69463
69464             var entity = context.hasEntity(id),
69465                 graph = context.graph();
69466             if (!entity) return;
69467
69468             entityEditor.preset(context.presets().match(entity, graph));
69469             entityEditor.modified(base !== graph);
69470             entityEditor(selection$$1);
69471         }
69472     }
69473
69474
69475     function clean(o) {
69476
69477         function cleanVal(k, v) {
69478             function keepSpaces(k) {
69479                 return k.match(/_hours|_times/) !== null;
69480             }
69481
69482             var blacklist = ['description', 'note', 'fixme'];
69483             if (lodash.some(blacklist, function(s) { return k.indexOf(s) !== -1; })) return v;
69484
69485             var cleaned = v.split(';')
69486                 .map(function(s) { return s.trim(); })
69487                 .join(keepSpaces(k) ? '; ' : ';');
69488
69489             // The code below is not intended to validate websites and emails.
69490             // It is only intended to prevent obvious copy-paste errors. (#2323)
69491             // clean website- and email-like tags
69492             if (k.indexOf('website') !== -1 ||
69493                 k.indexOf('email') !== -1 ||
69494                 cleaned.indexOf('http') === 0) {
69495                 cleaned = cleaned
69496                     .replace(/[\u200B-\u200F\uFEFF]/g, '');  // strip LRM and other zero width chars
69497
69498             }
69499
69500             return cleaned;
69501         }
69502
69503         var out = {}, k, v;
69504         for (k in o) {
69505             if (k && (v = o[k]) !== undefined) {
69506                 out[k] = cleanVal(k, v);
69507             }
69508         }
69509         return out;
69510     }
69511
69512
69513     // Tag changes that fire on input can all get coalesced into a single
69514     // history operation when the user leaves the field.  #2342
69515     function changeTags(changed, onInput) {
69516         var entity = context.entity(id),
69517             annotation = t('operations.change_tags.annotation'),
69518             tags = lodash.clone(entity.tags);
69519
69520         lodash.forEach(changed, function(v, k) {
69521             if (v !== undefined || tags.hasOwnProperty(k)) {
69522                 tags[k] = v;
69523             }
69524         });
69525
69526         if (!onInput) {
69527             tags = clean(tags);
69528         }
69529
69530         if (!lodash.isEqual(entity.tags, tags)) {
69531             if (coalesceChanges) {
69532                 context.overwrite(actionChangeTags(id, tags), annotation);
69533             } else {
69534                 context.perform(actionChangeTags(id, tags), annotation);
69535                 coalesceChanges = !!onInput;
69536             }
69537         }
69538     }
69539
69540
69541     entityEditor.modified = function(_) {
69542         if (!arguments.length) return modified;
69543         modified = _;
69544         selectAll('button.preset-close use')
69545             .attr('xlink:href', (modified ? '#icon-apply' : '#icon-close'));
69546     };
69547
69548
69549     entityEditor.state = function(_) {
69550         if (!arguments.length) return state;
69551         state = _;
69552         return entityEditor;
69553     };
69554
69555
69556     entityEditor.entityID = function(_) {
69557         if (!arguments.length) return id;
69558         id = _;
69559         base = context.graph();
69560         entityEditor.preset(context.presets().match(context.entity(id), base));
69561         entityEditor.modified(false);
69562         coalesceChanges = false;
69563         return entityEditor;
69564     };
69565
69566
69567     entityEditor.preset = function(_) {
69568         if (!arguments.length) return activePreset;
69569         if (_ !== activePreset) {
69570             activePreset = _;
69571             reference = uiTagReference(activePreset.reference(context.geometry(id)), context)
69572                 .showing(false);
69573         }
69574         return entityEditor;
69575     };
69576
69577
69578     return utilRebind(entityEditor, dispatch$$1, 'on');
69579 }
69580
69581 function uiPresetList(context) {
69582     var dispatch$$1 = dispatch('choose'),
69583         id,
69584         currentPreset,
69585         autofocus = false;
69586
69587
69588     function presetList(selection$$1) {
69589         var entity = context.entity(id),
69590             geometry = context.geometry(id);
69591
69592         // Treat entities on addr:interpolation lines as points, not vertices (#3241)
69593         if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
69594             geometry = 'point';
69595         }
69596
69597         var presets = context.presets().matchGeometry(geometry);
69598
69599         selection$$1.html('');
69600
69601         var messagewrap = selection$$1
69602             .append('div')
69603             .attr('class', 'header fillL cf');
69604
69605         var message = messagewrap
69606             .append('h3')
69607             .text(t('inspector.choose'));
69608
69609         if (context.entity(id).isUsed(context.graph())) {
69610             messagewrap
69611                 .append('button')
69612                 .attr('class', 'preset-choose')
69613                 .on('click', function() { dispatch$$1.call('choose', this, currentPreset); })
69614                 .call(svgIcon((textDirection === 'rtl') ? '#icon-backward' : '#icon-forward'));
69615         } else {
69616             messagewrap
69617                 .append('button')
69618                 .attr('class', 'close')
69619                 .on('click', function() {
69620                     context.enter(modeBrowse(context));
69621                 })
69622                 .call(svgIcon('#icon-close'));
69623         }
69624
69625         function keydown() {
69626             // hack to let delete shortcut work when search is autofocused
69627             if (search.property('value').length === 0 &&
69628                 (event.keyCode === d3keybinding.keyCodes['⌫'] ||
69629                  event.keyCode === d3keybinding.keyCodes['⌦'])) {
69630                 event.preventDefault();
69631                 event.stopPropagation();
69632                 operationDelete([id], context)();
69633             } else if (search.property('value').length === 0 &&
69634                 (event.ctrlKey || event.metaKey) &&
69635                 event.keyCode === d3keybinding.keyCodes.z) {
69636                 event.preventDefault();
69637                 event.stopPropagation();
69638                 context.undo();
69639             } else if (!event.ctrlKey && !event.metaKey) {
69640                 select(this).on('keydown', null);
69641             }
69642         }
69643
69644         function keypress() {
69645             // enter
69646             var value = search.property('value');
69647             if (event.keyCode === 13 && value.length) {
69648                 list.selectAll('.preset-list-item:first-child').datum().choose();
69649             }
69650         }
69651
69652         function inputevent() {
69653             var value = search.property('value');
69654             list.classed('filtered', value.length);
69655             if (value.length) {
69656                 var results = presets.search(value, geometry);
69657                 message.text(t('inspector.results', {
69658                     n: results.collection.length,
69659                     search: value
69660                 }));
69661                 list.call(drawList, results);
69662             } else {
69663                 list.call(drawList, context.presets().defaults(geometry, 36));
69664                 message.text(t('inspector.choose'));
69665             }
69666         }
69667
69668         var searchWrap = selection$$1
69669             .append('div')
69670             .attr('class', 'search-header');
69671
69672         var search = searchWrap
69673             .append('input')
69674             .attr('class', 'preset-search-input')
69675             .attr('placeholder', t('inspector.search'))
69676             .attr('type', 'search')
69677             .call(utilNoAuto)
69678             .on('keydown', keydown)
69679             .on('keypress', keypress)
69680             .on('input', inputevent);
69681
69682         searchWrap
69683             .call(svgIcon('#icon-search', 'pre-text'));
69684
69685         if (autofocus) {
69686             search.node().focus();
69687         }
69688
69689         var listWrap = selection$$1
69690             .append('div')
69691             .attr('class', 'inspector-body');
69692
69693         var list = listWrap
69694             .append('div')
69695             .attr('class', 'preset-list fillL cf')
69696             .call(drawList, context.presets().defaults(geometry, 36));
69697     }
69698
69699
69700     function drawList(list, presets) {
69701         var collection = presets.collection.map(function(preset) {
69702             return preset.members ? CategoryItem(preset) : PresetItem(preset);
69703         });
69704
69705         var items = list.selectAll('.preset-list-item')
69706             .data(collection, function(d) { return d.preset.id; });
69707
69708         items.order();
69709
69710         items.exit()
69711             .remove();
69712
69713         items.enter()
69714             .append('div')
69715             .attr('class', function(item) { return 'preset-list-item preset-' + item.preset.id.replace('/', '-'); })
69716             .classed('current', function(item) { return item.preset === currentPreset; })
69717             .each(function(item) { select(this).call(item); })
69718             .style('opacity', 0)
69719             .transition()
69720             .style('opacity', 1);
69721     }
69722
69723
69724     function CategoryItem(preset) {
69725         var box, sublist, shown = false;
69726
69727         function item(selection$$1) {
69728             var wrap = selection$$1.append('div')
69729                 .attr('class', 'preset-list-button-wrap category col12');
69730
69731             var button = wrap
69732                 .append('button')
69733                 .attr('class', 'preset-list-button')
69734                 .classed('expanded', false)
69735                 .call(uiPresetIcon()
69736                     .geometry(context.geometry(id))
69737                     .preset(preset))
69738                 .on('click', function() {
69739                     var isExpanded = select(this).classed('expanded');
69740                     var iconName = isExpanded ?
69741                         (textDirection === 'rtl' ? '#icon-backward' : '#icon-forward') : '#icon-down';
69742                     select(this)
69743                         .classed('expanded', !isExpanded);
69744                     select(this).selectAll('div.label svg.icon use')
69745                         .attr('href', iconName);
69746                     item.choose();
69747                 });
69748
69749             var label = button
69750                 .append('div')
69751                 .attr('class', 'label');
69752
69753             label
69754                 .call(svgIcon((textDirection === 'rtl' ? '#icon-backward' : '#icon-forward'), 'inline'))
69755                 .append('span')
69756                 .html(function() { return preset.name() + '&hellip;'; });
69757
69758             box = selection$$1.append('div')
69759                 .attr('class', 'subgrid col12')
69760                 .style('max-height', '0px')
69761                 .style('opacity', 0);
69762
69763             box.append('div')
69764                 .attr('class', 'arrow');
69765
69766             sublist = box.append('div')
69767                 .attr('class', 'preset-list fillL3 cf fl');
69768         }
69769
69770
69771         item.choose = function() {
69772             if (!box || !sublist) return;
69773
69774             if (shown) {
69775                 shown = false;
69776                 box.transition()
69777                     .duration(200)
69778                     .style('opacity', '0')
69779                     .style('max-height', '0px')
69780                     .style('padding-bottom', '0px');
69781             } else {
69782                 shown = true;
69783                 sublist.call(drawList, preset.members);
69784                 box.transition()
69785                     .duration(200)
69786                     .style('opacity', '1')
69787                     .style('max-height', 200 + preset.members.collection.length * 80 + 'px')
69788                     .style('padding-bottom', '20px');
69789             }
69790         };
69791
69792         item.preset = preset;
69793
69794         return item;
69795     }
69796
69797
69798     function PresetItem(preset) {
69799         function item(selection$$1) {
69800             var wrap = selection$$1.append('div')
69801                 .attr('class', 'preset-list-button-wrap col12');
69802
69803             wrap.append('button')
69804                 .attr('class', 'preset-list-button')
69805                 .call(uiPresetIcon()
69806                     .geometry(context.geometry(id))
69807                     .preset(preset))
69808                 .on('click', item.choose)
69809                 .append('div')
69810                 .attr('class', 'label')
69811                 .text(preset.name());
69812
69813             wrap.call(item.reference.button);
69814             selection$$1.call(item.reference.body);
69815         }
69816
69817         item.choose = function() {
69818             context.presets().choose(preset);
69819
69820             context.perform(
69821                 actionChangePreset(id, currentPreset, preset),
69822                 t('operations.change_tags.annotation')
69823             );
69824
69825             dispatch$$1.call('choose', this, preset);
69826         };
69827
69828         item.help = function() {
69829             event.stopPropagation();
69830             item.reference.toggle();
69831         };
69832
69833         item.preset = preset;
69834         item.reference = uiTagReference(preset.reference(context.geometry(id)), context);
69835
69836         return item;
69837     }
69838
69839
69840     presetList.autofocus = function(_) {
69841         if (!arguments.length) return autofocus;
69842         autofocus = _;
69843         return presetList;
69844     };
69845
69846
69847     presetList.entityID = function(_) {
69848         if (!arguments.length) return id;
69849         id = _;
69850         presetList.preset(context.presets().match(context.entity(id), context.graph()));
69851         return presetList;
69852     };
69853
69854
69855     presetList.preset = function(_) {
69856         if (!arguments.length) return currentPreset;
69857         currentPreset = _;
69858         return presetList;
69859     };
69860
69861
69862     return utilRebind(presetList, dispatch$$1, 'on');
69863 }
69864
69865 function uiViewOnOSM(context) {
69866     var id;
69867
69868     function viewOnOSM(selection) {
69869         var entity = context.entity(id);
69870
69871         selection.style('display', entity.isNew() ? 'none' : null);
69872
69873         var link = selection.selectAll('.view-on-osm')
69874             .data([0]);
69875
69876         var enter = link.enter()
69877             .append('a')
69878             .attr('class', 'view-on-osm')
69879             .attr('target', '_blank')
69880             .call(svgIcon('#icon-out-link', 'inline'));
69881
69882         enter
69883             .append('span')
69884             .text(t('inspector.view_on_osm'));
69885
69886         link
69887             .merge(enter)
69888             .attr('href', context.connection().entityURL(entity));
69889     }
69890
69891
69892     viewOnOSM.entityID = function(_) {
69893         if (!arguments.length) return id;
69894         id = _;
69895         return viewOnOSM;
69896     };
69897
69898     return viewOnOSM;
69899 }
69900
69901 function uiInspector(context) {
69902     var presetList = uiPresetList(context),
69903         entityEditor = uiEntityEditor(context),
69904         state = 'select',
69905         entityID,
69906         newFeature = false;
69907
69908
69909     function inspector(selection$$1) {
69910         presetList
69911             .entityID(entityID)
69912             .autofocus(newFeature)
69913             .on('choose', setPreset);
69914
69915         entityEditor
69916             .state(state)
69917             .entityID(entityID)
69918             .on('choose', showList);
69919
69920         var wrap = selection$$1.selectAll('.panewrap')
69921             .data([0]);
69922
69923         var enter = wrap.enter()
69924             .append('div')
69925             .attr('class', 'panewrap');
69926
69927         enter
69928             .append('div')
69929             .attr('class', 'preset-list-pane pane');
69930
69931         enter
69932             .append('div')
69933             .attr('class', 'entity-editor-pane pane');
69934
69935         wrap = wrap.merge(enter);
69936         var presetPane = wrap.selectAll('.preset-list-pane');
69937         var editorPane = wrap.selectAll('.entity-editor-pane');
69938
69939         var graph = context.graph(),
69940             entity = context.entity(entityID),
69941             showEditor = state === 'hover' ||
69942                 entity.isUsed(graph) ||
69943                 entity.isHighwayIntersection(graph);
69944
69945         if (showEditor) {
69946             wrap.style('right', '0%');
69947             editorPane.call(entityEditor);
69948         } else {
69949             wrap.style('right', '-100%');
69950             presetPane.call(presetList);
69951         }
69952
69953         var footer = selection$$1.selectAll('.footer')
69954             .data([0]);
69955
69956         footer = footer.enter()
69957             .append('div')
69958             .attr('class', 'footer')
69959             .merge(footer);
69960
69961         footer
69962             .call(uiViewOnOSM(context).entityID(entityID));
69963
69964
69965         function showList(preset) {
69966             wrap.transition()
69967                 .styleTween('right', function() { return interpolateValue('0%', '-100%'); });
69968
69969             presetPane
69970                 .call(presetList.preset(preset).autofocus(true));
69971         }
69972
69973
69974         function setPreset(preset) {
69975             wrap.transition()
69976                 .styleTween('right', function() { return interpolateValue('-100%', '0%'); });
69977
69978             editorPane
69979                 .call(entityEditor.preset(preset));
69980         }
69981     }
69982
69983
69984     inspector.state = function(_) {
69985         if (!arguments.length) return state;
69986         state = _;
69987         entityEditor.state(state);
69988         return inspector;
69989     };
69990
69991
69992     inspector.entityID = function(_) {
69993         if (!arguments.length) return entityID;
69994         entityID = _;
69995         return inspector;
69996     };
69997
69998
69999     inspector.newFeature = function(_) {
70000         if (!arguments.length) return newFeature;
70001         newFeature = _;
70002         return inspector;
70003     };
70004
70005
70006     return inspector;
70007 }
70008
70009 function uiNotice(context) {
70010
70011     return function(selection) {
70012         var div = selection
70013             .append('div')
70014             .attr('class', 'notice');
70015
70016         var button = div
70017             .append('button')
70018             .attr('class', 'zoom-to notice')
70019             .on('click', function() { context.map().zoom(context.minEditableZoom()); });
70020
70021         button
70022             .call(svgIcon('#icon-plus', 'pre-text'))
70023             .append('span')
70024             .attr('class', 'label')
70025             .text(t('zoom_in_edit'));
70026
70027
70028         function disableTooHigh() {
70029             div.style('display', context.editable() ? 'none' : 'block');
70030         }
70031
70032         context.map()
70033             .on('move.notice', lodash.debounce(disableTooHigh, 500));
70034
70035         disableTooHigh();
70036     };
70037 }
70038
70039 function uiSidebar(context) {
70040     var inspector = uiInspector(context),
70041         current;
70042
70043
70044     function sidebar(selection) {
70045         var featureListWrap = selection
70046             .append('div')
70047             .attr('class', 'feature-list-pane')
70048             .call(uiFeatureList(context));
70049
70050         selection
70051             .call(uiNotice(context));
70052
70053         var inspectorWrap = selection
70054             .append('div')
70055             .attr('class', 'inspector-hidden inspector-wrap fr');
70056
70057
70058         function hover(id) {
70059             if (!current && context.hasEntity(id)) {
70060                 featureListWrap
70061                     .classed('inspector-hidden', true);
70062
70063                 inspectorWrap
70064                     .classed('inspector-hidden', false)
70065                     .classed('inspector-hover', true);
70066
70067                 if (inspector.entityID() !== id || inspector.state() !== 'hover') {
70068                     inspector
70069                         .state('hover')
70070                         .entityID(id);
70071
70072                     inspectorWrap
70073                         .call(inspector);
70074                 }
70075
70076             } else if (!current) {
70077                 featureListWrap
70078                     .classed('inspector-hidden', false);
70079                 inspectorWrap
70080                     .classed('inspector-hidden', true);
70081                 inspector
70082                     .state('hide');
70083             }
70084         }
70085
70086
70087         sidebar.hover = lodash.throttle(hover, 200);
70088
70089
70090         sidebar.select = function(id, newFeature) {
70091             if (!current && id) {
70092                 featureListWrap
70093                     .classed('inspector-hidden', true);
70094
70095                 inspectorWrap
70096                     .classed('inspector-hidden', false)
70097                     .classed('inspector-hover', false);
70098
70099                 if (inspector.entityID() !== id || inspector.state() !== 'select') {
70100                     inspector
70101                         .state('select')
70102                         .entityID(id)
70103                         .newFeature(newFeature);
70104
70105                     inspectorWrap
70106                         .call(inspector);
70107                 }
70108
70109             } else if (!current) {
70110                 featureListWrap
70111                     .classed('inspector-hidden', false);
70112                 inspectorWrap
70113                     .classed('inspector-hidden', true);
70114                 inspector
70115                     .state('hide');
70116             }
70117         };
70118
70119
70120         sidebar.show = function(component) {
70121             featureListWrap
70122                 .classed('inspector-hidden', true);
70123             inspectorWrap
70124                 .classed('inspector-hidden', true);
70125
70126             if (current) current.remove();
70127             current = selection
70128                 .append('div')
70129                 .attr('class', 'sidebar-component')
70130                 .call(component);
70131         };
70132
70133
70134         sidebar.hide = function() {
70135             featureListWrap
70136                 .classed('inspector-hidden', false);
70137             inspectorWrap
70138                 .classed('inspector-hidden', true);
70139
70140             if (current) current.remove();
70141             current = null;
70142         };
70143     }
70144
70145
70146     sidebar.hover = function() {};
70147     sidebar.hover.cancel = function() {};
70148     sidebar.select = function() {};
70149     sidebar.show = function() {};
70150     sidebar.hide = function() {};
70151
70152     return sidebar;
70153 }
70154
70155 function uiSpinner(context) {
70156     var connection = context.connection();
70157
70158
70159     return function(selection) {
70160         var img = selection
70161             .append('img')
70162             .attr('src', context.imagePath('loader-black.gif'))
70163             .style('opacity', 0);
70164
70165         connection
70166             .on('loading.spinner', function() {
70167                 img.transition()
70168                     .style('opacity', 1);
70169             });
70170
70171         connection
70172             .on('loaded.spinner', function() {
70173                 img.transition()
70174                     .style('opacity', 0);
70175             });
70176     };
70177 }
70178
70179 function uiSplash(context) {
70180
70181     return function(selection) {
70182         if (context.storage('sawSplash'))
70183              return;
70184
70185         context.storage('sawSplash', true);
70186
70187         var modalSelection = uiModal(selection);
70188
70189         modalSelection.select('.modal')
70190             .attr('class', 'modal-splash modal col6');
70191
70192         var introModal = modalSelection.select('.content')
70193             .append('div')
70194             .attr('class', 'fillL');
70195
70196         introModal
70197             .append('div')
70198             .attr('class','modal-section cf')
70199             .append('h3').text(t('splash.welcome'));
70200
70201         introModal
70202             .append('div')
70203             .attr('class','modal-section')
70204             .append('p')
70205             .html(t('splash.text', {
70206                 version: context.version,
70207                 website: '<a href="http://ideditor.com/">ideditor.com</a>',
70208                 github: '<a href="https://github.com/openstreetmap/iD">github.com</a>'
70209             }));
70210
70211         var buttonWrap = introModal
70212             .append('div')
70213             .attr('class', 'modal-actions cf');
70214
70215         var walkthrough = buttonWrap
70216             .append('button')
70217             .attr('class', 'walkthrough col6')
70218             .on('click', function() {
70219                 context.container().call(uiIntro(context));
70220                 modalSelection.close();
70221             });
70222
70223         walkthrough
70224             .append('svg')
70225             .attr('class', 'logo logo-walkthrough')
70226             .append('use')
70227             .attr('xlink:href', '#logo-walkthrough');
70228
70229         walkthrough
70230             .append('div')
70231             .text(t('splash.walkthrough'));
70232
70233         var startEditing = buttonWrap
70234             .append('button')
70235             .attr('class', 'start-editing col6')
70236             .on('click', modalSelection.close);
70237
70238         startEditing
70239             .append('svg')
70240             .attr('class', 'logo logo-features')
70241             .append('use')
70242             .attr('xlink:href', '#logo-features');
70243
70244         startEditing
70245             .append('div')
70246             .text(t('splash.start'));
70247
70248
70249         modalSelection.select('button.close')
70250             .attr('class','hide');
70251
70252     };
70253 }
70254
70255 function uiStatus(context) {
70256     var connection = context.connection();
70257
70258     return function(selection$$1) {
70259
70260         function update() {
70261             connection.status(function(err, apiStatus) {
70262                 selection$$1.html('');
70263
70264                 if (err) {
70265                     if (apiStatus === 'rateLimited') {
70266                         selection$$1
70267                             .text(t('status.rateLimit'))
70268                             .append('a')
70269                             .attr('class', 'api-status-login')
70270                             .attr('target', '_blank')
70271                             .call(svgIcon('#icon-out-link', 'inline'))
70272                             .append('span')
70273                             .text(t('login'))
70274                             .on('click.login', function() {
70275                                 event.preventDefault();
70276                                 connection.authenticate();
70277                             });
70278                     } else {
70279                         // TODO: nice messages for different error types
70280                         selection$$1.text(t('status.error'));
70281                     }
70282
70283                 } else if (apiStatus === 'readonly') {
70284                     selection$$1.text(t('status.readonly'));
70285                 } else if (apiStatus === 'offline') {
70286                     selection$$1.text(t('status.offline'));
70287                 }
70288
70289                 selection$$1.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
70290             });
70291         }
70292
70293         connection
70294             .on('change', function() { update(selection$$1); });
70295
70296         window.setInterval(update, 90000);
70297         update(selection$$1);
70298     };
70299 }
70300
70301 function uiUndoRedo(context) {
70302     var commands = [{
70303         id: 'undo',
70304         cmd: uiCmd('⌘Z'),
70305         action: function() { if (!saving()) context.undo(); },
70306         annotation: function() { return context.history().undoAnnotation(); }
70307     }, {
70308         id: 'redo',
70309         cmd: uiCmd('⌘⇧Z'),
70310         action: function() { if (!saving()) context.redo(); },
70311         annotation: function() { return context.history().redoAnnotation(); }
70312     }];
70313
70314
70315     function saving() {
70316         return context.mode().id === 'save';
70317     }
70318
70319
70320     return function(selection$$1) {
70321         var tooltipBehavior = tooltip()
70322             .placement('bottom')
70323             .html(true)
70324             .title(function (d) {
70325                 return uiTooltipHtml(d.annotation() ?
70326                     t(d.id + '.tooltip', {action: d.annotation()}) :
70327                     t(d.id + '.nothing'), d.cmd);
70328             });
70329
70330         var buttons = selection$$1.selectAll('button')
70331             .data(commands)
70332             .enter()
70333             .append('button')
70334             .attr('class', function(d) { return 'col6 disabled ' + d.id + '-button'; })
70335             .on('click', function(d) { return d.action(); })
70336             .call(tooltipBehavior);
70337
70338         buttons.each(function(d) {
70339             var iconName = d.id;
70340             if (textDirection === 'rtl') {
70341                 if (iconName === 'undo') {
70342                     iconName = 'redo';
70343                 } else if (iconName === 'redo') {
70344                     iconName = 'undo';
70345                 }
70346             }
70347             select(this)
70348                 .call(svgIcon('#icon-' + iconName));
70349         });
70350
70351         var keybinding = d3keybinding('undo')
70352             .on(commands[0].cmd, function() { event.preventDefault(); commands[0].action(); })
70353             .on(commands[1].cmd, function() { event.preventDefault(); commands[1].action(); });
70354
70355         select(document)
70356             .call(keybinding);
70357
70358         context.history()
70359             .on('change.undo_redo', update);
70360
70361         context
70362             .on('enter.undo_redo', update);
70363
70364         function update() {
70365             buttons
70366                 .property('disabled', saving())
70367                 .classed('disabled', function(d) { return !d.annotation(); })
70368                 .each(function() {
70369                     var selection$$1 = select(this);
70370                     if (selection$$1.property('tooltipVisible')) {
70371                         selection$$1.call(tooltipBehavior.show);
70372                     }
70373                 });
70374         }
70375     };
70376 }
70377
70378 // these are module variables so they are preserved through a ui.restart()
70379 var sawVersion = null;
70380 var isNewVersion = false;
70381 var isNewUser = false;
70382
70383
70384 function uiVersion(context) {
70385
70386     var currVersion = context.version,
70387         matchedVersion = currVersion.match(/\d\.\d\.\d.*/);
70388
70389     if (sawVersion === null && matchedVersion !== null) {
70390         isNewVersion = (context.storage('sawVersion') !== currVersion);
70391         isNewUser = !context.storage('sawSplash');
70392         context.storage('sawVersion', currVersion);
70393         sawVersion = currVersion;
70394     }
70395
70396     return function(selection) {
70397         selection
70398             .append('a')
70399             .attr('target', '_blank')
70400             .attr('tabindex', -1)
70401             .attr('href', 'https://github.com/openstreetmap/iD')
70402             .text(currVersion);
70403
70404         // only show new version indicator to users that have used iD before
70405         if (isNewVersion && !isNewUser) {
70406             selection
70407                 .append('div')
70408                 .attr('class', 'badge')
70409                 .append('a')
70410                 .attr('target', '_blank')
70411                 .attr('tabindex', -1)
70412                 .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CHANGELOG.md#whats-new')
70413                 .call(svgIcon('#gift-11'))
70414                 .call(tooltip()
70415                     .title(t('version.whats_new', { version: currVersion }))
70416                     .placement('top')
70417                 );
70418         }
70419     };
70420 }
70421
70422 function uiZoom(context) {
70423     var zooms = [{
70424         id: 'zoom-in',
70425         icon: 'plus',
70426         title: t('zoom.in'),
70427         action: context.zoomIn,
70428         key: '+'
70429     }, {
70430         id: 'zoom-out',
70431         icon: 'minus',
70432         title: t('zoom.out'),
70433         action: context.zoomOut,
70434         key: '-'
70435     }];
70436
70437
70438     function zoomIn() {
70439         event.preventDefault();
70440         context.zoomIn();
70441     }
70442
70443
70444     function zoomOut() {
70445         event.preventDefault();
70446         context.zoomOut();
70447     }
70448
70449
70450     function zoomInFurther() {
70451         event.preventDefault();
70452         context.zoomInFurther();
70453     }
70454
70455
70456     function zoomOutFurther() {
70457         event.preventDefault();
70458         context.zoomOutFurther();
70459     }
70460
70461
70462     return function(selection$$1) {
70463         var button = selection$$1.selectAll('button')
70464             .data(zooms)
70465             .enter()
70466             .append('button')
70467             .attr('tabindex', -1)
70468             .attr('class', function(d) { return d.id; })
70469             .on('click.editor', function(d) { d.action(); })
70470             .call(tooltip()
70471                 .placement((textDirection === 'rtl') ? 'right' : 'left')
70472                 .html(true)
70473                 .title(function(d) {
70474                     return uiTooltipHtml(d.title, d.key);
70475                 })
70476             );
70477
70478         button.each(function(d) {
70479             select(this)
70480                 .call(svgIcon('#icon-' + d.icon, 'light'));
70481         });
70482
70483         var keybinding = d3keybinding('zoom');
70484
70485        lodash.each(['plus', 'ffplus', '=', 'ffequals'], function(key) {
70486             keybinding.on([key], zoomIn);
70487             keybinding.on([uiCmd('⌘' + key)], zoomInFurther);
70488         });
70489
70490         lodash.each(['_', '-', 'ffminus', 'dash'], function(key) {
70491             keybinding.on([key], zoomOut);
70492             keybinding.on([uiCmd('⌘' + key)], zoomOutFurther);
70493         });
70494
70495         select(document)
70496             .call(keybinding);
70497     };
70498 }
70499
70500 function uiInit(context) {
70501     var uiInitCounter = 0;
70502
70503
70504     function render(container) {
70505         container
70506             .attr('dir', textDirection);
70507
70508         var map = context.map();
70509
70510         var hash = behaviorHash(context);
70511         hash();
70512
70513         if (!hash.hadHash) {
70514             map.centerZoom([0, 0], 2);
70515         }
70516
70517         container
70518             .append('svg')
70519             .attr('id', 'defs')
70520             .call(svgDefs(context));
70521
70522         container
70523             .append('div')
70524             .attr('id', 'sidebar')
70525             .attr('class', 'col4')
70526             .call(ui.sidebar);
70527
70528         var content = container
70529             .append('div')
70530             .attr('id', 'content')
70531             .attr('class', 'active');
70532
70533         var bar = content
70534             .append('div')
70535             .attr('id', 'bar')
70536             .attr('class', 'fillD');
70537
70538         content
70539             .append('div')
70540             .attr('id', 'map')
70541             .attr('dir', 'ltr')
70542             .call(map);
70543
70544         content
70545             .call(uiMapInMap(context));
70546
70547         content
70548             .append('div')
70549             .call(uiInfo(context));
70550
70551         bar
70552             .append('div')
70553             .attr('class', 'spacer col4');
70554
70555         var limiter = bar.append('div')
70556             .attr('class', 'limiter');
70557
70558         limiter
70559             .append('div')
70560             .attr('class', 'button-wrap joined col3')
70561             .call(uiModes(context), limiter);
70562
70563         limiter
70564             .append('div')
70565             .attr('class', 'button-wrap joined col1')
70566             .call(uiUndoRedo(context));
70567
70568         limiter
70569             .append('div')
70570             .attr('class', 'button-wrap col1')
70571             .call(uiSave(context));
70572
70573         bar
70574             .append('div')
70575             .attr('class', 'full-screen')
70576             .call(uiFullScreen(context));
70577
70578         bar
70579             .append('div')
70580             .attr('class', 'spinner')
70581             .call(uiSpinner(context));
70582
70583
70584         var controls = bar
70585             .append('div')
70586             .attr('class', 'map-controls');
70587
70588         controls
70589             .append('div')
70590             .attr('class', 'map-control zoombuttons')
70591             .call(uiZoom(context));
70592
70593         controls
70594             .append('div')
70595             .attr('class', 'map-control geolocate-control')
70596             .call(uiGeolocate(context));
70597
70598         controls
70599             .append('div')
70600             .attr('class', 'map-control background-control')
70601             .call(uiBackground(context));
70602
70603         controls
70604             .append('div')
70605             .attr('class', 'map-control map-data-control')
70606             .call(uiMapData(context));
70607
70608         controls
70609             .append('div')
70610             .attr('class', 'map-control help-control')
70611             .call(uiHelp(context));
70612
70613
70614         var about = content
70615             .append('div')
70616             .attr('id', 'about');
70617
70618         about
70619             .append('div')
70620             .attr('id', 'attrib')
70621             .attr('dir', 'ltr')
70622             .call(uiAttribution(context));
70623
70624         about
70625             .append('div')
70626             .attr('class', 'api-status')
70627             .call(uiStatus(context));
70628
70629
70630         var footer = about
70631             .append('div')
70632             .attr('id', 'footer')
70633             .attr('class', 'fillD');
70634
70635         footer
70636             .append('div')
70637             .attr('id', 'flash-wrap')
70638             .attr('class', 'footer-hide');
70639
70640         var footerWrap = footer
70641             .append('div')
70642             .attr('id', 'footer-wrap')
70643             .attr('class', 'footer-show');
70644
70645         footerWrap
70646             .append('div')
70647             .attr('id', 'scale-block')
70648             .call(uiScale(context));
70649
70650         var aboutList = footerWrap
70651             .append('div')
70652             .attr('id', 'info-block')
70653             .append('ul')
70654             .attr('id', 'about-list');
70655
70656         if (!context.embed()) {
70657             aboutList
70658                 .call(uiAccount(context));
70659         }
70660
70661         aboutList
70662             .append('li')
70663             .attr('class', 'version')
70664             .call(uiVersion(context));
70665
70666         var issueLinks = aboutList
70667             .append('li');
70668
70669         issueLinks
70670             .append('a')
70671             .attr('target', '_blank')
70672             .attr('tabindex', -1)
70673             .attr('href', 'https://github.com/openstreetmap/iD/issues')
70674             .call(svgIcon('#icon-bug', 'light'))
70675             .call(tooltip().title(t('report_a_bug')).placement('top'));
70676
70677         issueLinks
70678             .append('a')
70679             .attr('target', '_blank')
70680             .attr('tabindex', -1)
70681             .attr('href', 'https://github.com/openstreetmap/iD/blob/master/CONTRIBUTING.md#translating')
70682             .call(svgIcon('#icon-translate', 'light'))
70683             .call(tooltip().title(t('help_translate')).placement('top'));
70684
70685         aboutList
70686             .append('li')
70687             .attr('class', 'feature-warning')
70688             .attr('tabindex', -1)
70689             .call(uiFeatureInfo(context));
70690
70691         aboutList
70692             .append('li')
70693             .attr('class', 'user-list')
70694             .attr('tabindex', -1)
70695             .call(uiContributors(context));
70696
70697
70698         window.onbeforeunload = function() {
70699             return context.save();
70700         };
70701
70702         window.onunload = function() {
70703             context.history().unlock();
70704         };
70705
70706         var mapDimensions = map.dimensions();
70707
70708
70709         function onResize() {
70710             mapDimensions = utilGetDimensions(content, true);
70711             map.dimensions(mapDimensions);
70712         }
70713
70714         select(window)
70715             .on('resize.editor', onResize);
70716
70717         onResize();
70718
70719         function pan(d) {
70720             return function() {
70721                 event.preventDefault();
70722                 context.pan(d, 100);
70723             };
70724         }
70725
70726
70727         // pan amount
70728         var pa = 10;
70729
70730         var keybinding = d3keybinding('main')
70731             .on('⌫', function() { event.preventDefault(); })
70732             .on('←', pan([pa, 0]))
70733             .on('↑', pan([0, pa]))
70734             .on('→', pan([-pa, 0]))
70735             .on('↓', pan([0, -pa]))
70736             .on(['⇧←', uiCmd('⌘←')], pan([mapDimensions[0], 0]))
70737             .on(['⇧↑', uiCmd('⌘↑')], pan([0, mapDimensions[1]]))
70738             .on(['⇧→', uiCmd('⌘→')], pan([-mapDimensions[0], 0]))
70739             .on(['⇧↓', uiCmd('⌘↓')], pan([0, -mapDimensions[1]]));
70740
70741         select(document)
70742             .call(keybinding);
70743
70744         context.enter(modeBrowse(context));
70745
70746         if (!uiInitCounter++) {
70747             context.container()
70748                 .call(uiSplash(context))
70749                 .call(uiRestore(context))
70750                 .call(uiShortcuts(context));
70751         }
70752
70753         var authenticating = uiLoading(context)
70754             .message(t('loading_auth'))
70755             .blocking(true);
70756
70757         context.connection()
70758             .on('authLoading.ui', function() {
70759                 context.container()
70760                     .call(authenticating);
70761             })
70762             .on('authDone.ui', function() {
70763                 authenticating.close();
70764             });
70765
70766         uiInitCounter++;
70767     }
70768
70769
70770     var renderCallback;
70771
70772     function ui(node, callback) {
70773         renderCallback = callback;
70774         var container = select(node);
70775         context.container(container);
70776         context.loadLocale(function(err) {
70777             if (!err) {
70778                 render(container);
70779             }
70780             if (callback) {
70781                 callback(err);
70782             }
70783         });
70784     }
70785
70786
70787     ui.restart = function(arg) {
70788         context.locale(arg);
70789         context.loadLocale(function(err) {
70790             if (!err) {
70791                 context.container().selectAll('*').remove();
70792                 render(context.container());
70793                 if (renderCallback) renderCallback();
70794             }
70795         });
70796     };
70797
70798
70799     ui.sidebar = uiSidebar(context);
70800
70801     return ui;
70802 }
70803
70804 var changeset;
70805 var readOnlyTags = ['created_by', 'imagery_used', 'host', 'locale'];
70806
70807
70808 function uiCommit(context) {
70809     var dispatch$$1 = dispatch('cancel', 'save');
70810
70811
70812     function commit(selection$$1) {
70813         if (!changeset) {
70814             var detected = utilDetect(),
70815                 tags = {
70816                     created_by: ('iD ' + context.version).substr(0, 255),
70817                     imagery_used: context.history().imageryUsed().join(';').substr(0, 255),
70818                     host: detected.host.substr(0, 255),
70819                     locale: detected.locale.substr(0, 255)
70820                 };
70821
70822             changeset = new osmChangeset({ tags: tags });
70823         }
70824
70825
70826         var changes = context.history().changes(),
70827             summary = context.history().difference().summary(),
70828             rawTagEditor = uiRawTagEditor(context).on('change', changeTags),
70829             comment = context.storage('comment') || '',
70830             commentDate = +context.storage('commentDate') || 0,
70831             currDate = Date.now(),
70832             cutoff = 2 * 86400 * 1000;   // 2 days
70833
70834         // expire the stored comment if it is too old - #3947
70835         if (commentDate > currDate || currDate - commentDate > cutoff) {
70836             comment = '';
70837         }
70838
70839         selection$$1
70840             .append('div')
70841             .attr('class', 'header fillL')
70842             .append('h3')
70843             .text(t('commit.title'));
70844
70845         var body = selection$$1
70846             .append('div')
70847             .attr('class', 'body');
70848
70849         var commentSection = body
70850             .append('div')
70851             .attr('class', 'modal-section form-field commit-form');
70852
70853         commentSection
70854             .append('label')
70855             .attr('class', 'form-label')
70856             .text(t('commit.message_label'));
70857
70858         var commentField = commentSection
70859             .append('textarea')
70860             .attr('class', 'commit-form-comment')
70861             .attr('placeholder', t('commit.description_placeholder'))
70862             .attr('maxlength', 255)
70863             .property('value', comment)
70864             .on('input.save', change(true))
70865             .on('change.save', change())
70866             .on('blur.save', function() {
70867                 context.storage('comment', this.value);
70868                 context.storage('commentDate', Date.now());
70869             });
70870
70871
70872         commentField.node().select();
70873
70874         context.connection().userChangesets(function (err, changesets) {
70875             if (err) return;
70876
70877             var comments = changesets.map(function(changeset) {
70878                 return {
70879                     title: changeset.tags.comment,
70880                     value: changeset.tags.comment
70881                 };
70882             });
70883
70884             commentField
70885                 .call(d3combobox()
70886                     .container(context.container())
70887                     .caseSensitive(true)
70888                     .data(lodash.uniqBy(comments, 'title'))
70889                 );
70890         });
70891
70892         var clippyArea = commentSection.append('div')
70893             .attr('class', 'clippy-area');
70894
70895         var changeSetInfo = commentSection.append('div')
70896             .attr('class', 'changeset-info');
70897
70898         changeSetInfo.append('a')
70899             .attr('target', '_blank')
70900             .attr('tabindex', -1)
70901             .call(svgIcon('#icon-out-link', 'inline'))
70902             .attr('href', t('commit.about_changeset_comments_link'))
70903             .append('span')
70904             .text(t('commit.about_changeset_comments'));
70905
70906
70907         // Warnings
70908         var warnings = body.selectAll('div.warning-section')
70909             .data([context.history().validate(changes)]);
70910
70911         warnings = warnings.enter()
70912             .append('div')
70913             .attr('class', 'modal-section warning-section fillL2')
70914             .style('display', function(d) { return lodash.isEmpty(d) ? 'none' : null; })
70915             .style('background', '#ffb')
70916             .merge(warnings);
70917
70918         warnings
70919             .append('h3')
70920             .text(t('commit.warnings'));
70921
70922         warnings
70923             .append('ul')
70924             .attr('class', 'changeset-list');
70925
70926         var warningLi = warnings.select('ul').selectAll('li')
70927             .data(function(d) { return d; });
70928
70929         warningLi = warningLi.enter()
70930             .append('li')
70931             .on('mouseover', mouseover)
70932             .on('mouseout', mouseout)
70933             .on('click', warningClick)
70934             .merge(warningLi);
70935
70936         warningLi
70937             .call(svgIcon('#icon-alert', 'pre-text'));
70938
70939         warningLi
70940             .append('strong')
70941             .text(function(d) { return d.message; });
70942
70943         warningLi.filter(function(d) { return d.tooltip; })
70944             .call(tooltip()
70945                 .title(function(d) { return d.tooltip; })
70946                 .placement('top')
70947             );
70948
70949
70950         // Upload Explanation
70951         var saveSection = body
70952             .append('div')
70953             .attr('class','modal-section save-section fillL cf');
70954
70955         var prose = saveSection
70956             .append('p')
70957             .attr('class', 'commit-info')
70958             .html(t('commit.upload_explanation'));
70959
70960
70961         context.connection().userDetails(function(err, user) {
70962             if (err) return;
70963
70964             var userLink = select(document.createElement('div'));
70965
70966             if (user.image_url) {
70967                 userLink
70968                     .append('img')
70969                     .attr('src', user.image_url)
70970                     .attr('class', 'icon pre-text user-icon');
70971             }
70972
70973             userLink
70974                 .append('a')
70975                 .attr('class','user-info')
70976                 .text(user.display_name)
70977                 .attr('href', context.connection().userURL(user.display_name))
70978                 .attr('tabindex', -1)
70979                 .attr('target', '_blank');
70980
70981             prose
70982                 .html(t('commit.upload_explanation_with_user', { user: userLink.html() }));
70983         });
70984
70985
70986         // Buttons
70987         var buttonSection = saveSection
70988             .append('div')
70989             .attr('class', 'buttons fillL cf');
70990
70991         var cancelButton = buttonSection
70992             .append('button')
70993             .attr('class', 'secondary-action col5 button cancel-button')
70994             .on('click.cancel', function() {
70995                 dispatch$$1.call('cancel');
70996             });
70997
70998         cancelButton
70999             .append('span')
71000             .attr('class', 'label')
71001             .text(t('commit.cancel'));
71002
71003         var saveButton = buttonSection
71004             .append('button')
71005             .attr('class', 'action col5 button save-button')
71006             .attr('disabled', function() {
71007                 var n = select('.commit-form textarea').node();
71008                 return (n && n.value.length) ? null : true;
71009             })
71010             .on('click.save', function() {
71011                 dispatch$$1.call('save', this, changeset);
71012             });
71013
71014         saveButton
71015             .append('span')
71016             .attr('class', 'label')
71017             .text(t('commit.save'));
71018
71019
71020         // Raw Tag Editor
71021         var tagSection = body
71022             .append('div')
71023             .attr('class', 'modal-section tag-section raw-tag-editor');
71024
71025
71026         // Changes
71027         var changeSection = body
71028             .append('div')
71029             .attr('class', 'commit-section modal-section fillL2');
71030
71031         changeSection.append('h3')
71032             .text(t('commit.changes', { count: summary.length }));
71033
71034         var li = changeSection
71035             .append('ul')
71036             .attr('class', 'changeset-list')
71037             .selectAll('li')
71038             .data(summary);
71039
71040         li = li.enter()
71041             .append('li')
71042             .on('mouseover', mouseover)
71043             .on('mouseout', mouseout)
71044             .on('click', zoomToEntity)
71045             .merge(li);
71046
71047         li.each(function(d) {
71048             select(this)
71049                 .call(svgIcon('#icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
71050         });
71051
71052         li.append('span')
71053             .attr('class', 'change-type')
71054             .text(function(d) { return t('commit.' + d.changeType) + ' '; });
71055
71056         li.append('strong')
71057             .attr('class', 'entity-type')
71058             .text(function(d) {
71059                 var matched = context.presets().match(d.entity, d.graph);
71060                 return (matched && matched.name()) || utilDisplayType(d.entity.id);
71061             });
71062
71063         li.append('span')
71064             .attr('class', 'entity-name')
71065             .text(function(d) {
71066                 var name = utilDisplayName(d.entity) || '',
71067                     string = '';
71068                 if (name !== '') string += ':';
71069                 return string += ' ' + name;
71070             });
71071
71072         li.style('opacity', 0)
71073             .transition()
71074             .style('opacity', 1);
71075
71076
71077         // Call change() off the bat, in case a changeset
71078         // comment is recovered from localStorage
71079         utilTriggerEvent(commentField, 'input');
71080
71081
71082         function mouseover(d) {
71083             if (d.entity) {
71084                 context.surface().selectAll(
71085                     utilEntityOrMemberSelector([d.entity.id], context.graph())
71086                 ).classed('hover', true);
71087             }
71088         }
71089
71090
71091         function mouseout() {
71092             context.surface().selectAll('.hover')
71093                 .classed('hover', false);
71094         }
71095
71096
71097         function warningClick(d) {
71098             if (d.entity) {
71099                 context.map().zoomTo(d.entity);
71100                 context.enter(modeSelect(context, [d.entity.id]));
71101             }
71102         }
71103
71104
71105         function zoomToEntity(change) {
71106             var entity = change.entity;
71107             if (change.changeType !== 'deleted' &&
71108                 context.graph().entity(entity.id).geometry(context.graph()) !== 'vertex') {
71109                 context.map().zoomTo(entity);
71110                 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph()))
71111                     .classed('hover', true);
71112             }
71113         }
71114
71115
71116         function checkComment(comment) {
71117             // Save button disabled if there is no comment..
71118             selectAll('.save-section .save-button')
71119                 .attr('disabled', (comment.length ? null : true));
71120
71121             // Warn if comment mentions Google..
71122             var googleWarning = clippyArea
71123                .html('')
71124                .selectAll('a')
71125                .data(comment.match(/google/i) ? [true] : []);
71126
71127             googleWarning.exit()
71128                 .remove();
71129
71130             googleWarning.enter()
71131                .append('a')
71132                .attr('target', '_blank')
71133                .attr('tabindex', -1)
71134                .call(svgIcon('#icon-alert', 'inline'))
71135                .attr('href', t('commit.google_warning_link'))
71136                .append('span')
71137                .text(t('commit.google_warning'));
71138         }
71139
71140
71141         function change(onInput) {
71142             return function() {
71143                 var comment = commentField.property('value').trim();
71144                 if (!onInput) {
71145                     commentField.property('value', comment);
71146                 }
71147
71148                 checkComment(comment);
71149
71150                 var changeset = updateChangeset({ comment: comment });
71151                 var expanded = !tagSection.selectAll('a.hide-toggle.expanded').empty();
71152
71153                 tagSection
71154                     .call(rawTagEditor
71155                         .expanded(expanded)
71156                         .readOnlyTags(readOnlyTags)
71157                         .tags(lodash.clone(changeset.tags))
71158                     );
71159             };
71160         }
71161
71162
71163         function changeTags(changed) {
71164             if (changed.hasOwnProperty('comment')) {
71165                 if (changed.comment === undefined) {
71166                     changed.comment = '';
71167                 }
71168                 changed.comment = changed.comment.trim();
71169                 commentField.property('value', changed.comment);
71170             }
71171             updateChangeset(changed);
71172             utilTriggerEvent(commentField, 'input');
71173         }
71174
71175
71176         function updateChangeset(changed) {
71177             var tags = lodash.clone(changeset.tags);
71178
71179             lodash.forEach(changed, function(v, k) {
71180                 k = k.trim().substr(0, 255);
71181                 if (readOnlyTags.indexOf(k) !== -1) return;
71182
71183                 if (k !== '' && v !== undefined) {
71184                     tags[k] = v.trim().substr(0, 255);
71185                 } else {
71186                     delete tags[k];
71187                 }
71188             });
71189
71190             if (!lodash.isEqual(changeset.tags, tags)) {
71191                 changeset = changeset.update({ tags: tags });
71192             }
71193
71194             return changeset;
71195         }
71196
71197     }
71198
71199
71200     commit.reset = function() {
71201         changeset = null;
71202     };
71203
71204
71205     return utilRebind(commit, dispatch$$1, 'on');
71206 }
71207
71208 function uiConfirm(selection) {
71209     var modalSelection = uiModal(selection);
71210
71211     modalSelection.select('.modal')
71212         .classed('modal-alert', true);
71213
71214     var section = modalSelection.select('.content');
71215
71216     section.append('div')
71217         .attr('class', 'modal-section header');
71218
71219     section.append('div')
71220         .attr('class', 'modal-section message-text');
71221
71222     var buttons = section.append('div')
71223         .attr('class', 'modal-section buttons cf');
71224
71225
71226     modalSelection.okButton = function() {
71227         buttons
71228             .append('button')
71229             .attr('class', 'action col4')
71230             .on('click.confirm', function() {
71231                 modalSelection.remove();
71232             })
71233             .text(t('confirm.okay'));
71234
71235         return modalSelection;
71236     };
71237
71238
71239     return modalSelection;
71240 }
71241
71242 function uiConflicts(context) {
71243     var dispatch$$1 = dispatch('download', 'cancel', 'save'),
71244         list;
71245
71246
71247     function conflicts(selection$$1) {
71248         var header = selection$$1
71249             .append('div')
71250             .attr('class', 'header fillL');
71251
71252         header
71253             .append('button')
71254             .attr('class', 'fr')
71255             .on('click', function() { dispatch$$1.call('cancel'); })
71256             .call(svgIcon('#icon-close'));
71257
71258         header
71259             .append('h3')
71260             .text(t('save.conflict.header'));
71261
71262         var body = selection$$1
71263             .append('div')
71264             .attr('class', 'body fillL');
71265
71266         body
71267             .append('div')
71268             .attr('class', 'conflicts-help')
71269             .text(t('save.conflict.help'))
71270             .append('a')
71271             .attr('class', 'conflicts-download')
71272             .text(t('save.conflict.download_changes'))
71273             .on('click.download', function() { dispatch$$1.call('download'); });
71274
71275         body
71276             .append('div')
71277             .attr('class', 'conflict-container fillL3')
71278             .call(showConflict, 0);
71279
71280         body
71281             .append('div')
71282             .attr('class', 'conflicts-done')
71283             .attr('opacity', 0)
71284             .style('display', 'none')
71285             .text(t('save.conflict.done'));
71286
71287         var buttons = body
71288             .append('div')
71289             .attr('class','buttons col12 joined conflicts-buttons');
71290
71291         buttons
71292             .append('button')
71293             .attr('disabled', list.length > 1)
71294             .attr('class', 'action conflicts-button col6')
71295             .text(t('save.title'))
71296             .on('click.try_again', function() { dispatch$$1.call('save'); });
71297
71298         buttons
71299             .append('button')
71300             .attr('class', 'secondary-action conflicts-button col6')
71301             .text(t('confirm.cancel'))
71302             .on('click.cancel', function() { dispatch$$1.call('cancel'); });
71303     }
71304
71305
71306     function showConflict(selection$$1, index) {
71307         if (index < 0 || index >= list.length) return;
71308
71309         var parent = select(selection$$1.node().parentNode);
71310
71311         // enable save button if this is the last conflict being reviewed..
71312         if (index === list.length - 1) {
71313             window.setTimeout(function() {
71314                 parent.select('.conflicts-button')
71315                     .attr('disabled', null);
71316
71317                 parent.select('.conflicts-done')
71318                     .transition()
71319                     .attr('opacity', 1)
71320                     .style('display', 'block');
71321             }, 250);
71322         }
71323
71324         var item = selection$$1
71325             .selectAll('.conflict')
71326             .data([list[index]]);
71327
71328         var enter = item.enter()
71329             .append('div')
71330             .attr('class', 'conflict');
71331
71332         enter
71333             .append('h4')
71334             .attr('class', 'conflict-count')
71335             .text(t('save.conflict.count', { num: index + 1, total: list.length }));
71336
71337         enter
71338             .append('a')
71339             .attr('class', 'conflict-description')
71340             .attr('href', '#')
71341             .text(function(d) { return d.name; })
71342             .on('click', function(d) {
71343                 zoomToEntity(d.id);
71344                 event.preventDefault();
71345             });
71346
71347         var details = enter
71348             .append('div')
71349             .attr('class', 'conflict-detail-container');
71350
71351         details
71352             .append('ul')
71353             .attr('class', 'conflict-detail-list')
71354             .selectAll('li')
71355             .data(function(d) { return d.details || []; })
71356             .enter()
71357             .append('li')
71358             .attr('class', 'conflict-detail-item')
71359             .html(function(d) { return d; });
71360
71361         details
71362             .append('div')
71363             .attr('class', 'conflict-choices')
71364             .call(addChoices);
71365
71366         details
71367             .append('div')
71368             .attr('class', 'conflict-nav-buttons joined cf')
71369             .selectAll('button')
71370             .data(['previous', 'next'])
71371             .enter()
71372             .append('button')
71373             .text(function(d) { return t('save.conflict.' + d); })
71374             .attr('class', 'conflict-nav-button action col6')
71375             .attr('disabled', function(d, i) {
71376                 return (i === 0 && index === 0) ||
71377                     (i === 1 && index === list.length - 1) || null;
71378             })
71379             .on('click', function(d, i) {
71380                 var container = parent.select('.conflict-container'),
71381                 sign = (i === 0 ? -1 : 1);
71382
71383                 container
71384                     .selectAll('.conflict')
71385                     .remove();
71386
71387                 container
71388                     .call(showConflict, index + sign);
71389
71390                 event.preventDefault();
71391             });
71392
71393         item.exit()
71394             .remove();
71395     }
71396
71397
71398     function addChoices(selection$$1) {
71399         var choices = selection$$1
71400             .append('ul')
71401             .attr('class', 'layer-list')
71402             .selectAll('li')
71403             .data(function(d) { return d.choices || []; });
71404
71405         var enter = choices.enter()
71406             .append('li')
71407             .attr('class', 'layer');
71408
71409         var label = enter
71410             .append('label');
71411
71412         label
71413             .append('input')
71414             .attr('type', 'radio')
71415             .attr('name', function(d) { return d.id; })
71416             .on('change', function(d, i) {
71417                 var ul = this.parentNode.parentNode.parentNode;
71418                 ul.__data__.chosen = i;
71419                 choose(ul, d);
71420             });
71421
71422         label
71423             .append('span')
71424             .text(function(d) { return d.text; });
71425
71426         choices
71427             .each(function(d, i) {
71428                 var ul = this.parentNode;
71429                 if (ul.__data__.chosen === i) choose(ul, d);
71430             });
71431     }
71432
71433
71434     function choose(ul, datum) {
71435         if (event) event.preventDefault();
71436
71437         select(ul)
71438             .selectAll('li')
71439             .classed('active', function(d) { return d === datum; })
71440             .selectAll('input')
71441             .property('checked', function(d) { return d === datum; });
71442
71443         var extent$$1 = geoExtent$$1(),
71444             entity;
71445
71446         entity = context.graph().hasEntity(datum.id);
71447         if (entity) extent$$1._extend(entity.extent(context.graph()));
71448
71449         datum.action();
71450
71451         entity = context.graph().hasEntity(datum.id);
71452         if (entity) extent$$1._extend(entity.extent(context.graph()));
71453
71454         zoomToEntity(datum.id, extent$$1);
71455     }
71456
71457
71458     function zoomToEntity(id, extent$$1) {
71459         context.surface().selectAll('.hover')
71460             .classed('hover', false);
71461
71462         var entity = context.graph().hasEntity(id);
71463         if (entity) {
71464             if (extent$$1) {
71465                 context.map().trimmedExtent(extent$$1);
71466             } else {
71467                 context.map().zoomTo(entity);
71468             }
71469             context.surface().selectAll(
71470                 utilEntityOrMemberSelector([entity.id], context.graph()))
71471                 .classed('hover', true);
71472         }
71473     }
71474
71475
71476     // The conflict list should be an array of objects like:
71477     // {
71478     //     id: id,
71479     //     name: entityName(local),
71480     //     details: merge.conflicts(),
71481     //     chosen: 1,
71482     //     choices: [
71483     //         choice(id, keepMine, forceLocal),
71484     //         choice(id, keepTheirs, forceRemote)
71485     //     ]
71486     // }
71487     conflicts.list = function(_) {
71488         if (!arguments.length) return list;
71489         list = _;
71490         return conflicts;
71491     };
71492
71493
71494     return utilRebind(conflicts, dispatch$$1, 'on');
71495 }
71496
71497 function uiEditMenu(context, operations) {
71498     var menu,
71499         center = [0, 0],
71500         offset = [0, 0],
71501         tooltip;
71502
71503     var p = 8,               // top padding
71504         m = 4,               // top margin
71505         h = 15,              // height of icon
71506         vpBottomMargin = 45, // viewport bottom margin
71507         vpSideMargin = 35,   // viewport side margin
71508         buttonWidth = 44,
71509         buttonHeight = (2 * p + h),
71510         menuWidth = buttonWidth,
71511         menuHeight = (2 * m) + operations.length * buttonHeight,
71512         menuSideMargin = 10,
71513         tooltipWidth = 200,
71514         tooltipHeight = 200;  // a reasonable guess, real height depends on tooltip contents
71515
71516
71517     var editMenu = function (selection$$1) {
71518         if (!operations.length) return;
71519
71520         selection$$1.node().parentNode.focus();
71521
71522         var isRTL = textDirection === 'rtl',
71523             viewport = context.surfaceRect();
71524
71525         if (!isRTL && (center[0] + menuSideMargin + menuWidth) > (viewport.width - vpSideMargin)) {
71526             // menu is going left-to-right and near right viewport edge, go left instead
71527             isRTL = true;
71528         } else if (isRTL && (center[0] - menuSideMargin - menuWidth) < vpSideMargin) {
71529             // menu is going right-to-left and near left viewport edge, go right instead
71530             isRTL = false;
71531         }
71532
71533         offset[0] = (isRTL ? -1 * (menuSideMargin + menuWidth) : menuSideMargin);
71534
71535         if (center[1] + menuHeight > (viewport.height - vpBottomMargin)) {
71536             // menu is near bottom viewport edge, shift upwards
71537             offset[1] = -1 * (center[1] + menuHeight - viewport.height + vpBottomMargin);
71538         }
71539
71540         var origin = [ center[0] + offset[0], center[1] + offset[1] ];
71541
71542         menu = selection$$1
71543             .append('g')
71544             .attr('class', 'edit-menu')
71545             .attr('transform', 'translate(' + origin + ')')
71546             .attr('opacity', 0);
71547
71548         menu
71549             .transition()
71550             .attr('opacity', 1);
71551
71552         menu
71553             .append('rect')
71554             .attr('class', 'edit-menu-background')
71555             .attr('x', 4)
71556             .attr('rx', 4)
71557             .attr('ry', 4)
71558             .attr('width', menuWidth)
71559             .attr('height', menuHeight)
71560             .attr('stroke-linecap', 'round');
71561
71562
71563         var button = menu.selectAll('.edit-menu-item')
71564             .data(operations)
71565             .enter()
71566             .append('g')
71567             .attr('class', function (d) { return 'edit-menu-item edit-menu-item-' + d.id; })
71568             .classed('disabled', function (d) { return d.disabled(); })
71569             .attr('transform', function (d, i) {
71570                 return 'translate(' + geoRoundCoords([
71571                     0,
71572                     m + i * buttonHeight
71573                 ]).join(',') + ')';
71574             });
71575
71576         button
71577             .append('rect')
71578             .attr('x', 4)
71579             .attr('width', buttonWidth)
71580             .attr('height', buttonHeight)
71581             .on('click', click)
71582             .on('mousedown', mousedown)
71583             .on('mouseover', mouseover)
71584             .on('mouseout', mouseout);
71585
71586         button
71587             .append('use')
71588             .attr('width', '20')
71589             .attr('height', '20')
71590             .attr('transform', function () {
71591                 return 'translate(' + [2 * p, 5] + ')';
71592             })
71593             .attr('xlink:href', function (d) { return '#operation-' + d.id; });
71594
71595         tooltip = select(document.body)
71596             .append('div')
71597             .attr('class', 'tooltip-inner edit-menu-tooltip');
71598
71599
71600         function click(operation) {
71601             event.stopPropagation();
71602             if (operation.disabled()) return;
71603             operation();
71604             editMenu.close();
71605         }
71606
71607         function mousedown() {
71608             event.stopPropagation();  // https://github.com/openstreetmap/iD/issues/1869
71609         }
71610
71611         function mouseover(d, i) {
71612             var tipX, tipY;
71613
71614             if (!isRTL) {
71615                 tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
71616             } else {
71617                 tipX = viewport.left + origin[0] - 4 - tooltipWidth;
71618             }
71619
71620             if (tipX + tooltipWidth > viewport.right) {
71621                 // tip is going left-to-right and near right viewport edge, go left instead
71622                 tipX = viewport.left + origin[0] - 4 - tooltipWidth;
71623             } else if (tipX < viewport.left) {
71624                 // tip is going right-to-left and near left viewport edge, go right instead
71625                 tipX = viewport.left + origin[0] + menuSideMargin + menuWidth;
71626             }
71627
71628             tipY = viewport.top + origin[1] + (i * buttonHeight);
71629             if (tipY + tooltipHeight > viewport.bottom) {
71630                 // tip is near bottom viewport edge, shift upwards
71631                 tipY -= tipY + tooltipHeight - viewport.bottom;
71632             }
71633
71634             tooltip
71635                 .style('left', tipX + 'px')
71636                 .style('top', tipY + 'px')
71637                 .style('display', 'block')
71638                 .html(uiTooltipHtml(d.tooltip(), d.keys[0], d.title));
71639         }
71640
71641         function mouseout() {
71642             tooltip.style('display', 'none');
71643         }
71644     };
71645
71646
71647     editMenu.close = function () {
71648         if (menu) {
71649             menu
71650                 .style('pointer-events', 'none')
71651                 .transition()
71652                 .attr('opacity', 0)
71653                 .remove();
71654         }
71655
71656         if (tooltip) {
71657             tooltip.remove();
71658         }
71659     };
71660
71661
71662     editMenu.center = function (_) {
71663         if (!arguments.length) return center;
71664         center = _;
71665         return editMenu;
71666     };
71667
71668
71669     return editMenu;
71670 }
71671
71672 var timer$1;
71673
71674 function uiFlash(showDuration) {
71675     showDuration = showDuration || 1500;
71676
71677     if (timer$1) {
71678         timer$1.stop();
71679     }
71680
71681     select('#footer-wrap')
71682         .attr('class', 'footer-hide');
71683     select('#flash-wrap')
71684         .attr('class', 'footer-show');
71685
71686     var content = select('#flash-wrap').selectAll('.content')
71687         .data([0]);
71688
71689     content = content.enter()
71690         .append('div')
71691         .attr('class', 'content')
71692         .merge(content);
71693
71694     timer$1 = timeout$1(function() {
71695         timer$1 = null;
71696         select('#footer-wrap')
71697             .attr('class', 'footer-show');
71698         select('#flash-wrap')
71699             .attr('class', 'footer-hide');
71700     }, showDuration);
71701
71702
71703     return content;
71704 }
71705
71706 function uiLasso(context) {
71707     var group, polygon;
71708
71709     lasso.coordinates = [];
71710
71711     function lasso(selection$$1) {
71712         context.container()
71713             .classed('lasso', true);
71714
71715         group = selection$$1
71716             .append('g')
71717             .attr('class', 'lasso hide');
71718
71719         polygon = group
71720             .append('path')
71721             .attr('class', 'lasso-path');
71722
71723         group
71724             .call(uiToggle(true));
71725     }
71726
71727
71728     function draw() {
71729         if (polygon) {
71730             polygon.data([lasso.coordinates])
71731                 .attr('d', function(d) { return 'M' + d.join(' L') + ' Z'; });
71732         }
71733     }
71734
71735
71736     lasso.extent = function () {
71737         return lasso.coordinates.reduce(function(extent$$1, point) {
71738             return extent$$1.extend(geoExtent$$1(point));
71739         }, geoExtent$$1());
71740     };
71741
71742
71743     lasso.p = function(_) {
71744         if (!arguments.length) return lasso;
71745         lasso.coordinates.push(_);
71746         draw();
71747         return lasso;
71748     };
71749
71750
71751     lasso.close = function() {
71752         if (group) {
71753             group.call(uiToggle(false, function() {
71754                 select(this).remove();
71755             }));
71756         }
71757         context.container().classed('lasso', false);
71758     };
71759
71760
71761     return lasso;
71762 }
71763
71764 function uiRadialMenu(context, operations) {
71765     var menu,
71766         center = [0, 0],
71767         tooltip;
71768
71769
71770     var radialMenu = function(selection$$1) {
71771         if (!operations.length) return;
71772
71773         selection$$1.node().parentNode.focus();
71774
71775         function click(operation) {
71776             event.stopPropagation();
71777             if (operation.disabled()) return;
71778             operation();
71779             radialMenu.close();
71780         }
71781
71782         menu = selection$$1
71783             .append('g')
71784             .attr('class', 'radial-menu')
71785             .attr('transform', 'translate(' + center + ')')
71786             .attr('opacity', 0);
71787
71788         menu
71789             .transition()
71790             .attr('opacity', 1);
71791
71792         var r = 50,
71793             a = Math.PI / 4,
71794             a0 = -Math.PI / 4,
71795             a1 = a0 + (operations.length - 1) * a;
71796
71797         menu
71798             .append('path')
71799             .attr('class', 'radial-menu-background')
71800             .attr('d', 'M' + r * Math.sin(a0) + ',' +
71801                              r * Math.cos(a0) +
71802                       ' A' + r + ',' + r + ' 0 ' + (operations.length > 5 ? '1' : '0') + ',0 ' +
71803                              (r * Math.sin(a1) + 1e-3) + ',' +
71804                              (r * Math.cos(a1) + 1e-3)) // Force positive-length path (#1305)
71805             .attr('stroke-width', 50)
71806             .attr('stroke-linecap', 'round');
71807
71808         var button = menu.selectAll()
71809             .data(operations)
71810             .enter()
71811             .append('g')
71812             .attr('class', function(d) { return 'radial-menu-item radial-menu-item-' + d.id; })
71813             .classed('disabled', function(d) { return d.disabled(); })
71814             .attr('transform', function(d, i) {
71815                 return 'translate(' + geoRoundCoords([
71816                         r * Math.sin(a0 + i * a),
71817                         r * Math.cos(a0 + i * a)]).join(',') + ')';
71818             });
71819
71820         button
71821             .append('circle')
71822             .attr('r', 15)
71823             .on('click', click)
71824             .on('mousedown', mousedown)
71825             .on('mouseover', mouseover)
71826             .on('mouseout', mouseout);
71827
71828         button
71829             .append('use')
71830             .attr('transform', 'translate(-10,-10)')
71831             .attr('width', '20')
71832             .attr('height', '20')
71833             .attr('xlink:href', function(d) { return '#operation-' + d.id; });
71834
71835         tooltip = select(document.body)
71836             .append('div')
71837             .attr('class', 'tooltip-inner radial-menu-tooltip');
71838
71839         function mousedown() {
71840             event.stopPropagation(); // https://github.com/openstreetmap/iD/issues/1869
71841         }
71842
71843         function mouseover(d, i) {
71844             var rect = context.surfaceRect(),
71845                 angle = a0 + i * a,
71846                 top = rect.top + (r + 25) * Math.cos(angle) + center[1] + 'px',
71847                 left = rect.left + (r + 25) * Math.sin(angle) + center[0] + 'px',
71848                 bottom = rect.height - (r + 25) * Math.cos(angle) - center[1] + 'px',
71849                 right = rect.width - (r + 25) * Math.sin(angle) - center[0] + 'px';
71850
71851             tooltip
71852                 .style('top', null)
71853                 .style('left', null)
71854                 .style('bottom', null)
71855                 .style('right', null)
71856                 .style('display', 'block')
71857                 .html(uiTooltipHtml(d.tooltip(), d.keys[0]));
71858
71859             if (i === 0) {
71860                 tooltip
71861                     .style('right', right)
71862                     .style('top', top);
71863             } else if (i >= 4) {
71864                 tooltip
71865                     .style('left', left)
71866                     .style('bottom', bottom);
71867             } else {
71868                 tooltip
71869                     .style('left', left)
71870                     .style('top', top);
71871             }
71872         }
71873
71874         function mouseout() {
71875             tooltip.style('display', 'none');
71876         }
71877     };
71878
71879
71880     radialMenu.close = function() {
71881         if (menu) {
71882             menu
71883                 .style('pointer-events', 'none')
71884                 .transition()
71885                 .attr('opacity', 0)
71886                 .remove();
71887         }
71888
71889         if (tooltip) {
71890             tooltip.remove();
71891         }
71892     };
71893
71894
71895     radialMenu.center = function(_) {
71896         if (!arguments.length) return center;
71897         center = _;
71898         return radialMenu;
71899     };
71900
71901
71902     return radialMenu;
71903 }
71904
71905 function uiSelectionList(context, selectedIDs) {
71906
71907     function selectEntity(entity) {
71908         context.enter(modeSelect(context, [entity.id]));
71909     }
71910
71911
71912     function deselectEntity(entity) {
71913         event.stopPropagation();
71914         var index = selectedIDs.indexOf(entity.id);
71915         if (index > -1) {
71916             selectedIDs.splice(index, 1);
71917         }
71918         context.enter(modeSelect(context, selectedIDs));
71919     }
71920
71921
71922     function selectionList(selection$$1) {
71923         selection$$1.classed('selection-list-pane', true);
71924
71925         var header = selection$$1
71926             .append('div')
71927             .attr('class', 'header fillL cf');
71928
71929         header
71930             .append('h3')
71931             .text(t('inspector.multiselect'));
71932
71933         var listWrap = selection$$1
71934             .append('div')
71935             .attr('class', 'inspector-body');
71936
71937         var list = listWrap
71938             .append('div')
71939             .attr('class', 'feature-list cf');
71940
71941         context.history().on('change.selection-list', drawList);
71942         drawList();
71943
71944
71945         function drawList() {
71946             var entities = selectedIDs
71947                 .map(function(id) { return context.hasEntity(id); })
71948                 .filter(function(entity) { return entity; });
71949
71950             var items = list.selectAll('.feature-list-item')
71951                 .data(entities, osmEntity$$1.key);
71952
71953             items.exit()
71954                 .remove();
71955
71956             // Enter
71957             var enter = items.enter()
71958                 .append('div')
71959                 .attr('class', 'feature-list-item')
71960                 .on('click', selectEntity);
71961
71962             var label = enter
71963                 .append('button')
71964                 .attr('class', 'label');
71965
71966             enter
71967                 .append('button')
71968                 .attr('class', 'close')
71969                 .on('click', deselectEntity)
71970                 .call(svgIcon('#icon-close'));
71971
71972             label
71973                 .append('span')
71974                 .attr('class', 'entity-geom-icon')
71975                 .call(svgIcon('', 'pre-text'));
71976
71977             label
71978                 .append('span')
71979                 .attr('class', 'entity-type');
71980
71981             label
71982                 .append('span')
71983                 .attr('class', 'entity-name');
71984
71985             // Update
71986             items = items.merge(enter);
71987
71988             items.selectAll('.entity-geom-icon use')
71989                 .attr('href', function() {
71990                     var entity = this.parentNode.parentNode.__data__;
71991                     return '#icon-' + context.geometry(entity.id);
71992                 });
71993
71994             items.selectAll('.entity-type')
71995                 .text(function(entity) { return context.presets().match(entity, context.graph()).name(); });
71996
71997             items.selectAll('.entity-name')
71998                 .text(function(entity) { return utilDisplayName(entity); });
71999         }
72000     }
72001
72002     return selectionList;
72003 }
72004
72005 function uiSourceSwitch(context) {
72006     var keys$$1;
72007
72008
72009     function click() {
72010         event.preventDefault();
72011
72012         if (context.history().hasChanges() &&
72013             !window.confirm(t('source_switch.lose_changes'))) return;
72014
72015         var live = select(this)
72016             .classed('live');
72017
72018         context.connection()
72019             .switch(live ? keys$$1[1] : keys$$1[0]);
72020
72021         context.enter(modeBrowse(context));
72022         context.flush();
72023
72024         select(this)
72025             .text(live ? t('source_switch.dev') : t('source_switch.live'))
72026             .classed('live', !live);
72027     }
72028
72029     var sourceSwitch = function(selection$$1) {
72030         selection$$1
72031             .append('a')
72032             .attr('href', '#')
72033             .text(t('source_switch.live'))
72034             .classed('live', true)
72035             .attr('tabindex', -1)
72036             .on('click', click);
72037     };
72038
72039
72040     sourceSwitch.keys = function(_) {
72041         if (!arguments.length) return keys$$1;
72042         keys$$1 = _;
72043         return sourceSwitch;
72044     };
72045
72046
72047     return sourceSwitch;
72048 }
72049
72050 function uiSuccess(context) {
72051     var dispatch$$1 = dispatch('cancel'),
72052         changeset;
72053
72054
72055     function success(selection$$1) {
72056         var header = selection$$1
72057             .append('div')
72058             .attr('class', 'header fillL');
72059
72060         header
72061             .append('button')
72062             .attr('class', 'fr')
72063             .on('click', function() { dispatch$$1.call('cancel'); })
72064             .call(svgIcon('#icon-close'));
72065
72066         header
72067             .append('h3')
72068             .text(t('success.just_edited'));
72069
72070         var body = selection$$1
72071             .append('div')
72072             .attr('class', 'body save-success fillL');
72073
72074         body
72075             .append('p')
72076             .html(t('success.help_html'));
72077
72078         body
72079             .append('a')
72080             .attr('class', 'details')
72081             .attr('target', '_blank')
72082             .attr('tabindex', -1)
72083             .call(svgIcon('#icon-out-link', 'inline'))
72084             .attr('href', t('success.help_link_url'))
72085             .append('span')
72086             .text(t('success.help_link_text'));
72087
72088         var changesetURL = context.connection().changesetURL(changeset.id);
72089
72090
72091         var viewOnOsm = body
72092             .append('a')
72093             .attr('class', 'button col12 osm')
72094             .attr('target', '_blank')
72095             .attr('href', changesetURL);
72096
72097         viewOnOsm
72098             .append('svg')
72099             .attr('class', 'logo logo-osm')
72100             .append('use')
72101             .attr('xlink:href', '#logo-osm');
72102
72103         viewOnOsm
72104             .append('div')
72105             .text(t('success.view_on_osm'));
72106
72107
72108         var message = (changeset.tags.comment || t('success.edited_osm')).substring(0, 130) +
72109             ' ' + context.connection().changesetURL(changeset.id);
72110
72111         var sharing = {
72112             facebook: 'https://facebook.com/sharer/sharer.php?u=' + encodeURIComponent(changesetURL),
72113             twitter: 'https://twitter.com/intent/tweet?source=webclient&text=' + encodeURIComponent(message),
72114             google: 'https://plus.google.com/share?url=' + encodeURIComponent(changesetURL)
72115         };
72116
72117         body.selectAll('.button.social')
72118             .data(entries(sharing))
72119             .enter()
72120             .append('a')
72121             .attr('class', 'button social col4')
72122             .attr('target', '_blank')
72123             .attr('href', function(d) { return d.value; })
72124             .call(tooltip()
72125                 .title(function(d) { return t('success.' + d.key); })
72126                 .placement('bottom'))
72127             .each(function(d) { select(this).call(svgIcon('#logo-' + d.key, 'social')); });
72128     }
72129
72130
72131     success.changeset = function(_) {
72132         if (!arguments.length) return changeset;
72133         changeset = _;
72134         return success;
72135     };
72136
72137
72138     return utilRebind(success, dispatch$$1, 'on');
72139 }
72140
72141 function coreHistory(context) {
72142     var imageryUsed = ['Bing'],
72143         dispatch$$1 = dispatch('change', 'undone', 'redone'),
72144         lock = utilSessionMutex('lock'),
72145         duration = 150,
72146         checkpoints = {},
72147         stack$$1, index, tree$$1;
72148
72149
72150     // internal _act, accepts list of actions and eased time
72151     function _act(actions, t) {
72152         actions = Array.prototype.slice.call(actions);
72153
72154         var annotation;
72155
72156         if (!lodash.isFunction(lodash.last(actions))) {
72157             annotation = actions.pop();
72158         }
72159
72160         stack$$1[index].transform = context.projection.transform();
72161         stack$$1[index].selectedIDs = context.selectedIDs();
72162
72163         var graph = stack$$1[index].graph;
72164         for (var i = 0; i < actions.length; i++) {
72165             graph = actions[i](graph, t);
72166         }
72167
72168         return {
72169             graph: graph,
72170             annotation: annotation,
72171             imageryUsed: imageryUsed
72172         };
72173     }
72174
72175
72176     // internal _perform with eased time
72177     function _perform(args, t) {
72178         var previous = stack$$1[index].graph;
72179         stack$$1 = stack$$1.slice(0, index + 1);
72180         stack$$1.push(_act(args, t));
72181         index++;
72182         return change(previous);
72183     }
72184
72185
72186     // internal _replace with eased time
72187     function _replace(args, t) {
72188         var previous = stack$$1[index].graph;
72189         // assert(index == stack.length - 1)
72190         stack$$1[index] = _act(args, t);
72191         return change(previous);
72192     }
72193
72194
72195     // internal _overwrite with eased time
72196     function _overwrite(args, t) {
72197         var previous = stack$$1[index].graph;
72198         if (index > 0) {
72199             index--;
72200             stack$$1.pop();
72201         }
72202         stack$$1 = stack$$1.slice(0, index + 1);
72203         stack$$1.push(_act(args, t));
72204         index++;
72205         return change(previous);
72206     }
72207
72208
72209     // determine diffrence and dispatch a change event
72210     function change(previous) {
72211         var difference = coreDifference(previous, history.graph());
72212         dispatch$$1.call('change', this, difference);
72213         return difference;
72214     }
72215
72216
72217     // iD uses namespaced keys so multiple installations do not conflict
72218     function getKey(n) {
72219         return 'iD_' + window.location.origin + '_' + n;
72220     }
72221
72222
72223     var history = {
72224
72225         graph: function() {
72226             return stack$$1[index].graph;
72227         },
72228
72229
72230         base: function() {
72231             return stack$$1[0].graph;
72232         },
72233
72234
72235         merge: function(entities, extent$$1) {
72236             stack$$1[0].graph.rebase(entities, lodash.map(stack$$1, 'graph'), false);
72237             tree$$1.rebase(entities, false);
72238
72239             dispatch$$1.call('change', this, undefined, extent$$1);
72240         },
72241
72242
72243         perform: function() {
72244             // complete any transition already in progress
72245             select(document).interrupt('history.perform');
72246
72247             var transitionable = false,
72248                 action0 = arguments[0];
72249
72250             if (arguments.length === 1 ||
72251                 arguments.length === 2 && !lodash.isFunction(arguments[1])) {
72252                 transitionable = !!action0.transitionable;
72253             }
72254
72255             if (transitionable) {
72256                 var origArguments = arguments;
72257                 select(document)
72258                     .transition('history.perform')
72259                     .duration(duration)
72260                     .ease(linear$1)
72261                     .tween('history.tween', function() {
72262                         return function(t) {
72263                             if (t < 1) _overwrite([action0], t);
72264                         };
72265                     })
72266                     .on('start', function() {
72267                         _perform([action0], 0);
72268                     })
72269                     .on('end interrupt', function() {
72270                         _overwrite(origArguments, 1);
72271                     });
72272
72273             } else {
72274                 return _perform(arguments);
72275             }
72276         },
72277
72278
72279         replace: function() {
72280             select(document).interrupt('history.perform');
72281             return _replace(arguments, 1);
72282         },
72283
72284
72285         // Same as calling pop and then perform
72286         overwrite: function() {
72287             select(document).interrupt('history.perform');
72288             return _overwrite(arguments, 1);
72289         },
72290
72291
72292         pop: function(n) {
72293             select(document).interrupt('history.perform');
72294
72295             var previous = stack$$1[index].graph;
72296             if (isNaN(+n) || +n < 0) {
72297                 n = 1;
72298             }
72299             while (n-- > 0 && index > 0) {
72300                 index--;
72301                 stack$$1.pop();
72302             }
72303             return change(previous);
72304         },
72305
72306
72307         // Back to the previous annotated state or index = 0.
72308         undo: function() {
72309             select(document).interrupt('history.perform');
72310
72311             var previous = stack$$1[index].graph;
72312             while (index > 0) {
72313                 index--;
72314                 if (stack$$1[index].annotation) break;
72315             }
72316
72317             dispatch$$1.call('undone', this, stack$$1[index]);
72318             return change(previous);
72319         },
72320
72321
72322         // Forward to the next annotated state.
72323         redo: function() {
72324             select(document).interrupt('history.perform');
72325
72326             var previous = stack$$1[index].graph;
72327             var tryIndex = index;
72328             while (tryIndex < stack$$1.length - 1) {
72329                 tryIndex++;
72330                 if (stack$$1[tryIndex].annotation) {
72331                     index = tryIndex;
72332                     dispatch$$1.call('redone', this, stack$$1[index]);
72333                     break;
72334                 }
72335             }
72336
72337             return change(previous);
72338         },
72339
72340
72341         undoAnnotation: function() {
72342             var i = index;
72343             while (i >= 0) {
72344                 if (stack$$1[i].annotation) return stack$$1[i].annotation;
72345                 i--;
72346             }
72347         },
72348
72349
72350         redoAnnotation: function() {
72351             var i = index + 1;
72352             while (i <= stack$$1.length - 1) {
72353                 if (stack$$1[i].annotation) return stack$$1[i].annotation;
72354                 i++;
72355             }
72356         },
72357
72358
72359         intersects: function(extent$$1) {
72360             return tree$$1.intersects(extent$$1, stack$$1[index].graph);
72361         },
72362
72363
72364         difference: function() {
72365             var base = stack$$1[0].graph,
72366                 head = stack$$1[index].graph;
72367             return coreDifference(base, head);
72368         },
72369
72370
72371         changes: function(action) {
72372             var base = stack$$1[0].graph,
72373                 head = stack$$1[index].graph;
72374
72375             if (action) {
72376                 head = action(head);
72377             }
72378
72379             var difference = coreDifference(base, head);
72380
72381             return {
72382                 modified: difference.modified(),
72383                 created: difference.created(),
72384                 deleted: difference.deleted()
72385             };
72386         },
72387
72388
72389         validate: function(changes) {
72390             return lodash(Validations)
72391                 .map(function(fn) { return fn()(changes, stack$$1[index].graph); })
72392                 .flatten()
72393                 .value();
72394         },
72395
72396
72397         hasChanges: function() {
72398             return this.difference().length() > 0;
72399         },
72400
72401
72402         imageryUsed: function(sources) {
72403             if (sources) {
72404                 imageryUsed = sources;
72405                 return history;
72406             } else {
72407                 return lodash(stack$$1.slice(1, index + 1))
72408                     .map('imageryUsed')
72409                     .flatten()
72410                     .uniq()
72411                     .without(undefined, 'Custom')
72412                     .value();
72413             }
72414         },
72415
72416
72417         // save the current history state
72418         checkpoint: function(key) {
72419             checkpoints[key] = {
72420                 stack: lodash.cloneDeep(stack$$1),
72421                 index: index
72422             };
72423             return history;
72424         },
72425
72426
72427         // restore history state to a given checkpoint or reset completely
72428         reset: function(key) {
72429             if (key !== undefined && checkpoints.hasOwnProperty(key)) {
72430                 stack$$1 = lodash.cloneDeep(checkpoints[key].stack);
72431                 index = checkpoints[key].index;
72432             } else {
72433                 stack$$1 = [{graph: coreGraph$$1()}];
72434                 index = 0;
72435                 tree$$1 = coreTree(stack$$1[0].graph);
72436                 checkpoints = {};
72437             }
72438             dispatch$$1.call('change');
72439             return history;
72440         },
72441
72442
72443         toIntroGraph: function() {
72444             var nextId = { n: 0, r: 0, w: 0 },
72445                 permIds = {},
72446                 graph = this.graph(),
72447                 baseEntities = {};
72448
72449             // clone base entities..
72450             lodash.forEach(graph.base().entities, function(entity) {
72451                 var copy = lodash.cloneDeepWith(entity, customizer);
72452                 baseEntities[copy.id] = copy;
72453             });
72454
72455             // replace base entities with head entities..
72456             lodash.forEach(graph.entities, function(entity, id) {
72457                 if (entity) {
72458                     var copy = lodash.cloneDeepWith(entity, customizer);
72459                     baseEntities[copy.id] = copy;
72460                 } else {
72461                     delete baseEntities[id];
72462                 }
72463             });
72464
72465             // swap temporary for permanent ids..
72466             lodash.forEach(baseEntities, function(entity) {
72467                 if (Array.isArray(entity.nodes)) {
72468                     entity.nodes = entity.nodes.map(function(node) {
72469                         return permIds[node] || node;
72470                     });
72471                 }
72472                 if (Array.isArray(entity.members)) {
72473                     entity.members = entity.members.map(function(member) {
72474                         member.id = permIds[member.id] || member.id;
72475                         return member;
72476                     });
72477                 }
72478             });
72479
72480             return JSON.stringify({ dataIntroGraph: baseEntities });
72481
72482
72483             function customizer(src) {
72484                 var copy = lodash.omit(lodash.cloneDeep(src), ['type', 'user', 'v', 'version', 'visible']);
72485                 if (lodash.isEmpty(copy.tags)) {
72486                     delete copy.tags;
72487                 }
72488
72489                 if (Array.isArray(copy.loc)) {
72490                     copy.loc[0] = +copy.loc[0].toFixed(6);
72491                     copy.loc[1] = +copy.loc[1].toFixed(6);
72492                 }
72493
72494                 var match = src.id.match(/([nrw])-\d*/);  // temporary id
72495                 if (match !== null) {
72496                     var nrw = match[1], permId;
72497                     do { permId = nrw + (++nextId[nrw]); }
72498                     while (baseEntities.hasOwnProperty(permId));
72499
72500                     copy.id = permIds[src.id] = permId;
72501                 }
72502                 return copy;
72503             }
72504         },
72505
72506
72507         toJSON: function() {
72508             if (!this.hasChanges()) return;
72509
72510             var allEntities = {},
72511                 baseEntities = {},
72512                 base = stack$$1[0];
72513
72514             var s = stack$$1.map(function(i) {
72515                 var modified = [], deleted = [];
72516
72517                 lodash.forEach(i.graph.entities, function(entity, id) {
72518                     if (entity) {
72519                         var key = osmEntity$$1.key(entity);
72520                         allEntities[key] = entity;
72521                         modified.push(key);
72522                     } else {
72523                         deleted.push(id);
72524                     }
72525
72526                     // make sure that the originals of changed or deleted entities get merged
72527                     // into the base of the stack after restoring the data from JSON.
72528                     if (id in base.graph.entities) {
72529                         baseEntities[id] = base.graph.entities[id];
72530                     }
72531                     // get originals of parent entities too
72532                     lodash.forEach(base.graph._parentWays[id], function(parentId) {
72533                         if (parentId in base.graph.entities) {
72534                             baseEntities[parentId] = base.graph.entities[parentId];
72535                         }
72536                     });
72537                 });
72538
72539                 var x = {};
72540
72541                 if (modified.length) x.modified = modified;
72542                 if (deleted.length) x.deleted = deleted;
72543                 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
72544                 if (i.annotation) x.annotation = i.annotation;
72545
72546                 return x;
72547             });
72548
72549             return JSON.stringify({
72550                 version: 3,
72551                 entities: lodash.values(allEntities),
72552                 baseEntities: lodash.values(baseEntities),
72553                 stack: s,
72554                 nextIDs: osmEntity$$1.id.next,
72555                 index: index
72556             });
72557         },
72558
72559
72560         fromJSON: function(json$$1, loadChildNodes) {
72561             var h = JSON.parse(json$$1),
72562                 loadComplete = true;
72563
72564             osmEntity$$1.id.next = h.nextIDs;
72565             index = h.index;
72566
72567             if (h.version === 2 || h.version === 3) {
72568                 var allEntities = {};
72569
72570                 h.entities.forEach(function(entity) {
72571                     allEntities[osmEntity$$1.key(entity)] = osmEntity$$1(entity);
72572                 });
72573
72574                 if (h.version === 3) {
72575                     // This merges originals for changed entities into the base of
72576                     // the stack even if the current stack doesn't have them (for
72577                     // example when iD has been restarted in a different region)
72578                     var baseEntities = h.baseEntities.map(function(d) { return osmEntity$$1(d); });
72579                     stack$$1[0].graph.rebase(baseEntities, lodash.map(stack$$1, 'graph'), true);
72580                     tree$$1.rebase(baseEntities, true);
72581
72582                     // When we restore a modified way, we also need to fetch any missing
72583                     // childnodes that would normally have been downloaded with it.. #2142
72584                     if (loadChildNodes) {
72585                         var missing =  lodash(baseEntities)
72586                                 .filter({ type: 'way' })
72587                                 .map('nodes')
72588                                 .flatten()
72589                                 .uniq()
72590                                 .reject(function(n) { return stack$$1[0].graph.hasEntity(n); })
72591                                 .value();
72592
72593                         if (!lodash.isEmpty(missing)) {
72594                             loadComplete = false;
72595                             context.redrawEnable(false);
72596
72597                             var loading = uiLoading(context).blocking(true);
72598                             context.container().call(loading);
72599
72600                             var childNodesLoaded = function(err, result) {
72601                                 if (!err) {
72602                                     var visible = lodash.groupBy(result.data, 'visible');
72603                                     if (!lodash.isEmpty(visible.true)) {
72604                                         missing = lodash.difference(missing, lodash.map(visible.true, 'id'));
72605                                         stack$$1[0].graph.rebase(visible.true, lodash.map(stack$$1, 'graph'), true);
72606                                         tree$$1.rebase(visible.true, true);
72607                                     }
72608
72609                                     // fetch older versions of nodes that were deleted..
72610                                     lodash.each(visible.false, function(entity) {
72611                                         context.connection()
72612                                             .loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
72613                                     });
72614                                 }
72615
72616                                 if (err || lodash.isEmpty(missing)) {
72617                                     loading.close();
72618                                     context.redrawEnable(true);
72619                                     dispatch$$1.call('change');
72620                                 }
72621                             };
72622
72623                             context.connection().loadMultiple(missing, childNodesLoaded);
72624                         }
72625                     }
72626                 }
72627
72628                 stack$$1 = h.stack.map(function(d) {
72629                     var entities = {}, entity;
72630
72631                     if (d.modified) {
72632                         d.modified.forEach(function(key) {
72633                             entity = allEntities[key];
72634                             entities[entity.id] = entity;
72635                         });
72636                     }
72637
72638                     if (d.deleted) {
72639                         d.deleted.forEach(function(id) {
72640                             entities[id] = undefined;
72641                         });
72642                     }
72643
72644                     return {
72645                         graph: coreGraph$$1(stack$$1[0].graph).load(entities),
72646                         annotation: d.annotation,
72647                         imageryUsed: d.imageryUsed
72648                     };
72649                 });
72650
72651             } else { // original version
72652                 stack$$1 = h.stack.map(function(d) {
72653                     var entities = {};
72654
72655                     for (var i in d.entities) {
72656                         var entity = d.entities[i];
72657                         entities[i] = entity === 'undefined' ? undefined : osmEntity$$1(entity);
72658                     }
72659
72660                     d.graph = coreGraph$$1(stack$$1[0].graph).load(entities);
72661                     return d;
72662                 });
72663             }
72664
72665             if (loadComplete) {
72666                 dispatch$$1.call('change');
72667             }
72668
72669             return history;
72670         },
72671
72672
72673         save: function() {
72674             if (lock.locked()) context.storage(getKey('saved_history'), history.toJSON() || null);
72675             return history;
72676         },
72677
72678
72679         clearSaved: function() {
72680             context.debouncedSave.cancel();
72681             if (lock.locked()) context.storage(getKey('saved_history'), null);
72682             return history;
72683         },
72684
72685
72686         lock: function() {
72687             return lock.lock();
72688         },
72689
72690
72691         unlock: function() {
72692             lock.unlock();
72693         },
72694
72695
72696         // is iD not open in another window and it detects that
72697         // there's a history stored in localStorage that's recoverable?
72698         restorableChanges: function() {
72699             return lock.locked() && !!context.storage(getKey('saved_history'));
72700         },
72701
72702
72703         // load history from a version stored in localStorage
72704         restore: function() {
72705             if (!lock.locked()) return;
72706
72707             var json$$1 = context.storage(getKey('saved_history'));
72708             if (json$$1) history.fromJSON(json$$1, true);
72709         },
72710
72711
72712         _getKey: getKey
72713
72714     };
72715
72716
72717     history.reset();
72718
72719     return utilRebind(history, dispatch$$1, 'on');
72720 }
72721
72722 function presetCollection(collection) {
72723     var maxSearchResults = 50,
72724         maxSuggestionResults = 10;
72725
72726     var presets = {
72727
72728         collection: collection,
72729
72730
72731         item: function(id) {
72732             return lodash.find(this.collection, function(d) {
72733                 return d.id === id;
72734             });
72735         },
72736
72737
72738         matchGeometry: function(geometry) {
72739             return presetCollection(this.collection.filter(function(d) {
72740                 return d.matchGeometry(geometry);
72741             }));
72742         },
72743
72744
72745         search: function(value, geometry) {
72746             if (!value) return this;
72747
72748             function leading(a) {
72749                 var index = a.indexOf(value);
72750                 return index === 0 || a[index - 1] === ' ';
72751             }
72752
72753             function suggestionName(name) {
72754                 var nameArray = name.split(' - ');
72755                 if (nameArray.length > 1) {
72756                     name = nameArray.slice(0, nameArray.length - 1).join(' - ');
72757                 }
72758                 return name.toLowerCase();
72759             }
72760
72761
72762             value = value.toLowerCase();
72763
72764             var searchable = lodash.filter(this.collection, function(a) {
72765                     return a.searchable !== false && a.suggestion !== true;
72766                 }),
72767                 suggestions = lodash.filter(this.collection, function(a) {
72768                     return a.suggestion === true;
72769                 });
72770
72771
72772             // matches value to preset.name
72773             var leading_name = lodash.filter(searchable, function(a) {
72774                     return leading(a.name().toLowerCase());
72775                 }).sort(function(a, b) {
72776                     var i;
72777                     i = b.originalScore - a.originalScore;
72778                     if (i !== 0) return i;
72779
72780                     i = a.name().toLowerCase().indexOf(value) - b.name().toLowerCase().indexOf(value);
72781                     if (i !== 0) return i;
72782
72783                     return a.name().length - b.name().length;
72784                 });
72785
72786             // matches value to preset.terms values
72787             var leading_terms = lodash.filter(searchable, function(a) {
72788                     return lodash.some(a.terms() || [], leading);
72789                 });
72790
72791             // matches value to preset.tags values
72792             var leading_tag_values = lodash.filter(searchable, function(a) {
72793                     return lodash.some(lodash.without(lodash.values(a.tags || {}), '*'), leading);
72794                 });
72795
72796
72797             // finds close matches to value in preset.name
72798             var similar_name = searchable.map(function(a) {
72799                     return {
72800                         preset: a,
72801                         dist: utilEditDistance(value, a.name())
72802                     };
72803                 }).filter(function(a) {
72804                     return a.dist + Math.min(value.length - a.preset.name().length, 0) < 3;
72805                 }).sort(function(a, b) {
72806                     return a.dist - b.dist;
72807                 }).map(function(a) {
72808                     return a.preset;
72809                 });
72810
72811             // finds close matches to value in preset.terms
72812             var similar_terms = lodash.filter(searchable, function(a) {
72813                     return lodash.some(a.terms() || [], function(b) {
72814                         return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
72815                     });
72816                 });
72817
72818             var leading_suggestions = lodash.filter(suggestions, function(a) {
72819                     return leading(suggestionName(a.name()));
72820                 }).sort(function(a, b) {
72821                     a = suggestionName(a.name());
72822                     b = suggestionName(b.name());
72823                     var i = a.indexOf(value) - b.indexOf(value);
72824                     if (i === 0) return a.length - b.length;
72825                     else return i;
72826                 });
72827
72828             var similar_suggestions = suggestions.map(function(a) {
72829                     return {
72830                         preset: a,
72831                         dist: utilEditDistance(value, suggestionName(a.name()))
72832                     };
72833                 }).filter(function(a) {
72834                     return a.dist + Math.min(value.length - suggestionName(a.preset.name()).length, 0) < 1;
72835                 }).sort(function(a, b) {
72836                     return a.dist - b.dist;
72837                 }).map(function(a) {
72838                     return a.preset;
72839                 });
72840
72841             var other = presets.item(geometry);
72842
72843             var results = leading_name.concat(
72844                     leading_terms,
72845                     leading_tag_values,
72846                     leading_suggestions.slice(0, maxSuggestionResults + 5),
72847                     similar_name,
72848                     similar_terms,
72849                     similar_suggestions.slice(0, maxSuggestionResults)
72850                 ).slice(0, maxSearchResults - 1);
72851
72852             return presetCollection(lodash.uniq(results.concat(other)));
72853         }
72854     };
72855
72856
72857     return presets;
72858 }
72859
72860 function presetCategory(id, category, all) {
72861     category = lodash.clone(category);
72862
72863     category.id = id;
72864
72865
72866     category.members = presetCollection(category.members.map(function(id) {
72867         return all.item(id);
72868     }));
72869
72870
72871     category.matchGeometry = function(geometry) {
72872         return category.geometry.indexOf(geometry) >= 0;
72873     };
72874
72875
72876     category.matchScore = function() {
72877         return -1;
72878     };
72879
72880
72881     category.name = function() {
72882         return t('presets.categories.' + id + '.name', {'default': id});
72883     };
72884
72885
72886     category.terms = function() {
72887         return [];
72888     };
72889
72890
72891     return category;
72892 }
72893
72894 function presetField(id, field) {
72895     field = lodash.clone(field);
72896
72897     field.id = id;
72898
72899
72900     field.matchGeometry = function(geometry) {
72901         return !field.geometry || field.geometry === geometry;
72902     };
72903
72904
72905     field.t = function(scope, options) {
72906         return t('presets.fields.' + id + '.' + scope, options);
72907     };
72908
72909
72910     field.label = function() {
72911         return field.t('label', {'default': id});
72912     };
72913
72914
72915     var placeholder = field.placeholder;
72916     field.placeholder = function() {
72917         return field.t('placeholder', {'default': placeholder});
72918     };
72919
72920
72921     return field;
72922 }
72923
72924 function presetPreset(id, preset, fields) {
72925     preset = lodash.clone(preset);
72926
72927     preset.id = id;
72928     preset.fields = (preset.fields || []).map(getFields);
72929     preset.geometry = (preset.geometry || []);
72930
72931
72932     function getFields(f) {
72933         return fields[f];
72934     }
72935
72936
72937     preset.matchGeometry = function(geometry) {
72938         return preset.geometry.indexOf(geometry) >= 0;
72939     };
72940
72941
72942     preset.originalScore = preset.matchScore || 1;
72943
72944
72945     preset.matchScore = function(entity) {
72946         var tags = preset.tags,
72947             score = 0;
72948
72949         for (var t$$1 in tags) {
72950             if (entity.tags[t$$1] === tags[t$$1]) {
72951                 score += preset.originalScore;
72952             } else if (tags[t$$1] === '*' && t$$1 in entity.tags) {
72953                 score += preset.originalScore / 2;
72954             } else {
72955                 return -1;
72956             }
72957         }
72958
72959         return score;
72960     };
72961
72962
72963     preset.t = function(scope, options) {
72964         return t('presets.presets.' + id + '.' + scope, options);
72965     };
72966
72967
72968     var name = preset.name || '';
72969     preset.name = function() {
72970         if (preset.suggestion) {
72971             id = id.split('/');
72972             id = id[0] + '/' + id[1];
72973             return name + ' - ' + t('presets.presets.' + id + '.name');
72974         }
72975         return preset.t('name', {'default': name});
72976     };
72977
72978
72979     preset.terms = function() {
72980         return preset.t('terms', {'default': ''}).toLowerCase().trim().split(/\s*,+\s*/);
72981     };
72982
72983
72984     preset.isFallback = function() {
72985         var tagCount = Object.keys(preset.tags).length;
72986         return tagCount === 0 || (tagCount === 1 && preset.tags.hasOwnProperty('area'));
72987     };
72988
72989
72990     var reference = preset.reference || {};
72991     preset.reference = function(geometry) {
72992         var key = reference.key || Object.keys(lodash.omit(preset.tags, 'name'))[0],
72993             value = reference.value || preset.tags[key];
72994
72995         if (geometry === 'relation' && key === 'type') {
72996             if (value in preset.tags) {
72997                 key = value;
72998                 value = preset.tags[key];
72999             } else {
73000                 return { rtype: value };
73001             }
73002         }
73003
73004         if (value === '*') {
73005             return { key: key };
73006         } else {
73007             return { key: key, value: value };
73008         }
73009     };
73010
73011
73012     var removeTags = preset.removeTags || preset.tags;
73013     preset.removeTags = function(tags, geometry) {
73014         tags = lodash.omit(tags, lodash.keys(removeTags));
73015
73016         for (var f in preset.fields) {
73017             var field = preset.fields[f];
73018             if (field.matchGeometry(geometry) && field.default === tags[field.key]) {
73019                 delete tags[field.key];
73020             }
73021         }
73022
73023         delete tags.area;
73024         return tags;
73025     };
73026
73027
73028     var applyTags = preset.addTags || preset.tags;
73029     preset.applyTags = function(tags, geometry) {
73030         var k;
73031
73032         tags = lodash.clone(tags);
73033
73034         for (k in applyTags) {
73035             if (applyTags[k] === '*') {
73036                 tags[k] = 'yes';
73037             } else {
73038                 tags[k] = applyTags[k];
73039             }
73040         }
73041
73042         // Add area=yes if necessary.
73043         // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
73044         // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
73045         // 2. chosen preset doesn't have a key in areaKeys (`railway=station`)
73046         if (geometry === 'area') {
73047             var needsAreaTag = true;
73048             if (preset.geometry.indexOf('line') === -1) {
73049                 for (k in applyTags) {
73050                     if (k in areaKeys) {
73051                         needsAreaTag = false;
73052                         break;
73053                     }
73054                 }
73055             }
73056             if (needsAreaTag) {
73057                 tags.area = 'yes';
73058             }
73059         }
73060
73061         for (var f in preset.fields) {
73062             var field = preset.fields[f];
73063             if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field.default) {
73064                 tags[field.key] = field.default;
73065             }
73066         }
73067
73068         return tags;
73069     };
73070
73071
73072     return preset;
73073 }
73074
73075 function presetIndex() {
73076     // a presetCollection with methods for
73077     // loading new data and returning defaults
73078
73079     var all = presetCollection([]),
73080         defaults = { area: all, line: all, point: all, vertex: all, relation: all },
73081         fields = {},
73082         universal = [],
73083         recent = presetCollection([]);
73084
73085     // Index of presets by (geometry, tag key).
73086     var index = {
73087         point: {},
73088         vertex: {},
73089         line: {},
73090         area: {},
73091         relation: {}
73092     };
73093
73094     all.match = function(entity, resolver) {
73095         var geometry = entity.geometry(resolver);
73096
73097         // Treat entities on addr:interpolation lines as points, not vertices (#3241)
73098         if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
73099             geometry = 'point';
73100         }
73101
73102         var geometryMatches = index[geometry],
73103             best = -1,
73104             match;
73105
73106         for (var k in entity.tags) {
73107             var keyMatches = geometryMatches[k];
73108             if (!keyMatches) continue;
73109
73110             for (var i = 0; i < keyMatches.length; i++) {
73111                 var score = keyMatches[i].matchScore(entity);
73112                 if (score > best) {
73113                     best = score;
73114                     match = keyMatches[i];
73115                 }
73116             }
73117         }
73118
73119         return match || all.item(geometry);
73120     };
73121
73122
73123     // Because of the open nature of tagging, iD will never have a complete
73124     // list of tags used in OSM, so we want it to have logic like "assume
73125     // that a closed way with an amenity tag is an area, unless the amenity
73126     // is one of these specific types". This function computes a structure
73127     // that allows testing of such conditions, based on the presets designated
73128     // as as supporting (or not supporting) the area geometry.
73129     //
73130     // The returned object L is a whitelist/blacklist of tags. A closed way
73131     // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
73132     // (see `Way#isArea()`). In other words, the keys of L form the whitelist,
73133     // and the subkeys form the blacklist.
73134     all.areaKeys = function() {
73135         var areaKeys = {},
73136             ignore = ['barrier', 'highway', 'footway', 'railway', 'type'],  // probably a line..
73137             presets = lodash.reject(all.collection, 'suggestion');
73138
73139         // whitelist
73140         presets.forEach(function(d) {
73141             for (var key in d.tags) break;
73142             if (!key) return;
73143             if (ignore.indexOf(key) !== -1) return;
73144
73145             if (d.geometry.indexOf('area') !== -1) {    // probably an area..
73146                 areaKeys[key] = areaKeys[key] || {};
73147             }
73148         });
73149
73150         // blacklist
73151         presets.forEach(function(d) {
73152             for (var key in d.tags) break;
73153             if (!key) return;
73154             if (ignore.indexOf(key) !== -1) return;
73155
73156             var value = d.tags[key];
73157             if (key in areaKeys &&                      // probably an area...
73158                 d.geometry.indexOf('line') !== -1 &&    // but sometimes a line
73159                 value !== '*') {
73160                 areaKeys[key][value] = true;
73161             }
73162         });
73163
73164         return areaKeys;
73165     };
73166
73167
73168     all.init = function() {
73169         var d = data.presets;
73170
73171         all.collection = [];
73172         recent.collection = [];
73173         fields = {};
73174         universal = [];
73175         index = { point: {}, vertex: {}, line: {}, area: {}, relation: {} };
73176
73177         if (d.fields) {
73178             lodash.forEach(d.fields, function(d, id) {
73179                 fields[id] = presetField(id, d);
73180                 if (d.universal) universal.push(fields[id]);
73181             });
73182         }
73183
73184         if (d.presets) {
73185             lodash.forEach(d.presets, function(d, id) {
73186                 all.collection.push(presetPreset(id, d, fields));
73187             });
73188         }
73189
73190         if (d.categories) {
73191             lodash.forEach(d.categories, function(d, id) {
73192                 all.collection.push(presetCategory(id, d, all));
73193             });
73194         }
73195
73196         if (d.defaults) {
73197             var getItem = lodash.bind(all.item, all);
73198             defaults = {
73199                 area: presetCollection(d.defaults.area.map(getItem)),
73200                 line: presetCollection(d.defaults.line.map(getItem)),
73201                 point: presetCollection(d.defaults.point.map(getItem)),
73202                 vertex: presetCollection(d.defaults.vertex.map(getItem)),
73203                 relation: presetCollection(d.defaults.relation.map(getItem))
73204             };
73205         }
73206
73207         for (var i = 0; i < all.collection.length; i++) {
73208             var preset = all.collection[i],
73209                 geometry = preset.geometry;
73210
73211             for (var j = 0; j < geometry.length; j++) {
73212                 var g = index[geometry[j]];
73213                 for (var k in preset.tags) {
73214                     (g[k] = g[k] || []).push(preset);
73215                 }
73216             }
73217         }
73218
73219         return all;
73220     };
73221
73222     all.field = function(id) {
73223         return fields[id];
73224     };
73225
73226     all.universal = function() {
73227         return universal;
73228     };
73229
73230     all.defaults = function(geometry, n) {
73231         var rec = recent.matchGeometry(geometry).collection.slice(0, 4),
73232             def = lodash.uniq(rec.concat(defaults[geometry].collection)).slice(0, n - 1);
73233         return presetCollection(lodash.uniq(rec.concat(def).concat(all.item(geometry))));
73234     };
73235
73236     all.choose = function(preset) {
73237         if (!preset.isFallback()) {
73238             recent = presetCollection(lodash.uniq([preset].concat(recent.collection)));
73239         }
73240         return all;
73241     };
73242
73243     return all;
73244 }
73245
73246 var areaKeys = {};
73247
73248 function setAreaKeys(value) {
73249     areaKeys = value;
73250 }
73251
73252
73253 function coreContext() {
73254
73255     // create a special translation that contains the keys in place of the strings
73256     var tkeys = lodash.cloneDeep(en);
73257     var parents = [];
73258
73259     function traverser(v, k, obj) {
73260         parents.push(k);
73261         if (lodash.isObject(v)) {
73262             lodash.forOwn(v, traverser);
73263         } else if (lodash.isString(v)) {
73264             obj[k] = parents.join('.');
73265         }
73266         parents.pop();
73267     }
73268
73269     lodash.forOwn(tkeys, traverser);
73270     addTranslation('_tkeys_', tkeys);
73271
73272     addTranslation('en', en);
73273     setLocale('en');
73274
73275     var dispatch$$1 = dispatch('enter', 'exit', 'change'),
73276         context = {};
73277
73278     // https://github.com/openstreetmap/iD/issues/772
73279     // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
73280     var storage;
73281     try { storage = localStorage; } catch (e) {}  // eslint-disable-line no-empty
73282     storage = storage || (function() {
73283         var s = {};
73284         return {
73285             getItem: function(k) { return s[k]; },
73286             setItem: function(k, v) { s[k] = v; },
73287             removeItem: function(k) { delete s[k]; }
73288         };
73289     })();
73290
73291     context.storage = function(k, v) {
73292         try {
73293             if (arguments.length === 1) return storage.getItem(k);
73294             else if (v === null) storage.removeItem(k);
73295             else storage.setItem(k, v);
73296         } catch (e) {
73297             // localstorage quota exceeded
73298             /* eslint-disable no-console */
73299             if (typeof console !== 'undefined') console.error('localStorage quota exceeded');
73300             /* eslint-enable no-console */
73301         }
73302     };
73303
73304
73305     /* Straight accessors. Avoid using these if you can. */
73306     var ui, connection, history;
73307     context.ui = function() { return ui; };
73308     context.connection = function() { return connection; };
73309     context.history = function() { return history; };
73310
73311
73312     /* Connection */
73313     function entitiesLoaded(err, result) {
73314         if (!err) history.merge(result.data, result.extent);
73315     }
73316
73317     context.preauth = function(options) {
73318         connection.switch(options);
73319         return context;
73320     };
73321
73322     context.loadTiles = function(projection$$1, dimensions, callback) {
73323         function done(err, result) {
73324             entitiesLoaded(err, result);
73325             if (callback) callback(err, result);
73326         }
73327         connection.loadTiles(projection$$1, dimensions, done);
73328     };
73329
73330     context.loadEntity = function(id, callback) {
73331         function done(err, result) {
73332             entitiesLoaded(err, result);
73333             if (callback) callback(err, result);
73334         }
73335         connection.loadEntity(id, done);
73336     };
73337
73338     context.zoomToEntity = function(id, zoomTo) {
73339         if (zoomTo !== false) {
73340             this.loadEntity(id, function(err, result) {
73341                 if (err) return;
73342                 var entity = lodash.find(result.data, function(e) { return e.id === id; });
73343                 if (entity) { map.zoomTo(entity); }
73344             });
73345         }
73346
73347         map.on('drawn.zoomToEntity', function() {
73348             if (!context.hasEntity(id)) return;
73349             map.on('drawn.zoomToEntity', null);
73350             context.on('enter.zoomToEntity', null);
73351             context.enter(modeSelect(context, [id]));
73352         });
73353
73354         context.on('enter.zoomToEntity', function() {
73355             if (mode.id !== 'browse') {
73356                 map.on('drawn.zoomToEntity', null);
73357                 context.on('enter.zoomToEntity', null);
73358             }
73359         });
73360     };
73361
73362     var minEditableZoom = 16;
73363     context.minEditableZoom = function(_) {
73364         if (!arguments.length) return minEditableZoom;
73365         minEditableZoom = _;
73366         connection.tileZoom(_);
73367         return context;
73368     };
73369
73370
73371     /* History */
73372     var inIntro = false;
73373     context.inIntro = function(_) {
73374         if (!arguments.length) return inIntro;
73375         inIntro = _;
73376         return context;
73377     };
73378
73379     context.save = function() {
73380         // no history save, no message onbeforeunload
73381         if (inIntro || select('.modal').size()) return;
73382
73383         var canSave;
73384         if (mode && mode.id === 'save') {
73385             canSave = false;
73386         } else {
73387             canSave = context.selectedIDs().every(function(id) {
73388                 var entity = context.hasEntity(id);
73389                 return entity && !entity.isDegenerate();
73390             });
73391         }
73392
73393         if (canSave) {
73394             history.save();
73395         }
73396         if (history.hasChanges()) {
73397             return t('save.unsaved_changes');
73398         }
73399     };
73400
73401
73402     /* Graph */
73403     context.hasEntity = function(id) {
73404         return history.graph().hasEntity(id);
73405     };
73406     context.entity = function(id) {
73407         return history.graph().entity(id);
73408     };
73409     context.childNodes = function(way) {
73410         return history.graph().childNodes(way);
73411     };
73412     context.geometry = function(id) {
73413         return context.entity(id).geometry(history.graph());
73414     };
73415
73416
73417     /* Modes */
73418     var mode;
73419     context.mode = function() {
73420         return mode;
73421     };
73422     context.enter = function(newMode) {
73423         if (mode) {
73424             mode.exit();
73425             dispatch$$1.call('exit', this, mode);
73426         }
73427
73428         mode = newMode;
73429         mode.enter();
73430         dispatch$$1.call('enter', this, mode);
73431     };
73432
73433     context.selectedIDs = function() {
73434         if (mode && mode.selectedIDs) {
73435             return mode.selectedIDs();
73436         } else {
73437             return [];
73438         }
73439     };
73440
73441
73442     /* Behaviors */
73443     context.install = function(behavior) {
73444         context.surface().call(behavior);
73445     };
73446     context.uninstall = function(behavior) {
73447         context.surface().call(behavior.off);
73448     };
73449
73450
73451     /* Copy/Paste */
73452     var copyIDs = [], copyGraph;
73453     context.copyGraph = function() { return copyGraph; };
73454     context.copyIDs = function(_) {
73455         if (!arguments.length) return copyIDs;
73456         copyIDs = _;
73457         copyGraph = history.graph();
73458         return context;
73459     };
73460
73461
73462     /* Background */
73463     var background;
73464     context.background = function() { return background; };
73465
73466
73467     /* Features */
73468     var features;
73469     context.features = function() { return features; };
73470     context.hasHiddenConnections = function(id) {
73471         var graph = history.graph(),
73472             entity = graph.entity(id);
73473         return features.hasHiddenConnections(entity, graph);
73474     };
73475
73476
73477     /* Presets */
73478     var presets;
73479     context.presets = function() { return presets; };
73480
73481
73482     /* Map */
73483     var map;
73484     context.map = function() { return map; };
73485     context.layers = function() { return map.layers; };
73486     context.surface = function() { return map.surface; };
73487     context.editable = function() { return map.editable(); };
73488     context.surfaceRect = function() {
73489         return map.surface.node().getBoundingClientRect();
73490     };
73491
73492
73493     /* Debug */
73494     var debugFlags = {
73495         tile: false,
73496         collision: false,
73497         imagery: false,
73498         imperial: false,
73499         driveLeft: false
73500     };
73501     context.debugFlags = function() {
73502         return debugFlags;
73503     };
73504     context.setDebug = function(flag, val) {
73505         if (arguments.length === 1) val = true;
73506         debugFlags[flag] = val;
73507         dispatch$$1.call('change');
73508         return context;
73509     };
73510     context.getDebug = function(flag) {
73511         return flag && debugFlags[flag];
73512     };
73513
73514
73515     /* Container */
73516     var container = select(document.body);
73517     context.container = function(_) {
73518         if (!arguments.length) return container;
73519         container = _;
73520         container.classed('id-container', true);
73521         return context;
73522     };
73523     var embed;
73524     context.embed = function(_) {
73525         if (!arguments.length) return embed;
73526         embed = _;
73527         return context;
73528     };
73529
73530
73531     /* Assets */
73532     var assetPath = '';
73533     context.assetPath = function(_) {
73534         if (!arguments.length) return assetPath;
73535         assetPath = _;
73536         return context;
73537     };
73538
73539     var assetMap = {};
73540     context.assetMap = function(_) {
73541         if (!arguments.length) return assetMap;
73542         assetMap = _;
73543         return context;
73544     };
73545
73546     context.asset = function(_) {
73547         var filename = assetPath + _;
73548         return assetMap[filename] || filename;
73549     };
73550
73551     context.imagePath = function(_) {
73552         return context.asset('img/' + _);
73553     };
73554
73555
73556     /* locales */
73557     // `locale` variable contains a "requested locale".
73558     // It won't become the `currentLocale` until after loadLocale() is called.
73559     var locale, localePath;
73560
73561     context.locale = function(loc, path$$1) {
73562         if (!arguments.length) return currentLocale;
73563         locale = loc;
73564         localePath = path$$1;
73565         return context;
73566     };
73567
73568     context.loadLocale = function(callback) {
73569         if (locale && locale !== 'en' && dataLocales.hasOwnProperty(locale)) {
73570             localePath = localePath || context.asset('locales/' + locale + '.json');
73571             json(localePath, function(err, result) {
73572                 if (!err) {
73573                     addTranslation(locale, result[locale]);
73574                     setLocale(locale);
73575                     utilDetect(true);
73576                 }
73577                 if (callback) {
73578                     callback(err);
73579                 }
73580             });
73581         } else {
73582             if (locale) {
73583                 setLocale(locale);
73584                 utilDetect(true);
73585             }
73586             if (callback) {
73587                 callback();
73588             }
73589         }
73590     };
73591
73592
73593     /* reset (aka flush) */
73594     context.reset = context.flush = function() {
73595         context.debouncedSave.cancel();
73596         lodash.each(services, function(service) {
73597             if (service && typeof service.reset === 'function') {
73598                 service.reset(context);
73599             }
73600         });
73601         features.reset();
73602         history.reset();
73603         return context;
73604     };
73605
73606
73607     /* Init */
73608     context.version = '2.2.2';
73609
73610     context.projection = geoRawMercator();
73611     context.curtainProjection = geoRawMercator();
73612
73613     locale = utilDetect().locale;
73614     if (locale && !dataLocales.hasOwnProperty(locale)) {
73615         locale = locale.split('-')[0];
73616     }
73617
73618     history = coreHistory(context);
73619     context.graph = history.graph;
73620     context.changes = history.changes;
73621     context.intersects = history.intersects;
73622
73623     // Debounce save, since it's a synchronous localStorage write,
73624     // and history changes can happen frequently (e.g. when dragging).
73625     context.debouncedSave = lodash.debounce(context.save, 350);
73626     function withDebouncedSave(fn) {
73627         return function() {
73628             var result = fn.apply(history, arguments);
73629             context.debouncedSave();
73630             return result;
73631         };
73632     }
73633
73634     context.perform = withDebouncedSave(history.perform);
73635     context.replace = withDebouncedSave(history.replace);
73636     context.pop = withDebouncedSave(history.pop);
73637     context.overwrite = withDebouncedSave(history.overwrite);
73638     context.undo = withDebouncedSave(history.undo);
73639     context.redo = withDebouncedSave(history.redo);
73640
73641     ui = uiInit(context);
73642
73643     connection = services.osm;
73644     background = rendererBackground(context);
73645     features = rendererFeatures(context);
73646     presets = presetIndex();
73647
73648     map = rendererMap(context);
73649     context.mouse = map.mouse;
73650     context.extent = map.extent;
73651     context.pan = map.pan;
73652     context.zoomIn = map.zoomIn;
73653     context.zoomOut = map.zoomOut;
73654     context.zoomInFurther = map.zoomInFurther;
73655     context.zoomOutFurther = map.zoomOutFurther;
73656     context.redrawEnable = map.redrawEnable;
73657
73658     lodash.each(services, function(service) {
73659         if (service && typeof service.init === 'function') {
73660             service.init(context);
73661         }
73662     });
73663
73664     background.init();
73665     presets.init();
73666     areaKeys = presets.areaKeys();
73667
73668
73669     return utilRebind(context, dispatch$$1, 'on');
73670 }
73671
73672 function osmWay() {
73673     if (!(this instanceof osmWay)) {
73674         return (new osmWay()).initialize(arguments);
73675     } else if (arguments.length) {
73676         this.initialize(arguments);
73677     }
73678 }
73679
73680
73681 osmEntity$$1.way = osmWay;
73682
73683 osmWay.prototype = Object.create(osmEntity$$1.prototype);
73684
73685
73686 lodash.extend(osmWay.prototype, {
73687     type: 'way',
73688     nodes: [],
73689
73690
73691     copy: function(resolver, copies) {
73692         if (copies[this.id])
73693             return copies[this.id];
73694
73695         var copy = osmEntity$$1.prototype.copy.call(this, resolver, copies);
73696
73697         var nodes = this.nodes.map(function(id) {
73698             return resolver.entity(id).copy(resolver, copies).id;
73699         });
73700
73701         copy = copy.update({ nodes: nodes });
73702         copies[this.id] = copy;
73703
73704         return copy;
73705     },
73706
73707
73708     extent: function(resolver) {
73709         return resolver.transient(this, 'extent', function() {
73710             var extent$$1 = geoExtent$$1();
73711             for (var i = 0; i < this.nodes.length; i++) {
73712                 var node = resolver.hasEntity(this.nodes[i]);
73713                 if (node) {
73714                     extent$$1._extend(node.extent());
73715                 }
73716             }
73717             return extent$$1;
73718         });
73719     },
73720
73721
73722     first: function() {
73723         return this.nodes[0];
73724     },
73725
73726
73727     last: function() {
73728         return this.nodes[this.nodes.length - 1];
73729     },
73730
73731
73732     contains: function(node) {
73733         return this.nodes.indexOf(node) >= 0;
73734     },
73735
73736
73737     affix: function(node) {
73738         if (this.nodes[0] === node) return 'prefix';
73739         if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
73740     },
73741
73742
73743     layer: function() {
73744         // explicit layer tag, clamp between -10, 10..
73745         if (isFinite(this.tags.layer)) {
73746             return Math.max(-10, Math.min(+(this.tags.layer), 10));
73747         }
73748
73749         // implied layer tag..
73750         if (this.tags.location === 'overground') return 1;
73751         if (this.tags.location === 'underground') return -1;
73752         if (this.tags.location === 'underwater') return -10;
73753
73754         if (this.tags.power === 'line') return 10;
73755         if (this.tags.power === 'minor_line') return 10;
73756         if (this.tags.aerialway) return 10;
73757         if (this.tags.bridge) return 1;
73758         if (this.tags.cutting) return -1;
73759         if (this.tags.tunnel) return -1;
73760         if (this.tags.waterway) return -1;
73761         if (this.tags.man_made === 'pipeline') return -10;
73762         if (this.tags.boundary) return -10;
73763         return 0;
73764     },
73765
73766
73767     isOneWay: function() {
73768         // explicit oneway tag..
73769         if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; }
73770         if (['no', '0'].indexOf(this.tags.oneway) !== -1) { return false; }
73771
73772         // implied oneway tag..
73773         for (var key in this.tags) {
73774             if (key in osmOneWayTags && (this.tags[key] in osmOneWayTags[key]))
73775                 return true;
73776         }
73777         return false;
73778     },
73779
73780
73781     lanes: function() {
73782         return osmLanes(this);
73783     },
73784
73785
73786     isClosed: function() {
73787         return this.nodes.length > 1 && this.first() === this.last();
73788     },
73789
73790
73791     isConvex: function(resolver) {
73792         if (!this.isClosed() || this.isDegenerate()) return null;
73793
73794         var nodes = lodash.uniq(resolver.childNodes(this)),
73795             coords = lodash.map(nodes, 'loc'),
73796             curr = 0, prev = 0;
73797
73798         for (var i = 0; i < coords.length; i++) {
73799             var o = coords[(i+1) % coords.length],
73800                 a = coords[i],
73801                 b = coords[(i+2) % coords.length],
73802                 res = geoCross(o, a, b);
73803
73804             curr = (res > 0) ? 1 : (res < 0) ? -1 : 0;
73805             if (curr === 0) {
73806                 continue;
73807             } else if (prev && curr !== prev) {
73808                 return false;
73809             }
73810             prev = curr;
73811         }
73812         return true;
73813     },
73814
73815
73816     isArea: function() {
73817         if (this.tags.area === 'yes')
73818             return true;
73819         if (!this.isClosed() || this.tags.area === 'no')
73820             return false;
73821         for (var key in this.tags) {
73822             if (key in areaKeys && !(this.tags[key] in areaKeys[key])) {
73823                 return true;
73824             }
73825         }
73826         return false;
73827     },
73828
73829
73830     isDegenerate: function() {
73831         return lodash.uniq(this.nodes).length < (this.isArea() ? 3 : 2);
73832     },
73833
73834
73835     areAdjacent: function(n1, n2) {
73836         for (var i = 0; i < this.nodes.length; i++) {
73837             if (this.nodes[i] === n1) {
73838                 if (this.nodes[i - 1] === n2) return true;
73839                 if (this.nodes[i + 1] === n2) return true;
73840             }
73841         }
73842         return false;
73843     },
73844
73845
73846     geometry: function(graph) {
73847         return graph.transient(this, 'geometry', function() {
73848             return this.isArea() ? 'area' : 'line';
73849         });
73850     },
73851
73852
73853     // If this way is not closed, append the beginning node to the end of the nodelist to close it.
73854     close: function() {
73855         if (this.isClosed() || !this.nodes.length) return this;
73856
73857         var nodes = this.nodes.slice();
73858         nodes = nodes.filter(noRepeatNodes);
73859         nodes.push(nodes[0]);
73860         return this.update({ nodes: nodes });
73861     },
73862
73863
73864     // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
73865     unclose: function() {
73866         if (!this.isClosed()) return this;
73867
73868         var nodes = this.nodes.slice(),
73869             connector = this.first(),
73870             i = nodes.length - 1;
73871
73872         // remove trailing connectors..
73873         while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
73874             nodes.splice(i, 1);
73875             i = nodes.length - 1;
73876         }
73877
73878         nodes = nodes.filter(noRepeatNodes);
73879         return this.update({ nodes: nodes });
73880     },
73881
73882
73883     // Adds a node (id) in front of the node which is currently at position index.
73884     // If index is undefined, the node will be added to the end of the way for linear ways,
73885     //   or just before the final connecting node for circular ways.
73886     // Consecutive duplicates are eliminated including existing ones.
73887     // Circularity is always preserved when adding a node.
73888     addNode: function(id, index) {
73889         var nodes = this.nodes.slice(),
73890             isClosed = this.isClosed(),
73891             max$$1 = isClosed ? nodes.length - 1 : nodes.length;
73892
73893         if (index === undefined) {
73894             index = max$$1;
73895         }
73896
73897         if (index < 0 || index > max$$1) {
73898             throw new RangeError('index ' + index + ' out of range 0..' + max$$1);
73899         }
73900
73901         // If this is a closed way, remove all connector nodes except the first one
73902         // (there may be duplicates) and adjust index if necessary..
73903         if (isClosed) {
73904             var connector = this.first();
73905
73906             // leading connectors..
73907             var i = 1;
73908             while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
73909                 nodes.splice(i, 1);
73910                 if (index > i) index--;
73911             }
73912
73913             // trailing connectors..
73914             i = nodes.length - 1;
73915             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
73916                 nodes.splice(i, 1);
73917                 if (index > i) index--;
73918                 i = nodes.length - 1;
73919             }
73920         }
73921
73922         nodes.splice(index, 0, id);
73923         nodes = nodes.filter(noRepeatNodes);
73924
73925         // If the way was closed before, append a connector node to keep it closed..
73926         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
73927             nodes.push(nodes[0]);
73928         }
73929
73930         return this.update({ nodes: nodes });
73931     },
73932
73933
73934     // Replaces the node which is currently at position index with the given node (id).
73935     // Consecutive duplicates are eliminated including existing ones.
73936     // Circularity is preserved when updating a node.
73937     updateNode: function(id, index) {
73938         var nodes = this.nodes.slice(),
73939             isClosed = this.isClosed(),
73940             max$$1 = nodes.length - 1;
73941
73942         if (index === undefined || index < 0 || index > max$$1) {
73943             throw new RangeError('index ' + index + ' out of range 0..' + max$$1);
73944         }
73945
73946         // If this is a closed way, remove all connector nodes except the first one
73947         // (there may be duplicates) and adjust index if necessary..
73948         if (isClosed) {
73949             var connector = this.first();
73950
73951             // leading connectors..
73952             var i = 1;
73953             while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
73954                 nodes.splice(i, 1);
73955                 if (index > i) index--;
73956             }
73957
73958             // trailing connectors..
73959             i = nodes.length - 1;
73960             while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
73961                 nodes.splice(i, 1);
73962                 if (index === i) index = 0;  // update leading connector instead
73963                 i = nodes.length - 1;
73964             }
73965         }
73966
73967         nodes.splice(index, 1, id);
73968         nodes = nodes.filter(noRepeatNodes);
73969
73970         // If the way was closed before, append a connector node to keep it closed..
73971         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
73972             nodes.push(nodes[0]);
73973         }
73974
73975         return this.update({nodes: nodes});
73976     },
73977
73978
73979     // Replaces each occurrence of node id needle with replacement.
73980     // Consecutive duplicates are eliminated including existing ones.
73981     // Circularity is preserved.
73982     replaceNode: function(needle, replacement) {
73983         var nodes = this.nodes.slice(),
73984             isClosed = this.isClosed();
73985
73986         for (var i = 0; i < nodes.length; i++) {
73987             if (nodes[i] === needle) {
73988                 nodes[i] = replacement;
73989             }
73990         }
73991
73992         nodes = nodes.filter(noRepeatNodes);
73993
73994         // If the way was closed before, append a connector node to keep it closed..
73995         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
73996             nodes.push(nodes[0]);
73997         }
73998
73999         return this.update({nodes: nodes});
74000     },
74001
74002
74003     // Removes each occurrence of node id needle with replacement.
74004     // Consecutive duplicates are eliminated including existing ones.
74005     // Circularity is preserved.
74006     removeNode: function(id) {
74007         var nodes = this.nodes.slice(),
74008             isClosed = this.isClosed();
74009
74010         nodes = nodes
74011             .filter(function(node) { return node !== id; })
74012             .filter(noRepeatNodes);
74013
74014         // If the way was closed before, append a connector node to keep it closed..
74015         if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
74016             nodes.push(nodes[0]);
74017         }
74018
74019         return this.update({nodes: nodes});
74020     },
74021
74022
74023     asJXON: function(changeset_id) {
74024         var r = {
74025             way: {
74026                 '@id': this.osmId(),
74027                 '@version': this.version || 0,
74028                 nd: lodash.map(this.nodes, function(id) {
74029                     return { keyAttributes: { ref: osmEntity$$1.id.toOSM(id) } };
74030                 }),
74031                 tag: lodash.map(this.tags, function(v, k) {
74032                     return { keyAttributes: { k: k, v: v } };
74033                 })
74034             }
74035         };
74036         if (changeset_id) {
74037             r.way['@changeset'] = changeset_id;
74038         }
74039         return r;
74040     },
74041
74042
74043     asGeoJSON: function(resolver) {
74044         return resolver.transient(this, 'GeoJSON', function() {
74045             var coordinates = lodash.map(resolver.childNodes(this), 'loc');
74046             if (this.isArea() && this.isClosed()) {
74047                 return {
74048                     type: 'Polygon',
74049                     coordinates: [coordinates]
74050                 };
74051             } else {
74052                 return {
74053                     type: 'LineString',
74054                     coordinates: coordinates
74055                 };
74056             }
74057         });
74058     },
74059
74060
74061     area: function(resolver) {
74062         return resolver.transient(this, 'area', function() {
74063             var nodes = resolver.childNodes(this);
74064
74065             var json$$1 = {
74066                 type: 'Polygon',
74067                 coordinates: [lodash.map(nodes, 'loc')]
74068             };
74069
74070             if (!this.isClosed() && nodes.length) {
74071                 json$$1.coordinates[0].push(nodes[0].loc);
74072             }
74073
74074             var area$$1 = area(json$$1);
74075
74076             // Heuristic for detecting counterclockwise winding order. Assumes
74077             // that OpenStreetMap polygons are not hemisphere-spanning.
74078             if (area$$1 > 2 * Math.PI) {
74079                 json$$1.coordinates[0] = json$$1.coordinates[0].reverse();
74080                 area$$1 = area(json$$1);
74081             }
74082
74083             return isNaN(area$$1) ? 0 : area$$1;
74084         });
74085     }
74086 });
74087
74088
74089 // Filter function to eliminate consecutive duplicates.
74090 function noRepeatNodes(node, i, arr) {
74091     return i === 0 || node !== arr[i - 1];
74092 }
74093
74094 function osmTurn(turn) {
74095     if (!(this instanceof osmTurn))
74096         return new osmTurn(turn);
74097     lodash.extend(this, turn);
74098 }
74099
74100
74101 function osmIntersection(graph, vertexId) {
74102     var vertex = graph.entity(vertexId),
74103         parentWays = graph.parentWays(vertex),
74104         coincident = [],
74105         highways = {};
74106
74107     function addHighway(way, adjacentNodeId) {
74108         if (highways[adjacentNodeId]) {
74109             coincident.push(adjacentNodeId);
74110         } else {
74111             highways[adjacentNodeId] = way;
74112         }
74113     }
74114
74115     // Pre-split ways that would need to be split in
74116     // order to add a restriction. The real split will
74117     // happen when the restriction is added.
74118     parentWays.forEach(function(way) {
74119         if (!way.tags.highway || way.isArea() || way.isDegenerate())
74120             return;
74121
74122         var isFirst = (vertexId === way.first()),
74123             isLast = (vertexId === way.last()),
74124             isAffix = (isFirst || isLast),
74125             isClosingNode = (isFirst && isLast);
74126
74127         if (isAffix && !isClosingNode) {
74128             var index = (isFirst ? 1 : way.nodes.length - 2);
74129             addHighway(way, way.nodes[index]);
74130
74131         } else {
74132             var splitIndex, wayA, wayB, indexA, indexB;
74133             if (isClosingNode) {
74134                 splitIndex = Math.ceil(way.nodes.length / 2);  // split at midpoint
74135                 wayA = osmWay({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex)});
74136                 wayB = osmWay({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
74137                 indexA = 1;
74138                 indexB = way.nodes.length - 2;
74139             } else {
74140                 splitIndex = lodash.indexOf(way.nodes, vertex.id, 1);  // split at vertexid
74141                 wayA = osmWay({id: way.id + '-a', tags: way.tags, nodes: way.nodes.slice(0, splitIndex + 1)});
74142                 wayB = osmWay({id: way.id + '-b', tags: way.tags, nodes: way.nodes.slice(splitIndex)});
74143                 indexA = splitIndex - 1;
74144                 indexB = splitIndex + 1;
74145             }
74146             graph = graph.replace(wayA).replace(wayB);
74147             addHighway(wayA, way.nodes[indexA]);
74148             addHighway(wayB, way.nodes[indexB]);
74149         }
74150     });
74151
74152     // remove any ways from this intersection that are coincident
74153     // (i.e. any adjacent node used by more than one intersecting way)
74154     coincident.forEach(function (n) {
74155         delete highways[n];
74156     });
74157
74158
74159     var intersection = {
74160         highways: highways,
74161         ways: lodash.values(highways),
74162         graph: graph
74163     };
74164
74165
74166     intersection.adjacentNodeId = function(fromWayId) {
74167         return lodash.find(lodash.keys(highways), function(k) {
74168             return highways[k].id === fromWayId;
74169         });
74170     };
74171
74172
74173     intersection.turns = function(fromNodeId) {
74174         var start = highways[fromNodeId];
74175         if (!start)
74176             return [];
74177
74178         if (start.first() === vertex.id && start.tags.oneway === 'yes')
74179             return [];
74180         if (start.last() === vertex.id && start.tags.oneway === '-1')
74181             return [];
74182
74183         function withRestriction(turn) {
74184             graph.parentRelations(graph.entity(turn.from.way)).forEach(function(relation) {
74185                 if (relation.tags.type !== 'restriction')
74186                     return;
74187
74188                 var f = relation.memberByRole('from'),
74189                     t = relation.memberByRole('to'),
74190                     v = relation.memberByRole('via');
74191
74192                 if (f && f.id === turn.from.way &&
74193                     v && v.id === turn.via.node &&
74194                     t && t.id === turn.to.way) {
74195                     turn.restriction = relation.id;
74196                 } else if (/^only_/.test(relation.tags.restriction) &&
74197                     f && f.id === turn.from.way &&
74198                     v && v.id === turn.via.node &&
74199                     t && t.id !== turn.to.way) {
74200                     turn.restriction = relation.id;
74201                     turn.indirect_restriction = true;
74202                 }
74203             });
74204
74205             return osmTurn(turn);
74206         }
74207
74208
74209         var from = {
74210                 node: fromNodeId,
74211                 way: start.id.split(/-(a|b)/)[0]
74212             },
74213             via = { node: vertex.id },
74214             turns = [];
74215
74216         lodash.each(highways, function(end, adjacentNodeId) {
74217             if (end === start)
74218                 return;
74219
74220             // backward
74221             if (end.first() !== vertex.id && end.tags.oneway !== 'yes') {
74222                 turns.push(withRestriction({
74223                     from: from,
74224                     via: via,
74225                     to: {
74226                         node: adjacentNodeId,
74227                         way: end.id.split(/-(a|b)/)[0]
74228                     }
74229                 }));
74230             }
74231
74232             // forward
74233             if (end.last() !== vertex.id && end.tags.oneway !== '-1') {
74234                 turns.push(withRestriction({
74235                     from: from,
74236                     via: via,
74237                     to: {
74238                         node: adjacentNodeId,
74239                         way: end.id.split(/-(a|b)/)[0]
74240                     }
74241                 }));
74242             }
74243
74244         });
74245
74246         // U-turn
74247         if (start.tags.oneway !== 'yes' && start.tags.oneway !== '-1') {
74248             turns.push(withRestriction({
74249                 from: from,
74250                 via: via,
74251                 to: from,
74252                 u: true
74253             }));
74254         }
74255
74256         return turns;
74257     };
74258
74259     return intersection;
74260 }
74261
74262
74263 function osmInferRestriction(graph, from, via, to, projection) {
74264     var fromWay = graph.entity(from.way),
74265         fromNode = graph.entity(from.node),
74266         toWay = graph.entity(to.way),
74267         toNode = graph.entity(to.node),
74268         viaNode = graph.entity(via.node),
74269         fromOneWay = (fromWay.tags.oneway === 'yes' && fromWay.last() === via.node) ||
74270             (fromWay.tags.oneway === '-1' && fromWay.first() === via.node),
74271         toOneWay = (toWay.tags.oneway === 'yes' && toWay.first() === via.node) ||
74272             (toWay.tags.oneway === '-1' && toWay.last() === via.node),
74273         angle = geoAngle(viaNode, fromNode, projection) -
74274                 geoAngle(viaNode, toNode, projection);
74275
74276     angle = angle * 180 / Math.PI;
74277
74278     while (angle < 0)
74279         angle += 360;
74280
74281     if (fromNode === toNode)
74282         return 'no_u_turn';
74283     if ((angle < 23 || angle > 336) && fromOneWay && toOneWay)
74284         return 'no_u_turn';
74285     if (angle < 158)
74286         return 'no_right_turn';
74287     if (angle > 202)
74288         return 'no_left_turn';
74289
74290     return 'no_straight_on';
74291 }
74292
74293 function actionAddMember(relationId, member, memberIndex) {
74294     return function(graph) {
74295         var relation = graph.entity(relationId);
74296
74297         if (isNaN(memberIndex) && member.type === 'way') {
74298             var members = relation.indexedMembers();
74299             members.push(member);
74300
74301             var joined = osmJoinWays(members, graph);
74302             for (var i = 0; i < joined.length; i++) {
74303                 var segment = joined[i];
74304                 for (var j = 0; j < segment.length && segment.length >= 2; j++) {
74305                     if (segment[j] !== member)
74306                         continue;
74307
74308                     if (j === 0) {
74309                         memberIndex = segment[j + 1].index;
74310                     } else if (j === segment.length - 1) {
74311                         memberIndex = segment[j - 1].index + 1;
74312                     } else {
74313                         memberIndex = Math.min(segment[j - 1].index + 1, segment[j + 1].index + 1);
74314                     }
74315                 }
74316             }
74317         }
74318
74319         return graph.replace(relation.addMember(member, memberIndex));
74320     };
74321 }
74322
74323 function actionAddMidpoint(midpoint, node) {
74324     return function(graph) {
74325         graph = graph.replace(node.move(midpoint.loc));
74326
74327         var parents = lodash.intersection(
74328             graph.parentWays(graph.entity(midpoint.edge[0])),
74329             graph.parentWays(graph.entity(midpoint.edge[1])));
74330
74331         parents.forEach(function(way) {
74332             for (var i = 0; i < way.nodes.length - 1; i++) {
74333                 if (geoEdgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
74334                     graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1));
74335
74336                     // Add only one midpoint on doubled-back segments,
74337                     // turning them into self-intersections.
74338                     return;
74339                 }
74340             }
74341         });
74342
74343         return graph;
74344     };
74345 }
74346
74347 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
74348 function actionAddVertex(wayId, nodeId, index) {
74349     return function(graph) {
74350         return graph.replace(graph.entity(wayId).addNode(nodeId, index));
74351     };
74352 }
74353
74354 function actionChangeMember(relationId, member, memberIndex) {
74355     return function(graph) {
74356         return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
74357     };
74358 }
74359
74360 function actionChangePreset(entityId, oldPreset, newPreset) {
74361     return function(graph) {
74362         var entity = graph.entity(entityId),
74363             geometry = entity.geometry(graph),
74364             tags = entity.tags;
74365
74366         if (oldPreset) tags = oldPreset.removeTags(tags, geometry);
74367         if (newPreset) tags = newPreset.applyTags(tags, geometry);
74368
74369         return graph.replace(entity.update({tags: tags}));
74370     };
74371 }
74372
74373 function actionChangeTags(entityId, tags) {
74374     return function(graph) {
74375         var entity = graph.entity(entityId);
74376         return graph.replace(entity.update({tags: tags}));
74377     };
74378 }
74379
74380 function actionCircularize(wayId, projection$$1, maxAngle) {
74381     maxAngle = (maxAngle || 20) * Math.PI / 180;
74382
74383
74384     var action = function(graph, t) {
74385         if (t === null || !isFinite(t)) t = 1;
74386         t = Math.min(Math.max(+t, 0), 1);
74387
74388         var way = graph.entity(wayId),
74389             origNodes = {};
74390
74391         graph.childNodes(way).forEach(function(node) {
74392             if (!origNodes[node.id]) origNodes[node.id] = node;
74393         });
74394
74395         if (!way.isConvex(graph)) {
74396             graph = action.makeConvex(graph);
74397         }
74398
74399         var nodes = lodash.uniq(graph.childNodes(way)),
74400             keyNodes = nodes.filter(function(n) { return graph.parentWays(n).length !== 1; }),
74401             points = nodes.map(function(n) { return projection$$1(n.loc); }),
74402             keyPoints = keyNodes.map(function(n) { return projection$$1(n.loc); }),
74403             centroid = (points.length === 2) ? geoInterp(points[0], points[1], 0.5) : d3polygonCentroid(points),
74404             radius = median(points, function(p) { return geoEuclideanDistance(centroid, p); }),
74405             sign = d3polygonArea(points) > 0 ? 1 : -1,
74406             ids;
74407
74408         // we need atleast two key nodes for the algorithm to work
74409         if (!keyNodes.length) {
74410             keyNodes = [nodes[0]];
74411             keyPoints = [points[0]];
74412         }
74413
74414         if (keyNodes.length === 1) {
74415             var index = nodes.indexOf(keyNodes[0]),
74416                 oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
74417
74418             keyNodes.push(nodes[oppositeIndex]);
74419             keyPoints.push(points[oppositeIndex]);
74420         }
74421
74422         // key points and nodes are those connected to the ways,
74423         // they are projected onto the circle, inbetween nodes are moved
74424         // to constant intervals between key nodes, extra inbetween nodes are
74425         // added if necessary.
74426         for (var i = 0; i < keyPoints.length; i++) {
74427             var nextKeyNodeIndex = (i + 1) % keyNodes.length,
74428                 startNode = keyNodes[i],
74429                 endNode = keyNodes[nextKeyNodeIndex],
74430                 startNodeIndex = nodes.indexOf(startNode),
74431                 endNodeIndex = nodes.indexOf(endNode),
74432                 numberNewPoints = -1,
74433                 indexRange = endNodeIndex - startNodeIndex,
74434                 nearNodes = {},
74435                 inBetweenNodes = [],
74436                 startAngle, endAngle, totalAngle, eachAngle,
74437                 angle, loc, node, origNode, j;
74438
74439             if (indexRange < 0) {
74440                 indexRange += nodes.length;
74441             }
74442
74443             // position this key node
74444             var distance$$1 = geoEuclideanDistance(centroid, keyPoints[i]);
74445             if (distance$$1 === 0) { distance$$1 = 1e-4; }
74446             keyPoints[i] = [
74447                 centroid[0] + (keyPoints[i][0] - centroid[0]) / distance$$1 * radius,
74448                 centroid[1] + (keyPoints[i][1] - centroid[1]) / distance$$1 * radius
74449             ];
74450             loc = projection$$1.invert(keyPoints[i]);
74451             node = keyNodes[i];
74452             origNode = origNodes[node.id];
74453             node = node.move(geoInterp(origNode.loc, loc, t));
74454             graph = graph.replace(node);
74455
74456             // figure out the between delta angle we want to match to
74457             startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
74458             endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
74459             totalAngle = endAngle - startAngle;
74460
74461             // detects looping around -pi/pi
74462             if (totalAngle * sign > 0) {
74463                 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
74464             }
74465
74466             do {
74467                 numberNewPoints++;
74468                 eachAngle = totalAngle / (indexRange + numberNewPoints);
74469             } while (Math.abs(eachAngle) > maxAngle);
74470
74471
74472             // move existing nodes
74473             for (j = 1; j < indexRange; j++) {
74474                 angle = startAngle + j * eachAngle;
74475                 loc = projection$$1.invert([
74476                     centroid[0] + Math.cos(angle) * radius,
74477                     centroid[1] + Math.sin(angle) * radius
74478                 ]);
74479
74480                 node = nodes[(j + startNodeIndex) % nodes.length];
74481                 origNode = origNodes[node.id];
74482                 nearNodes[node.id] = angle;
74483
74484                 node = node.move(geoInterp(origNode.loc, loc, t));
74485                 graph = graph.replace(node);
74486             }
74487
74488             // add new inbetween nodes if necessary
74489             for (j = 0; j < numberNewPoints; j++) {
74490                 angle = startAngle + (indexRange + j) * eachAngle;
74491                 loc = projection$$1.invert([
74492                     centroid[0] + Math.cos(angle) * radius,
74493                     centroid[1] + Math.sin(angle) * radius
74494                 ]);
74495
74496                 // choose a nearnode to use as the original
74497                 var min$$1 = Infinity;
74498                 for (var nodeId in nearNodes) {
74499                     var nearAngle = nearNodes[nodeId],
74500                         dist = Math.abs(nearAngle - angle);
74501                     if (dist < min$$1) {
74502                         dist = min$$1;
74503                         origNode = origNodes[nodeId];
74504                     }
74505                 }
74506
74507                 node = osmNode({ loc: geoInterp(origNode.loc, loc, t) });
74508                 graph = graph.replace(node);
74509
74510                 nodes.splice(endNodeIndex + j, 0, node);
74511                 inBetweenNodes.push(node.id);
74512             }
74513
74514             // Check for other ways that share these keyNodes..
74515             // If keyNodes are adjacent in both ways,
74516             // we can add inBetween nodes to that shared way too..
74517             if (indexRange === 1 && inBetweenNodes.length) {
74518                 var startIndex1 = way.nodes.lastIndexOf(startNode.id),
74519                     endIndex1 = way.nodes.lastIndexOf(endNode.id),
74520                     wayDirection1 = (endIndex1 - startIndex1);
74521                 if (wayDirection1 < -1) { wayDirection1 = 1; }
74522
74523                 /* eslint-disable no-loop-func */
74524                 lodash.each(lodash.without(graph.parentWays(keyNodes[i]), way), function(sharedWay) {
74525                     if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
74526                         var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id),
74527                             endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id),
74528                             wayDirection2 = (endIndex2 - startIndex2),
74529                             insertAt = endIndex2;
74530                         if (wayDirection2 < -1) { wayDirection2 = 1; }
74531
74532                         if (wayDirection1 !== wayDirection2) {
74533                             inBetweenNodes.reverse();
74534                             insertAt = startIndex2;
74535                         }
74536                         for (j = 0; j < inBetweenNodes.length; j++) {
74537                             sharedWay = sharedWay.addNode(inBetweenNodes[j], insertAt + j);
74538                         }
74539                         graph = graph.replace(sharedWay);
74540                     }
74541                 });
74542                 /* eslint-enable no-loop-func */
74543             }
74544
74545         }
74546
74547         // update the way to have all the new nodes
74548         ids = nodes.map(function(n) { return n.id; });
74549         ids.push(ids[0]);
74550
74551         way = way.update({nodes: ids});
74552         graph = graph.replace(way);
74553
74554         return graph;
74555     };
74556
74557
74558     action.makeConvex = function(graph) {
74559         var way = graph.entity(wayId),
74560             nodes = lodash.uniq(graph.childNodes(way)),
74561             points = nodes.map(function(n) { return projection$$1(n.loc); }),
74562             sign = d3polygonArea(points) > 0 ? 1 : -1,
74563             hull = d3polygonHull(points);
74564
74565         // D3 convex hulls go counterclockwise..
74566         if (sign === -1) {
74567             nodes.reverse();
74568             points.reverse();
74569         }
74570
74571         for (var i = 0; i < hull.length - 1; i++) {
74572             var startIndex = points.indexOf(hull[i]),
74573                 endIndex = points.indexOf(hull[i+1]),
74574                 indexRange = (endIndex - startIndex);
74575
74576             if (indexRange < 0) {
74577                 indexRange += nodes.length;
74578             }
74579
74580             // move interior nodes to the surface of the convex hull..
74581             for (var j = 1; j < indexRange; j++) {
74582                 var point = geoInterp(hull[i], hull[i+1], j / indexRange),
74583                     node = nodes[(j + startIndex) % nodes.length].move(projection$$1.invert(point));
74584                 graph = graph.replace(node);
74585             }
74586         }
74587         return graph;
74588     };
74589
74590
74591     action.disabled = function(graph) {
74592         if (!graph.entity(wayId).isClosed())
74593             return 'not_closed';
74594     };
74595
74596
74597     action.transitionable = true;
74598
74599
74600     return action;
74601 }
74602
74603 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteWayAction.as
74604 function actionDeleteWay(wayId) {
74605
74606
74607     function canDeleteNode(node, graph) {
74608         return !graph.parentWays(node).length &&
74609             !graph.parentRelations(node).length &&
74610             !node.hasInterestingTags();
74611     }
74612
74613
74614     var action = function(graph) {
74615         var way = graph.entity(wayId);
74616
74617         graph.parentRelations(way)
74618             .forEach(function(parent) {
74619                 parent = parent.removeMembersWithID(wayId);
74620                 graph = graph.replace(parent);
74621
74622                 if (parent.isDegenerate()) {
74623                     graph = actionDeleteRelation(parent.id)(graph);
74624                 }
74625             });
74626
74627         lodash.uniq(way.nodes).forEach(function(nodeId) {
74628             graph = graph.replace(way.removeNode(nodeId));
74629
74630             var node = graph.entity(nodeId);
74631             if (canDeleteNode(node, graph)) {
74632                 graph = graph.remove(node);
74633             }
74634         });
74635
74636         return graph.remove(way);
74637     };
74638
74639
74640     return action;
74641 }
74642
74643 function actionDeleteMultiple(ids) {
74644     var actions = {
74645         way: actionDeleteWay,
74646         node: actionDeleteNode,
74647         relation: actionDeleteRelation
74648     };
74649
74650
74651     var action = function(graph) {
74652         ids.forEach(function(id) {
74653             if (graph.hasEntity(id)) { // It may have been deleted aready.
74654                 graph = actions[graph.entity(id).type](id)(graph);
74655             }
74656         });
74657
74658         return graph;
74659     };
74660
74661
74662     return action;
74663 }
74664
74665 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
74666 function actionDeleteRelation(relationId) {
74667
74668
74669     function canDeleteEntity(entity, graph) {
74670         return !graph.parentWays(entity).length &&
74671             !graph.parentRelations(entity).length &&
74672             !entity.hasInterestingTags();
74673     }
74674
74675
74676     var action = function(graph) {
74677         var relation = graph.entity(relationId);
74678
74679         graph.parentRelations(relation)
74680             .forEach(function(parent) {
74681                 parent = parent.removeMembersWithID(relationId);
74682                 graph = graph.replace(parent);
74683
74684                 if (parent.isDegenerate()) {
74685                     graph = actionDeleteRelation(parent.id)(graph);
74686                 }
74687             });
74688
74689         lodash.uniq(lodash.map(relation.members, 'id')).forEach(function(memberId) {
74690             graph = graph.replace(relation.removeMembersWithID(memberId));
74691
74692             var entity = graph.entity(memberId);
74693             if (canDeleteEntity(entity, graph)) {
74694                 graph = actionDeleteMultiple([memberId])(graph);
74695             }
74696         });
74697
74698         return graph.remove(relation);
74699     };
74700
74701
74702     return action;
74703 }
74704
74705 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteNodeAction.as
74706 function actionDeleteNode(nodeId) {
74707     var action = function(graph) {
74708         var node = graph.entity(nodeId);
74709
74710         graph.parentWays(node)
74711             .forEach(function(parent) {
74712                 parent = parent.removeNode(nodeId);
74713                 graph = graph.replace(parent);
74714
74715                 if (parent.isDegenerate()) {
74716                     graph = actionDeleteWay(parent.id)(graph);
74717                 }
74718             });
74719
74720         graph.parentRelations(node)
74721             .forEach(function(parent) {
74722                 parent = parent.removeMembersWithID(nodeId);
74723                 graph = graph.replace(parent);
74724
74725                 if (parent.isDegenerate()) {
74726                     graph = actionDeleteRelation(parent.id)(graph);
74727                 }
74728             });
74729
74730         return graph.remove(node);
74731     };
74732
74733
74734     return action;
74735 }
74736
74737 // Connect the ways at the given nodes.
74738 //
74739 // The last node will survive. All other nodes will be replaced with
74740 // the surviving node in parent ways, and then removed.
74741 //
74742 // Tags and relation memberships of of non-surviving nodes are merged
74743 // to the survivor.
74744 //
74745 // This is the inverse of `iD.actionDisconnect`.
74746 //
74747 // Reference:
74748 //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
74749 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
74750 //
74751 function actionConnect(nodeIds) {
74752     return function(graph) {
74753         var survivor = graph.entity(lodash.last(nodeIds));
74754
74755         for (var i = 0; i < nodeIds.length - 1; i++) {
74756             var node = graph.entity(nodeIds[i]);
74757
74758             /* eslint-disable no-loop-func */
74759             graph.parentWays(node).forEach(function(parent) {
74760                 if (!parent.areAdjacent(node.id, survivor.id)) {
74761                     graph = graph.replace(parent.replaceNode(node.id, survivor.id));
74762                 }
74763             });
74764
74765             graph.parentRelations(node).forEach(function(parent) {
74766                 graph = graph.replace(parent.replaceMember(node, survivor));
74767             });
74768             /* eslint-enable no-loop-func */
74769
74770             survivor = survivor.mergeTags(node.tags);
74771             graph = actionDeleteNode(node.id)(graph);
74772         }
74773
74774         graph = graph.replace(survivor);
74775
74776         return graph;
74777     };
74778 }
74779
74780 function actionCopyEntities(ids, fromGraph) {
74781     var copies = {};
74782
74783
74784     var action = function(graph) {
74785         ids.forEach(function(id) {
74786             fromGraph.entity(id).copy(fromGraph, copies);
74787         });
74788
74789         for (var id in copies) {
74790             graph = graph.replace(copies[id]);
74791         }
74792
74793         return graph;
74794     };
74795
74796
74797     action.copies = function() {
74798         return copies;
74799     };
74800
74801
74802     return action;
74803 }
74804
74805 function actionDeleteMember(relationId, memberIndex) {
74806     return function(graph) {
74807         var relation = graph.entity(relationId)
74808             .removeMember(memberIndex);
74809
74810         graph = graph.replace(relation);
74811
74812         if (relation.isDegenerate())
74813             graph = actionDeleteRelation(relation.id)(graph);
74814
74815         return graph;
74816     };
74817 }
74818
74819 function actionDeprecateTags(entityId) {
74820
74821     return function(graph) {
74822         var entity = graph.entity(entityId),
74823             newtags = lodash.clone(entity.tags),
74824             change = false,
74825             rule;
74826
74827         // This handles dataDeprecated tags with a single condition
74828         for (var i = 0; i < dataDeprecated.length; i++) {
74829
74830             rule = dataDeprecated[i];
74831             var match = lodash.toPairs(rule.old)[0],
74832                 replacements = rule.replace ? lodash.toPairs(rule.replace) : null;
74833
74834             if (entity.tags[match[0]] && match[1] === '*') {
74835
74836                 var value = entity.tags[match[0]];
74837                 if (replacements && !newtags[replacements[0][0]]) {
74838                     newtags[replacements[0][0]] = value;
74839                 }
74840                 delete newtags[match[0]];
74841                 change = true;
74842
74843             } else if (entity.tags[match[0]] === match[1]) {
74844                 newtags = lodash.assign({}, rule.replace || {}, lodash.omit(newtags, match[0]));
74845                 change = true;
74846             }
74847         }
74848
74849         if (change) {
74850             return graph.replace(entity.update({tags: newtags}));
74851         } else {
74852             return graph;
74853         }
74854     };
74855 }
74856
74857 function actionDiscardTags(difference) {
74858
74859     return function(graph) {
74860         function discardTags(entity) {
74861             if (!lodash.isEmpty(entity.tags)) {
74862                 var tags = {};
74863                 lodash.each(entity.tags, function(v, k) {
74864                     if (v) tags[k] = v;
74865                 });
74866
74867                 graph = graph.replace(entity.update({
74868                     tags: lodash.omit(tags, dataDiscarded)
74869                 }));
74870             }
74871         }
74872
74873         difference.modified().forEach(discardTags);
74874         difference.created().forEach(discardTags);
74875
74876         return graph;
74877     };
74878 }
74879
74880 // Disconect the ways at the given node.
74881 //
74882 // Optionally, disconnect only the given ways.
74883 //
74884 // For testing convenience, accepts an ID to assign to the (first) new node.
74885 // Normally, this will be undefined and the way will automatically
74886 // be assigned a new ID.
74887 //
74888 // This is the inverse of `iD.actionConnect`.
74889 //
74890 // Reference:
74891 //   https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
74892 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
74893 //
74894 function actionDisconnect(nodeId, newNodeId) {
74895     var wayIds;
74896
74897
74898     var action = function(graph) {
74899         var node = graph.entity(nodeId),
74900             connections = action.connections(graph);
74901
74902         connections.forEach(function(connection) {
74903             var way = graph.entity(connection.wayID),
74904                 newNode = osmNode({id: newNodeId, loc: node.loc, tags: node.tags});
74905
74906             graph = graph.replace(newNode);
74907             if (connection.index === 0 && way.isArea()) {
74908                 // replace shared node with shared node..
74909                 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
74910             } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
74911                 // replace closing node with new new node..
74912                 graph = graph.replace(way.unclose().addNode(newNode.id));
74913             } else {
74914                 // replace shared node with multiple new nodes..
74915                 graph = graph.replace(way.updateNode(newNode.id, connection.index));
74916             }
74917         });
74918
74919         return graph;
74920     };
74921
74922
74923     action.connections = function(graph) {
74924         var candidates = [],
74925             keeping = false,
74926             parentWays = graph.parentWays(graph.entity(nodeId));
74927
74928         parentWays.forEach(function(way) {
74929             if (wayIds && wayIds.indexOf(way.id) === -1) {
74930                 keeping = true;
74931                 return;
74932             }
74933             if (way.isArea() && (way.nodes[0] === nodeId)) {
74934                 candidates.push({ wayID: way.id, index: 0 });
74935             } else {
74936                 way.nodes.forEach(function(waynode, index) {
74937                     if (waynode === nodeId) {
74938                         candidates.push({ wayID: way.id, index: index });
74939                     }
74940                 });
74941             }
74942         });
74943
74944         return keeping ? candidates : candidates.slice(1);
74945     };
74946
74947
74948     action.disabled = function(graph) {
74949         var connections = action.connections(graph);
74950         if (connections.length === 0 || (wayIds && wayIds.length !== connections.length))
74951             return 'not_connected';
74952
74953         var parentWays = graph.parentWays(graph.entity(nodeId)),
74954             seenRelationIds = {},
74955             sharedRelation;
74956
74957         parentWays.forEach(function(way) {
74958             if (wayIds && wayIds.indexOf(way.id) === -1)
74959                 return;
74960
74961             var relations = graph.parentRelations(way);
74962             relations.forEach(function(relation) {
74963                 if (relation.id in seenRelationIds) {
74964                     sharedRelation = relation;
74965                 } else {
74966                     seenRelationIds[relation.id] = true;
74967                 }
74968             });
74969         });
74970
74971         if (sharedRelation)
74972             return 'relation';
74973     };
74974
74975
74976     action.limitWays = function(_) {
74977         if (!arguments.length) return wayIds;
74978         wayIds = _;
74979         return action;
74980     };
74981
74982
74983     return action;
74984 }
74985
74986 // Join ways at the end node they share.
74987 //
74988 // This is the inverse of `iD.actionSplit`.
74989 //
74990 // Reference:
74991 //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
74992 //   https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
74993 //
74994 function actionJoin(ids) {
74995
74996     function groupEntitiesByGeometry(graph) {
74997         var entities = ids.map(function(id) { return graph.entity(id); });
74998         return lodash.extend({line: []}, lodash.groupBy(entities, function(entity) { return entity.geometry(graph); }));
74999     }
75000
75001
75002     var action = function(graph) {
75003         var ways = ids.map(graph.entity, graph),
75004             survivor = ways[0];
75005
75006         // Prefer to keep an existing way.
75007         for (var i = 0; i < ways.length; i++) {
75008             if (!ways[i].isNew()) {
75009                 survivor = ways[i];
75010                 break;
75011             }
75012         }
75013
75014         var joined = osmJoinWays(ways, graph)[0];
75015
75016         survivor = survivor.update({nodes: lodash.map(joined.nodes, 'id')});
75017         graph = graph.replace(survivor);
75018
75019         joined.forEach(function(way) {
75020             if (way.id === survivor.id)
75021                 return;
75022
75023             graph.parentRelations(way).forEach(function(parent) {
75024                 graph = graph.replace(parent.replaceMember(way, survivor));
75025             });
75026
75027             survivor = survivor.mergeTags(way.tags);
75028
75029             graph = graph.replace(survivor);
75030             graph = actionDeleteWay(way.id)(graph);
75031         });
75032
75033         return graph;
75034     };
75035
75036
75037     action.disabled = function(graph) {
75038         var geometries = groupEntitiesByGeometry(graph);
75039         if (ids.length < 2 || ids.length !== geometries.line.length)
75040             return 'not_eligible';
75041
75042         var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
75043         if (joined.length > 1)
75044             return 'not_adjacent';
75045
75046         var nodeIds = lodash.map(joined[0].nodes, 'id').slice(1, -1),
75047             relation,
75048             tags = {},
75049             conflicting = false;
75050
75051         joined[0].forEach(function(way) {
75052             var parents = graph.parentRelations(way);
75053             parents.forEach(function(parent) {
75054                 if (parent.isRestriction() && parent.members.some(function(m) { return nodeIds.indexOf(m.id) >= 0; }))
75055                     relation = parent;
75056             });
75057
75058             for (var k in way.tags) {
75059                 if (!(k in tags)) {
75060                     tags[k] = way.tags[k];
75061                 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
75062                     conflicting = true;
75063                 }
75064             }
75065         });
75066
75067         if (relation)
75068             return 'restriction';
75069
75070         if (conflicting)
75071             return 'conflicting_tags';
75072     };
75073
75074
75075     return action;
75076 }
75077
75078 function actionMerge(ids) {
75079
75080     function groupEntitiesByGeometry(graph) {
75081         var entities = ids.map(function(id) { return graph.entity(id); });
75082         return lodash.extend({point: [], area: [], line: [], relation: []},
75083             lodash.groupBy(entities, function(entity) { return entity.geometry(graph); }));
75084     }
75085
75086
75087     var action = function(graph) {
75088         var geometries = groupEntitiesByGeometry(graph),
75089             target = geometries.area[0] || geometries.line[0],
75090             points = geometries.point;
75091
75092         points.forEach(function(point) {
75093             target = target.mergeTags(point.tags);
75094             graph = graph.replace(target);
75095
75096             graph.parentRelations(point).forEach(function(parent) {
75097                 graph = graph.replace(parent.replaceMember(point, target));
75098             });
75099
75100             var nodes = lodash.uniq(graph.childNodes(target)),
75101                 removeNode = point;
75102
75103             for (var i = 0; i < nodes.length; i++) {
75104                 var node = nodes[i];
75105                 if (graph.parentWays(node).length > 1 ||
75106                     graph.parentRelations(node).length ||
75107                     node.hasInterestingTags()) {
75108                     continue;
75109                 }
75110
75111                 // Found an uninteresting child node on the target way.
75112                 // Move orig point into its place to preserve point's history. #3683
75113                 graph = graph.replace(point.update({ tags: {}, loc: node.loc }));
75114                 target = target.replaceNode(node.id, point.id);
75115                 graph = graph.replace(target);
75116                 removeNode = node;
75117                 break;
75118             }
75119
75120             graph = graph.remove(removeNode);
75121         });
75122
75123         return graph;
75124     };
75125
75126
75127     action.disabled = function(graph) {
75128         var geometries = groupEntitiesByGeometry(graph);
75129         if (geometries.point.length === 0 ||
75130             (geometries.area.length + geometries.line.length) !== 1 ||
75131             geometries.relation.length !== 0)
75132             return 'not_eligible';
75133     };
75134
75135
75136     return action;
75137 }
75138
75139 function actionMergePolygon(ids, newRelationId) {
75140
75141     function groupEntities(graph) {
75142         var entities = ids.map(function (id) { return graph.entity(id); });
75143         return lodash.extend({
75144                 closedWay: [],
75145                 multipolygon: [],
75146                 other: []
75147             }, lodash.groupBy(entities, function(entity) {
75148                 if (entity.type === 'way' && entity.isClosed()) {
75149                     return 'closedWay';
75150                 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
75151                     return 'multipolygon';
75152                 } else {
75153                     return 'other';
75154                 }
75155             }));
75156     }
75157
75158
75159     var action = function(graph) {
75160         var entities = groupEntities(graph);
75161
75162         // An array representing all the polygons that are part of the multipolygon.
75163         //
75164         // Each element is itself an array of objects with an id property, and has a
75165         // locs property which is an array of the locations forming the polygon.
75166         var polygons = entities.multipolygon.reduce(function(polygons, m) {
75167             return polygons.concat(osmJoinWays(m.members, graph));
75168         }, []).concat(entities.closedWay.map(function(d) {
75169             var member = [{id: d.id}];
75170             member.nodes = graph.childNodes(d);
75171             return member;
75172         }));
75173
75174         // contained is an array of arrays of boolean values,
75175         // where contained[j][k] is true iff the jth way is
75176         // contained by the kth way.
75177         var contained = polygons.map(function(w, i) {
75178             return polygons.map(function(d, n) {
75179                 if (i === n) return null;
75180                 return geoPolygonContainsPolygon(
75181                     lodash.map(d.nodes, 'loc'),
75182                     lodash.map(w.nodes, 'loc'));
75183             });
75184         });
75185
75186         // Sort all polygons as either outer or inner ways
75187         var members = [],
75188             outer = true;
75189
75190         while (polygons.length) {
75191             extractUncontained(polygons);
75192             polygons = polygons.filter(isContained);
75193             contained = contained.filter(isContained).map(filterContained);
75194         }
75195
75196         function isContained(d, i) {
75197             return lodash.some(contained[i]);
75198         }
75199
75200         function filterContained(d) {
75201             return d.filter(isContained);
75202         }
75203
75204         function extractUncontained(polygons) {
75205             polygons.forEach(function(d, i) {
75206                 if (!isContained(d, i)) {
75207                     d.forEach(function(member) {
75208                         members.push({
75209                             type: 'way',
75210                             id: member.id,
75211                             role: outer ? 'outer' : 'inner'
75212                         });
75213                     });
75214                 }
75215             });
75216             outer = !outer;
75217         }
75218
75219         // Move all tags to one relation
75220         var relation = entities.multipolygon[0] ||
75221             osmRelation({ id: newRelationId, tags: { type: 'multipolygon' }});
75222
75223         entities.multipolygon.slice(1).forEach(function(m) {
75224             relation = relation.mergeTags(m.tags);
75225             graph = graph.remove(m);
75226         });
75227
75228         entities.closedWay.forEach(function(way) {
75229             function isThisOuter(m) {
75230                 return m.id === way.id && m.role !== 'inner';
75231             }
75232             if (members.some(isThisOuter)) {
75233                 relation = relation.mergeTags(way.tags);
75234                 graph = graph.replace(way.update({ tags: {} }));
75235             }
75236         });
75237
75238         return graph.replace(relation.update({
75239             members: members,
75240             tags: lodash.omit(relation.tags, 'area')
75241         }));
75242     };
75243
75244
75245     action.disabled = function(graph) {
75246         var entities = groupEntities(graph);
75247         if (entities.other.length > 0 ||
75248             entities.closedWay.length + entities.multipolygon.length < 2)
75249             return 'not_eligible';
75250         if (!entities.multipolygon.every(function(r) { return r.isComplete(graph); }))
75251             return 'incomplete_relation';
75252     };
75253
75254
75255     return action;
75256 }
75257
75258 // Copyright (c) 2006, 2008 Tony Garnock-Jones <tonyg@lshift.net>
75259 // Copyright (c) 2006, 2008 LShift Ltd. <query@lshift.net>
75260 //
75261 // Permission is hereby granted, free of charge, to any person
75262 // obtaining a copy of this software and associated documentation files
75263 // (the "Software"), to deal in the Software without restriction,
75264 // including without limitation the rights to use, copy, modify, merge,
75265 // publish, distribute, sublicense, and/or sell copies of the Software,
75266 // and to permit persons to whom the Software is furnished to do so,
75267 // subject to the following conditions:
75268 //
75269 // The above copyright notice and this permission notice shall be
75270 // included in all copies or substantial portions of the Software.
75271 //
75272 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
75273 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
75274 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
75275 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
75276 // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
75277 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
75278 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
75279 // SOFTWARE.
75280
75281 // source:  https://bitbucket.org/lshift/synchrotron/src
75282 function longest_common_subsequence(file1, file2) {
75283     /* Text diff algorithm following Hunt and McIlroy 1976.
75284      * J. W. Hunt and M. D. McIlroy, An algorithm for differential file
75285      * comparison, Bell Telephone Laboratories CSTR #41 (1976)
75286      * http://www.cs.dartmouth.edu/~doug/
75287      *
75288      * Expects two arrays of strings.
75289      */
75290     var equivalenceClasses;
75291     var file2indices;
75292     var newCandidate;
75293     var candidates;
75294     var line;
75295     var c, i, j, jX, r, s;
75296
75297     equivalenceClasses = {};
75298     for (j = 0; j < file2.length; j++) {
75299         line = file2[j];
75300         if (equivalenceClasses[line]) {
75301             equivalenceClasses[line].push(j);
75302         } else {
75303             equivalenceClasses[line] = [j];
75304         }
75305     }
75306
75307     candidates = [{file1index: -1,
75308                    file2index: -1,
75309                    chain: null}];
75310
75311     for (i = 0; i < file1.length; i++) {
75312         line = file1[i];
75313         file2indices = equivalenceClasses[line] || [];
75314
75315         r = 0;
75316         c = candidates[0];
75317
75318         for (jX = 0; jX < file2indices.length; jX++) {
75319             j = file2indices[jX];
75320
75321             for (s = 0; s < candidates.length; s++) {
75322                 if ((candidates[s].file2index < j) &&
75323                     ((s === candidates.length - 1) ||
75324                      (candidates[s + 1].file2index > j)))
75325                     break;
75326             }
75327
75328             if (s < candidates.length) {
75329                 newCandidate = {file1index: i,
75330                                 file2index: j,
75331                                 chain: candidates[s]};
75332                 if (r === candidates.length) {
75333                     candidates.push(c);
75334                 } else {
75335                     candidates[r] = c;
75336                 }
75337                 r = s + 1;
75338                 c = newCandidate;
75339                 if (r === candidates.length) {
75340                     break; // no point in examining further (j)s
75341                 }
75342             }
75343         }
75344
75345         candidates[r] = c;
75346     }
75347
75348     // At this point, we know the LCS: it's in the reverse of the
75349     // linked-list through .chain of
75350     // candidates[candidates.length - 1].
75351
75352     return candidates[candidates.length - 1];
75353 }
75354
75355
75356
75357
75358
75359
75360
75361
75362
75363
75364
75365 function diff_indices(file1, file2) {
75366     // We apply the LCS to give a simple representation of the
75367     // offsets and lengths of mismatched chunks in the input
75368     // files. This is used by diff3_merge_indices below.
75369
75370     var result = [];
75371     var tail1 = file1.length;
75372     var tail2 = file2.length;
75373
75374     for (var candidate = longest_common_subsequence(file1, file2);
75375          candidate !== null;
75376          candidate = candidate.chain)
75377     {
75378         var mismatchLength1 = tail1 - candidate.file1index - 1;
75379         var mismatchLength2 = tail2 - candidate.file2index - 1;
75380         tail1 = candidate.file1index;
75381         tail2 = candidate.file2index;
75382
75383         if (mismatchLength1 || mismatchLength2) {
75384             result.push({file1: [tail1 + 1, mismatchLength1],
75385                          file2: [tail2 + 1, mismatchLength2]});
75386         }
75387     }
75388
75389     result.reverse();
75390     return result;
75391 }
75392
75393 function diff3_merge_indices (a, o, b) {
75394     // Given three files, A, O, and B, where both A and B are
75395     // independently derived from O, returns a fairly complicated
75396     // internal representation of merge decisions it's taken. The
75397     // interested reader may wish to consult
75398     //
75399     // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce. "A
75400     // Formal Investigation of Diff3." In Arvind and Prasad,
75401     // editors, Foundations of Software Technology and Theoretical
75402     // Computer Science (FSTTCS), December 2007.
75403     //
75404     // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
75405     var i;
75406
75407     var m1 = diff_indices(o, a);
75408     var m2 = diff_indices(o, b);
75409
75410     var hunks = [];
75411     function addHunk(h, side) {
75412         hunks.push([h.file1[0], side, h.file1[1], h.file2[0], h.file2[1]]);
75413     }
75414     for (i = 0; i < m1.length; i++) { addHunk(m1[i], 0); }
75415     for (i = 0; i < m2.length; i++) { addHunk(m2[i], 2); }
75416     hunks.sort();
75417
75418     var result = [];
75419     var commonOffset = 0;
75420     function copyCommon(targetOffset) {
75421         if (targetOffset > commonOffset) {
75422             result.push([1, commonOffset, targetOffset - commonOffset]);
75423             commonOffset = targetOffset;
75424         }
75425     }
75426
75427     for (var hunkIndex = 0; hunkIndex < hunks.length; hunkIndex++) {
75428         var firstHunkIndex = hunkIndex;
75429         var hunk = hunks[hunkIndex];
75430         var regionLhs = hunk[0];
75431         var regionRhs = regionLhs + hunk[2];
75432         while (hunkIndex < hunks.length - 1) {
75433             var maybeOverlapping = hunks[hunkIndex + 1];
75434             var maybeLhs = maybeOverlapping[0];
75435             if (maybeLhs > regionRhs) break;
75436             regionRhs = maybeLhs + maybeOverlapping[2];
75437             hunkIndex++;
75438         }
75439
75440         copyCommon(regionLhs);
75441         if (firstHunkIndex === hunkIndex) {
75442     // The "overlap" was only one hunk long, meaning that
75443     // there's no conflict here. Either a and o were the
75444     // same, or b and o were the same.
75445             if (hunk[4] > 0) {
75446                 result.push([hunk[1], hunk[3], hunk[4]]);
75447             }
75448         } else {
75449     // A proper conflict. Determine the extents of the
75450     // regions involved from a, o and b. Effectively merge
75451     // all the hunks on the left into one giant hunk, and
75452     // do the same for the right; then, correct for skew
75453     // in the regions of o that each side changed, and
75454     // report appropriate spans for the three sides.
75455     var regions = {
75456         0: [a.length, -1, o.length, -1],
75457         2: [b.length, -1, o.length, -1]
75458     };
75459             for (i = firstHunkIndex; i <= hunkIndex; i++) {
75460         hunk = hunks[i];
75461                 var side = hunk[1];
75462         var r = regions[side];
75463         var oLhs = hunk[0];
75464         var oRhs = oLhs + hunk[2];
75465                 var abLhs = hunk[3];
75466                 var abRhs = abLhs + hunk[4];
75467         r[0] = Math.min(abLhs, r[0]);
75468         r[1] = Math.max(abRhs, r[1]);
75469         r[2] = Math.min(oLhs, r[2]);
75470         r[3] = Math.max(oRhs, r[3]);
75471             }
75472     var aLhs = regions[0][0] + (regionLhs - regions[0][2]);
75473     var aRhs = regions[0][1] + (regionRhs - regions[0][3]);
75474     var bLhs = regions[2][0] + (regionLhs - regions[2][2]);
75475     var bRhs = regions[2][1] + (regionRhs - regions[2][3]);
75476             result.push([-1,
75477              aLhs,      aRhs      - aLhs,
75478              regionLhs, regionRhs - regionLhs,
75479              bLhs,      bRhs      - bLhs]);
75480         }
75481         commonOffset = regionRhs;
75482     }
75483
75484     copyCommon(o.length);
75485     return result;
75486 }
75487
75488 function diff3_merge (a, o, b, excludeFalseConflicts) {
75489     // Applies the output of Diff3.diff3_merge_indices to actually
75490     // construct the merged file; the returned result alternates
75491     // between "ok" and "conflict" blocks.
75492
75493     var result = [];
75494     var files = [a, o, b];
75495     var indices = diff3_merge_indices(a, o, b);
75496
75497     var okLines = [];
75498     function flushOk() {
75499         if (okLines.length) {
75500             result.push({ok: okLines});
75501         }
75502         okLines = [];
75503     }
75504     function pushOk(xs) {
75505         for (var j = 0; j < xs.length; j++) {
75506             okLines.push(xs[j]);
75507         }
75508     }
75509
75510     function isTrueConflict(rec) {
75511         if (rec[2] !== rec[6]) return true;
75512         var aoff = rec[1];
75513         var boff = rec[5];
75514         for (var j = 0; j < rec[2]; j++) {
75515             if (a[j + aoff] !== b[j + boff]) return true;
75516         }
75517         return false;
75518     }
75519
75520     for (var i = 0; i < indices.length; i++) {
75521         var x = indices[i];
75522         var side = x[0];
75523         if (side === -1) {
75524             if (excludeFalseConflicts && !isTrueConflict(x)) {
75525                 pushOk(files[0].slice(x[1], x[1] + x[2]));
75526             } else {
75527                 flushOk();
75528                 result.push({conflict: {a: a.slice(x[1], x[1] + x[2]),
75529                                         aIndex: x[1],
75530                                         o: o.slice(x[3], x[3] + x[4]),
75531                                         oIndex: x[3],
75532                                         b: b.slice(x[5], x[5] + x[6]),
75533                                         bIndex: x[5]}});
75534             }
75535         } else {
75536             pushOk(files[side].slice(x[1], x[1] + x[2]));
75537         }
75538     }
75539
75540     flushOk();
75541     return result;
75542 }
75543
75544 function actionMergeRemoteChanges(id, localGraph, remoteGraph, formatUser) {
75545     var option = 'safe',  // 'safe', 'force_local', 'force_remote'
75546         conflicts = [];
75547
75548
75549     function user(d) {
75550         return lodash.isFunction(formatUser) ? formatUser(d) : d;
75551     }
75552
75553
75554     function mergeLocation(remote, target) {
75555         function pointEqual(a, b) {
75556             var epsilon = 1e-6;
75557             return (Math.abs(a[0] - b[0]) < epsilon) && (Math.abs(a[1] - b[1]) < epsilon);
75558         }
75559
75560         if (option === 'force_local' || pointEqual(target.loc, remote.loc)) {
75561             return target;
75562         }
75563         if (option === 'force_remote') {
75564             return target.update({loc: remote.loc});
75565         }
75566
75567         conflicts.push(t('merge_remote_changes.conflict.location', { user: user(remote.user) }));
75568         return target;
75569     }
75570
75571
75572     function mergeNodes(base, remote, target) {
75573         if (option === 'force_local' || lodash.isEqual(target.nodes, remote.nodes)) {
75574             return target;
75575         }
75576         if (option === 'force_remote') {
75577             return target.update({nodes: remote.nodes});
75578         }
75579
75580         var ccount = conflicts.length,
75581             o = base.nodes || [],
75582             a = target.nodes || [],
75583             b = remote.nodes || [],
75584             nodes = [],
75585             hunks = diff3_merge(a, o, b, true);
75586
75587         for (var i = 0; i < hunks.length; i++) {
75588             var hunk = hunks[i];
75589             if (hunk.ok) {
75590                 nodes.push.apply(nodes, hunk.ok);
75591             } else {
75592                 // for all conflicts, we can assume c.a !== c.b
75593                 // because `diff3_merge` called with `true` option to exclude false conflicts..
75594                 var c = hunk.conflict;
75595                 if (lodash.isEqual(c.o, c.a)) {  // only changed remotely
75596                     nodes.push.apply(nodes, c.b);
75597                 } else if (lodash.isEqual(c.o, c.b)) {  // only changed locally
75598                     nodes.push.apply(nodes, c.a);
75599                 } else {       // changed both locally and remotely
75600                     conflicts.push(t('merge_remote_changes.conflict.nodelist', { user: user(remote.user) }));
75601                     break;
75602                 }
75603             }
75604         }
75605
75606         return (conflicts.length === ccount) ? target.update({nodes: nodes}) : target;
75607     }
75608
75609
75610     function mergeChildren(targetWay, children, updates, graph) {
75611         function isUsed(node, targetWay) {
75612             var parentWays = lodash.map(graph.parentWays(node), 'id');
75613             return node.hasInterestingTags() ||
75614                 lodash.without(parentWays, targetWay.id).length > 0 ||
75615                 graph.parentRelations(node).length > 0;
75616         }
75617
75618         var ccount = conflicts.length;
75619
75620         for (var i = 0; i < children.length; i++) {
75621             var id = children[i],
75622                 node = graph.hasEntity(id);
75623
75624             // remove unused childNodes..
75625             if (targetWay.nodes.indexOf(id) === -1) {
75626                 if (node && !isUsed(node, targetWay)) {
75627                     updates.removeIds.push(id);
75628                 }
75629                 continue;
75630             }
75631
75632             // restore used childNodes..
75633             var local = localGraph.hasEntity(id),
75634                 remote = remoteGraph.hasEntity(id),
75635                 target;
75636
75637             if (option === 'force_remote' && remote && remote.visible) {
75638                 updates.replacements.push(remote);
75639
75640             } else if (option === 'force_local' && local) {
75641                 target = osmEntity$$1(local);
75642                 if (remote) {
75643                     target = target.update({ version: remote.version });
75644                 }
75645                 updates.replacements.push(target);
75646
75647             } else if (option === 'safe' && local && remote && local.version !== remote.version) {
75648                 target = osmEntity$$1(local, { version: remote.version });
75649                 if (remote.visible) {
75650                     target = mergeLocation(remote, target);
75651                 } else {
75652                     conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
75653                 }
75654
75655                 if (conflicts.length !== ccount) break;
75656                 updates.replacements.push(target);
75657             }
75658         }
75659
75660         return targetWay;
75661     }
75662
75663
75664     function updateChildren(updates, graph) {
75665         for (var i = 0; i < updates.replacements.length; i++) {
75666             graph = graph.replace(updates.replacements[i]);
75667         }
75668         if (updates.removeIds.length) {
75669             graph = actionDeleteMultiple(updates.removeIds)(graph);
75670         }
75671         return graph;
75672     }
75673
75674
75675     function mergeMembers(remote, target) {
75676         if (option === 'force_local' || lodash.isEqual(target.members, remote.members)) {
75677             return target;
75678         }
75679         if (option === 'force_remote') {
75680             return target.update({members: remote.members});
75681         }
75682
75683         conflicts.push(t('merge_remote_changes.conflict.memberlist', { user: user(remote.user) }));
75684         return target;
75685     }
75686
75687
75688     function mergeTags(base, remote, target) {
75689         function ignoreKey(k) {
75690             return lodash.includes(dataDiscarded, k);
75691         }
75692
75693         if (option === 'force_local' || lodash.isEqual(target.tags, remote.tags)) {
75694             return target;
75695         }
75696         if (option === 'force_remote') {
75697             return target.update({tags: remote.tags});
75698         }
75699
75700         var ccount = conflicts.length,
75701             o = base.tags || {},
75702             a = target.tags || {},
75703             b = remote.tags || {},
75704             keys = lodash.reject(lodash.union(lodash.keys(o), lodash.keys(a), lodash.keys(b)), ignoreKey),
75705             tags = lodash.clone(a),
75706             changed = false;
75707
75708         for (var i = 0; i < keys.length; i++) {
75709             var k = keys[i];
75710
75711             if (o[k] !== b[k] && a[k] !== b[k]) {    // changed remotely..
75712                 if (o[k] !== a[k]) {      // changed locally..
75713                     conflicts.push(t('merge_remote_changes.conflict.tags',
75714                         { tag: k, local: a[k], remote: b[k], user: user(remote.user) }));
75715
75716                 } else {                  // unchanged locally, accept remote change..
75717                     if (b.hasOwnProperty(k)) {
75718                         tags[k] = b[k];
75719                     } else {
75720                         delete tags[k];
75721                     }
75722                     changed = true;
75723                 }
75724             }
75725         }
75726
75727         return (changed && conflicts.length === ccount) ? target.update({tags: tags}) : target;
75728     }
75729
75730
75731     //  `graph.base()` is the common ancestor of the two graphs.
75732     //  `localGraph` contains user's edits up to saving
75733     //  `remoteGraph` contains remote edits to modified nodes
75734     //  `graph` must be a descendent of `localGraph` and may include
75735     //      some conflict resolution actions performed on it.
75736     //
75737     //                  --- ... --- `localGraph` -- ... -- `graph`
75738     //                 /
75739     //  `graph.base()` --- ... --- `remoteGraph`
75740     //
75741     var action = function(graph) {
75742         var updates = { replacements: [], removeIds: [] },
75743             base = graph.base().entities[id],
75744             local = localGraph.entity(id),
75745             remote = remoteGraph.entity(id),
75746             target = osmEntity$$1(local, { version: remote.version });
75747
75748         // delete/undelete
75749         if (!remote.visible) {
75750             if (option === 'force_remote') {
75751                 return actionDeleteMultiple([id])(graph);
75752
75753             } else if (option === 'force_local') {
75754                 if (target.type === 'way') {
75755                     target = mergeChildren(target, lodash.uniq(local.nodes), updates, graph);
75756                     graph = updateChildren(updates, graph);
75757                 }
75758                 return graph.replace(target);
75759
75760             } else {
75761                 conflicts.push(t('merge_remote_changes.conflict.deleted', { user: user(remote.user) }));
75762                 return graph;  // do nothing
75763             }
75764         }
75765
75766         // merge
75767         if (target.type === 'node') {
75768             target = mergeLocation(remote, target);
75769
75770         } else if (target.type === 'way') {
75771             // pull in any child nodes that may not be present locally..
75772             graph.rebase(remoteGraph.childNodes(remote), [graph], false);
75773             target = mergeNodes(base, remote, target);
75774             target = mergeChildren(target, lodash.union(local.nodes, remote.nodes), updates, graph);
75775
75776         } else if (target.type === 'relation') {
75777             target = mergeMembers(remote, target);
75778         }
75779
75780         target = mergeTags(base, remote, target);
75781
75782         if (!conflicts.length) {
75783             graph = updateChildren(updates, graph).replace(target);
75784         }
75785
75786         return graph;
75787     };
75788
75789
75790     action.withOption = function(opt) {
75791         option = opt;
75792         return action;
75793     };
75794
75795
75796     action.conflicts = function() {
75797         return conflicts;
75798     };
75799
75800
75801     return action;
75802 }
75803
75804 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
75805 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
75806 function actionMove(moveIds, tryDelta, projection, cache) {
75807     var delta = tryDelta;
75808
75809     function vecAdd(a, b) { return [a[0] + b[0], a[1] + b[1]]; }
75810     function vecSub(a, b) { return [a[0] - b[0], a[1] - b[1]]; }
75811
75812     function setupCache(graph) {
75813         function canMove(nodeId) {
75814             // Allow movement of any node that is in the selectedIDs list..
75815             if (moveIds.indexOf(nodeId) !== -1) return true;
75816
75817             // Allow movement of a vertex where 2 ways meet..
75818             var parents = lodash.map(graph.parentWays(graph.entity(nodeId)), 'id');
75819             if (parents.length < 3) return true;
75820
75821             // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
75822             var parentsMoving = lodash.every(parents, function(id) { return cache.moving[id]; });
75823             if (!parentsMoving) delete cache.moving[nodeId];
75824
75825             return parentsMoving;
75826         }
75827
75828         function cacheEntities(ids) {
75829             ids.forEach(function(id) {
75830                 if (cache.moving[id]) return;
75831                 cache.moving[id] = true;
75832
75833                 var entity = graph.hasEntity(id);
75834                 if (!entity) return;
75835
75836                 if (entity.type === 'node') {
75837                     cache.nodes.push(id);
75838                     cache.startLoc[id] = entity.loc;
75839                 } else if (entity.type === 'way') {
75840                     cache.ways.push(id);
75841                     cacheEntities(entity.nodes);
75842                 } else {
75843                     cacheEntities(entity.members.map(function(member) {
75844                         return member.id;
75845                     }));
75846                 }
75847             });
75848         }
75849
75850         function cacheIntersections(ids) {
75851             function isEndpoint(way, id) { return !way.isClosed() && !!way.affix(id); }
75852
75853             ids.forEach(function(id) {
75854                 // consider only intersections with 1 moved and 1 unmoved way.
75855                 var childNodes = graph.childNodes(graph.entity(id));
75856                 childNodes.forEach(function(node) {
75857                     var parents = graph.parentWays(node);
75858                     if (parents.length !== 2) return;
75859
75860                     var moved = graph.entity(id),
75861                         unmoved = lodash.find(parents, function(way) { return !cache.moving[way.id]; });
75862                     if (!unmoved) return;
75863
75864                     // exclude ways that are overly connected..
75865                     if (lodash.intersection(moved.nodes, unmoved.nodes).length > 2) return;
75866
75867                     if (moved.isArea() || unmoved.isArea()) return;
75868
75869                     cache.intersection[node.id] = {
75870                         nodeId: node.id,
75871                         movedId: moved.id,
75872                         unmovedId: unmoved.id,
75873                         movedIsEP: isEndpoint(moved, node.id),
75874                         unmovedIsEP: isEndpoint(unmoved, node.id)
75875                     };
75876                 });
75877             });
75878         }
75879
75880
75881         if (!cache) {
75882             cache = {};
75883         }
75884         if (!cache.ok) {
75885             cache.moving = {};
75886             cache.intersection = {};
75887             cache.replacedVertex = {};
75888             cache.startLoc = {};
75889             cache.nodes = [];
75890             cache.ways = [];
75891
75892             cacheEntities(moveIds);
75893             cacheIntersections(cache.ways);
75894             cache.nodes = lodash.filter(cache.nodes, canMove);
75895
75896             cache.ok = true;
75897         }
75898     }
75899
75900
75901     // Place a vertex where the moved vertex used to be, to preserve way shape..
75902     function replaceMovedVertex(nodeId, wayId, graph, delta) {
75903         var way = graph.entity(wayId),
75904             moved = graph.entity(nodeId),
75905             movedIndex = way.nodes.indexOf(nodeId),
75906             len, prevIndex, nextIndex;
75907
75908         if (way.isClosed()) {
75909             len = way.nodes.length - 1;
75910             prevIndex = (movedIndex + len - 1) % len;
75911             nextIndex = (movedIndex + len + 1) % len;
75912         } else {
75913             len = way.nodes.length;
75914             prevIndex = movedIndex - 1;
75915             nextIndex = movedIndex + 1;
75916         }
75917
75918         var prev = graph.hasEntity(way.nodes[prevIndex]),
75919             next = graph.hasEntity(way.nodes[nextIndex]);
75920
75921         // Don't add orig vertex at endpoint..
75922         if (!prev || !next) return graph;
75923
75924         var key = wayId + '_' + nodeId,
75925             orig = cache.replacedVertex[key];
75926         if (!orig) {
75927             orig = osmNode();
75928             cache.replacedVertex[key] = orig;
75929             cache.startLoc[orig.id] = cache.startLoc[nodeId];
75930         }
75931
75932         var start, end;
75933         if (delta) {
75934             start = projection(cache.startLoc[nodeId]);
75935             end = projection.invert(vecAdd(start, delta));
75936         } else {
75937             end = cache.startLoc[nodeId];
75938         }
75939         orig = orig.move(end);
75940
75941         var angle = Math.abs(geoAngle(orig, prev, projection) -
75942                 geoAngle(orig, next, projection)) * 180 / Math.PI;
75943
75944         // Don't add orig vertex if it would just make a straight line..
75945         if (angle > 175 && angle < 185) return graph;
75946
75947         // Don't add orig vertex if another point is already nearby (within 10m)
75948         if (geoSphericalDistance(prev.loc, orig.loc) < 10 ||
75949             geoSphericalDistance(orig.loc, next.loc) < 10) return graph;
75950
75951         // moving forward or backward along way?
75952         var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection),
75953             p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection),
75954             d1 = geoPathLength(p1),
75955             d2 = geoPathLength(p2),
75956             insertAt = (d1 < d2) ? movedIndex : nextIndex;
75957
75958         // moving around closed loop?
75959         if (way.isClosed() && insertAt === 0) insertAt = len;
75960
75961         way = way.addNode(orig.id, insertAt);
75962         return graph.replace(orig).replace(way);
75963     }
75964
75965
75966     // Reorder nodes around intersections that have moved..
75967     function unZorroIntersection(intersection, graph) {
75968         var vertex = graph.entity(intersection.nodeId),
75969             way1 = graph.entity(intersection.movedId),
75970             way2 = graph.entity(intersection.unmovedId),
75971             isEP1 = intersection.movedIsEP,
75972             isEP2 = intersection.unmovedIsEP;
75973
75974         // don't move the vertex if it is the endpoint of both ways.
75975         if (isEP1 && isEP2) return graph;
75976
75977         var nodes1 = lodash.without(graph.childNodes(way1), vertex),
75978             nodes2 = lodash.without(graph.childNodes(way2), vertex);
75979
75980         if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
75981         if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
75982
75983         var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection),
75984             edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection),
75985             loc;
75986
75987         // snap vertex to nearest edge (or some point between them)..
75988         if (!isEP1 && !isEP2) {
75989             var epsilon = 1e-4, maxIter = 10;
75990             for (var i = 0; i < maxIter; i++) {
75991                 loc = geoInterp(edge1.loc, edge2.loc, 0.5);
75992                 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
75993                 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
75994                 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
75995             }
75996         } else if (!isEP1) {
75997             loc = edge1.loc;
75998         } else {
75999             loc = edge2.loc;
76000         }
76001
76002         graph = graph.replace(vertex.move(loc));
76003
76004         // if zorro happened, reorder nodes..
76005         if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
76006             way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
76007             graph = graph.replace(way1);
76008         }
76009         if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
76010             way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
76011             graph = graph.replace(way2);
76012         }
76013
76014         return graph;
76015     }
76016
76017
76018     function cleanupIntersections(graph) {
76019         lodash.each(cache.intersection, function(obj) {
76020             graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, delta);
76021             graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
76022             graph = unZorroIntersection(obj, graph);
76023         });
76024
76025         return graph;
76026     }
76027
76028
76029     // check if moving way endpoint can cross an unmoved way, if so limit delta..
76030     function limitDelta(graph) {
76031         lodash.each(cache.intersection, function(obj) {
76032             // Don't limit movement if this is vertex joins 2 endpoints..
76033             if (obj.movedIsEP && obj.unmovedIsEP) return;
76034             // Don't limit movement if this vertex is not an endpoint anyway..
76035             if (!obj.movedIsEP) return;
76036
76037             var node = graph.entity(obj.nodeId),
76038                 start = projection(node.loc),
76039                 end = vecAdd(start, delta),
76040                 movedNodes = graph.childNodes(graph.entity(obj.movedId)),
76041                 movedPath = lodash.map(lodash.map(movedNodes, 'loc'),
76042                     function(loc) { return vecAdd(projection(loc), delta); }),
76043                 unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId)),
76044                 unmovedPath = lodash.map(lodash.map(unmovedNodes, 'loc'), projection),
76045                 hits = geoPathIntersections(movedPath, unmovedPath);
76046
76047             for (var i = 0; i < hits.length; i++) {
76048                 if (lodash.isEqual(hits[i], end)) continue;
76049                 var edge = geoChooseEdge(unmovedNodes, end, projection);
76050                 delta = vecSub(projection(edge.loc), start);
76051             }
76052         });
76053     }
76054
76055
76056     var action = function(graph) {
76057         if (delta[0] === 0 && delta[1] === 0) return graph;
76058
76059         setupCache(graph);
76060
76061         if (!lodash.isEmpty(cache.intersection)) {
76062             limitDelta(graph);
76063         }
76064
76065         lodash.each(cache.nodes, function(id) {
76066             var node = graph.entity(id),
76067                 start = projection(node.loc),
76068                 end = vecAdd(start, delta);
76069             graph = graph.replace(node.move(projection.invert(end)));
76070         });
76071
76072         if (!lodash.isEmpty(cache.intersection)) {
76073             graph = cleanupIntersections(graph);
76074         }
76075
76076         return graph;
76077     };
76078
76079
76080     action.delta = function() {
76081         return delta;
76082     };
76083
76084
76085     return action;
76086 }
76087
76088 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/MoveCommand.java
76089 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
76090 function actionMoveNode(nodeId, loc) {
76091     return function(graph) {
76092         return graph.replace(graph.entity(nodeId).move(loc));
76093     };
76094 }
76095
76096 function actionNoop() {
76097     return function(graph) {
76098         return graph;
76099     };
76100 }
76101
76102 /*
76103  * Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
76104  */
76105 function actionOrthogonalize(wayId, projection) {
76106     var threshold = 12, // degrees within right or straight to alter
76107         lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180),
76108         upperThreshold = Math.cos(threshold * Math.PI / 180);
76109
76110
76111     var action = function(graph, t) {
76112         if (t === null || !isFinite(t)) t = 1;
76113         t = Math.min(Math.max(+t, 0), 1);
76114
76115         var way = graph.entity(wayId),
76116             nodes = graph.childNodes(way),
76117             points = lodash.uniq(nodes).map(function(n) { return projection(n.loc); }),
76118             corner = {i: 0, dotp: 1},
76119             epsilon = 1e-4,
76120             node, loc, score, motions, i, j;
76121
76122         if (points.length === 3) {   // move only one vertex for right triangle
76123             for (i = 0; i < 1000; i++) {
76124                 motions = points.map(calcMotion);
76125                 points[corner.i] = addPoints(points[corner.i], motions[corner.i]);
76126                 score = corner.dotp;
76127                 if (score < epsilon) {
76128                     break;
76129                 }
76130             }
76131
76132             node = graph.entity(nodes[corner.i].id);
76133             loc = projection.invert(points[corner.i]);
76134             graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
76135
76136         } else {
76137             var best,
76138                 originalPoints = lodash.clone(points);
76139             score = Infinity;
76140
76141             for (i = 0; i < 1000; i++) {
76142                 motions = points.map(calcMotion);
76143                 for (j = 0; j < motions.length; j++) {
76144                     points[j] = addPoints(points[j],motions[j]);
76145                 }
76146                 var newScore = squareness(points);
76147                 if (newScore < score) {
76148                     best = lodash.clone(points);
76149                     score = newScore;
76150                 }
76151                 if (score < epsilon) {
76152                     break;
76153                 }
76154             }
76155
76156             points = best;
76157
76158             for (i = 0; i < points.length; i++) {
76159                 // only move the points that actually moved
76160                 if (originalPoints[i][0] !== points[i][0] || originalPoints[i][1] !== points[i][1]) {
76161                     loc = projection.invert(points[i]);
76162                     node = graph.entity(nodes[i].id);
76163                     graph = graph.replace(node.move(geoInterp(node.loc, loc, t)));
76164                 }
76165             }
76166
76167             // remove empty nodes on straight sections
76168             for (i = 0; t === 1 && i < points.length; i++) {
76169                 node = graph.entity(nodes[i].id);
76170
76171                 if (graph.parentWays(node).length > 1 ||
76172                     graph.parentRelations(node).length ||
76173                     node.hasInterestingTags()) {
76174                     continue;
76175                 }
76176
76177                 var dotp = normalizedDotProduct(i, points);
76178                 if (dotp < -1 + epsilon) {
76179                     graph = actionDeleteNode(node.id)(graph);
76180                 }
76181             }
76182         }
76183
76184         return graph;
76185
76186
76187         function calcMotion(b, i, array) {
76188             var a = array[(i - 1 + array.length) % array.length],
76189                 c = array[(i + 1) % array.length],
76190                 p = subtractPoints(a, b),
76191                 q = subtractPoints(c, b),
76192                 scale, dotp;
76193
76194             scale = 2 * Math.min(geoEuclideanDistance(p, [0, 0]), geoEuclideanDistance(q, [0, 0]));
76195             p = normalizePoint(p, 1.0);
76196             q = normalizePoint(q, 1.0);
76197
76198             dotp = filterDotProduct(p[0] * q[0] + p[1] * q[1]);
76199
76200             // nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
76201             if (array.length > 3) {
76202                 if (dotp < -0.707106781186547) {
76203                     dotp += 1.0;
76204                 }
76205             } else if (dotp && Math.abs(dotp) < corner.dotp) {
76206                 corner.i = i;
76207                 corner.dotp = Math.abs(dotp);
76208             }
76209
76210             return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
76211         }
76212     };
76213
76214
76215     function squareness(points) {
76216         return points.reduce(function(sum, val, i, array) {
76217             var dotp = normalizedDotProduct(i, array);
76218
76219             dotp = filterDotProduct(dotp);
76220             return sum + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
76221         }, 0);
76222     }
76223
76224
76225     function normalizedDotProduct(i, points) {
76226         var a = points[(i - 1 + points.length) % points.length],
76227             b = points[i],
76228             c = points[(i + 1) % points.length],
76229             p = subtractPoints(a, b),
76230             q = subtractPoints(c, b);
76231
76232         p = normalizePoint(p, 1.0);
76233         q = normalizePoint(q, 1.0);
76234
76235         return p[0] * q[0] + p[1] * q[1];
76236     }
76237
76238
76239     function subtractPoints(a, b) {
76240         return [a[0] - b[0], a[1] - b[1]];
76241     }
76242
76243
76244     function addPoints(a, b) {
76245         return [a[0] + b[0], a[1] + b[1]];
76246     }
76247
76248
76249     function normalizePoint(point, scale) {
76250         var vector = [0, 0];
76251         var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
76252         if (length !== 0) {
76253             vector[0] = point[0] / length;
76254             vector[1] = point[1] / length;
76255         }
76256
76257         vector[0] *= scale;
76258         vector[1] *= scale;
76259
76260         return vector;
76261     }
76262
76263
76264     function filterDotProduct(dotp) {
76265         if (lowerThreshold > Math.abs(dotp) || Math.abs(dotp) > upperThreshold) {
76266             return dotp;
76267         }
76268
76269         return 0;
76270     }
76271
76272
76273     action.disabled = function(graph) {
76274         var way = graph.entity(wayId),
76275             nodes = graph.childNodes(way),
76276             points = lodash.uniq(nodes).map(function(n) { return projection(n.loc); });
76277
76278         if (squareness(points)) {
76279             return false;
76280         }
76281
76282         return 'not_squarish';
76283     };
76284
76285
76286     action.transitionable = true;
76287
76288
76289     return action;
76290 }
76291
76292 // Split a way at the given node.
76293 //
76294 // Optionally, split only the given ways, if multiple ways share
76295 // the given node.
76296 //
76297 // This is the inverse of `iD.actionJoin`.
76298 //
76299 // For testing convenience, accepts an ID to assign to the new way.
76300 // Normally, this will be undefined and the way will automatically
76301 // be assigned a new ID.
76302 //
76303 // Reference:
76304 //   https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
76305 //
76306 function actionSplit(nodeId, newWayIds) {
76307     var wayIds;
76308
76309     // if the way is closed, we need to search for a partner node
76310     // to split the way at.
76311     //
76312     // The following looks for a node that is both far away from
76313     // the initial node in terms of way segment length and nearby
76314     // in terms of beeline-distance. This assures that areas get
76315     // split on the most "natural" points (independent of the number
76316     // of nodes).
76317     // For example: bone-shaped areas get split across their waist
76318     // line, circles across the diameter.
76319     function splitArea(nodes, idxA, graph) {
76320         var lengths = new Array(nodes.length),
76321             length,
76322             i,
76323             best = 0,
76324             idxB;
76325
76326         function wrap(index) {
76327             return utilWrap(index, nodes.length);
76328         }
76329
76330         function dist(nA, nB) {
76331             return geoSphericalDistance(graph.entity(nA).loc, graph.entity(nB).loc);
76332         }
76333
76334         // calculate lengths
76335         length = 0;
76336         for (i = wrap(idxA+1); i !== idxA; i = wrap(i+1)) {
76337             length += dist(nodes[i], nodes[wrap(i-1)]);
76338             lengths[i] = length;
76339         }
76340
76341         length = 0;
76342         for (i = wrap(idxA-1); i !== idxA; i = wrap(i-1)) {
76343             length += dist(nodes[i], nodes[wrap(i+1)]);
76344             if (length < lengths[i])
76345                 lengths[i] = length;
76346         }
76347
76348         // determine best opposite node to split
76349         for (i = 0; i < nodes.length; i++) {
76350             var cost = lengths[i] / dist(nodes[idxA], nodes[i]);
76351             if (cost > best) {
76352                 idxB = i;
76353                 best = cost;
76354             }
76355         }
76356
76357         return idxB;
76358     }
76359
76360
76361     function split(graph, wayA, newWayId) {
76362         var wayB = osmWay({id: newWayId, tags: wayA.tags}),
76363             nodesA,
76364             nodesB,
76365             isArea = wayA.isArea(),
76366             isOuter = osmIsSimpleMultipolygonOuterMember(wayA, graph);
76367
76368         if (wayA.isClosed()) {
76369             var nodes = wayA.nodes.slice(0, -1),
76370                 idxA = lodash.indexOf(nodes, nodeId),
76371                 idxB = splitArea(nodes, idxA, graph);
76372
76373             if (idxB < idxA) {
76374                 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
76375                 nodesB = nodes.slice(idxB, idxA + 1);
76376             } else {
76377                 nodesA = nodes.slice(idxA, idxB + 1);
76378                 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
76379             }
76380         } else {
76381             var idx = lodash.indexOf(wayA.nodes, nodeId, 1);
76382             nodesA = wayA.nodes.slice(0, idx + 1);
76383             nodesB = wayA.nodes.slice(idx);
76384         }
76385
76386         wayA = wayA.update({nodes: nodesA});
76387         wayB = wayB.update({nodes: nodesB});
76388
76389         graph = graph.replace(wayA);
76390         graph = graph.replace(wayB);
76391
76392         graph.parentRelations(wayA).forEach(function(relation) {
76393             if (relation.isRestriction()) {
76394                 var via = relation.memberByRole('via');
76395                 if (via && wayB.contains(via.id)) {
76396                     relation = relation.updateMember({id: wayB.id}, relation.memberById(wayA.id).index);
76397                     graph = graph.replace(relation);
76398                 }
76399             } else {
76400                 if (relation === isOuter) {
76401                     graph = graph.replace(relation.mergeTags(wayA.tags));
76402                     graph = graph.replace(wayA.update({tags: {}}));
76403                     graph = graph.replace(wayB.update({tags: {}}));
76404                 }
76405
76406                 var member = {
76407                     id: wayB.id,
76408                     type: 'way',
76409                     role: relation.memberById(wayA.id).role
76410                 };
76411
76412                 graph = actionAddMember(relation.id, member)(graph);
76413             }
76414         });
76415
76416         if (!isOuter && isArea) {
76417             var multipolygon = osmRelation({
76418                 tags: lodash.extend({}, wayA.tags, {type: 'multipolygon'}),
76419                 members: [
76420                     {id: wayA.id, role: 'outer', type: 'way'},
76421                     {id: wayB.id, role: 'outer', type: 'way'}
76422                 ]});
76423
76424             graph = graph.replace(multipolygon);
76425             graph = graph.replace(wayA.update({tags: {}}));
76426             graph = graph.replace(wayB.update({tags: {}}));
76427         }
76428
76429         return graph;
76430     }
76431
76432
76433     var action = function(graph) {
76434         var candidates = action.ways(graph);
76435         for (var i = 0; i < candidates.length; i++) {
76436             graph = split(graph, candidates[i], newWayIds && newWayIds[i]);
76437         }
76438         return graph;
76439     };
76440
76441
76442     action.ways = function(graph) {
76443         var node = graph.entity(nodeId),
76444             parents = graph.parentWays(node),
76445             hasLines = lodash.some(parents, function(parent) { return parent.geometry(graph) === 'line'; });
76446
76447         return parents.filter(function(parent) {
76448             if (wayIds && wayIds.indexOf(parent.id) === -1)
76449                 return false;
76450
76451             if (!wayIds && hasLines && parent.geometry(graph) !== 'line')
76452                 return false;
76453
76454             if (parent.isClosed()) {
76455                 return true;
76456             }
76457
76458             for (var i = 1; i < parent.nodes.length - 1; i++) {
76459                 if (parent.nodes[i] === nodeId) {
76460                     return true;
76461                 }
76462             }
76463
76464             return false;
76465         });
76466     };
76467
76468
76469     action.disabled = function(graph) {
76470         var candidates = action.ways(graph);
76471         if (candidates.length === 0 || (wayIds && wayIds.length !== candidates.length))
76472             return 'not_eligible';
76473     };
76474
76475
76476     action.limitWays = function(_) {
76477         if (!arguments.length) return wayIds;
76478         wayIds = _;
76479         return action;
76480     };
76481
76482
76483     return action;
76484 }
76485
76486 // Create a restriction relation for `turn`, which must have the following structure:
76487 //
76488 //     {
76489 //         from: { node: <node ID>, way: <way ID> },
76490 //         via:  { node: <node ID> },
76491 //         to:   { node: <node ID>, way: <way ID> },
76492 //         restriction: <'no_right_turn', 'no_left_turn', etc.>
76493 //     }
76494 //
76495 // This specifies a restriction of type `restriction` when traveling from
76496 // `from.node` in `from.way` toward `to.node` in `to.way` via `via.node`.
76497 // (The action does not check that these entities form a valid intersection.)
76498 //
76499 // If `restriction` is not provided, it is automatically determined by
76500 // osmInferRestriction.
76501 //
76502 // If necessary, the `from` and `to` ways are split. In these cases, `from.node`
76503 // and `to.node` are used to determine which portion of the split ways become
76504 // members of the restriction.
76505 //
76506 // For testing convenience, accepts an ID to assign to the new relation.
76507 // Normally, this will be undefined and the relation will automatically
76508 // be assigned a new ID.
76509 //
76510 function actionRestrictTurn(turn, projection, restrictionId) {
76511
76512     return function(graph) {
76513         var from = graph.entity(turn.from.way),
76514             via  = graph.entity(turn.via.node),
76515             to   = graph.entity(turn.to.way);
76516
76517         function isClosingNode(way, nodeId) {
76518             return nodeId === way.first() && nodeId === way.last();
76519         }
76520
76521         function split(toOrFrom) {
76522             var newID = toOrFrom.newID || osmWay().id;
76523             graph = actionSplit(via.id, [newID])
76524                 .limitWays([toOrFrom.way])(graph);
76525
76526             var a = graph.entity(newID),
76527                 b = graph.entity(toOrFrom.way);
76528
76529             if (a.nodes.indexOf(toOrFrom.node) !== -1) {
76530                 return [a, b];
76531             } else {
76532                 return [b, a];
76533             }
76534         }
76535
76536         if (!from.affix(via.id) || isClosingNode(from, via.id)) {
76537             if (turn.from.node === turn.to.node) {
76538                 // U-turn
76539                 from = to = split(turn.from)[0];
76540             } else if (turn.from.way === turn.to.way) {
76541                 // Straight-on or circular
76542                 var s = split(turn.from);
76543                 from = s[0];
76544                 to   = s[1];
76545             } else {
76546                 // Other
76547                 from = split(turn.from)[0];
76548             }
76549         }
76550
76551         if (!to.affix(via.id) || isClosingNode(to, via.id)) {
76552             to = split(turn.to)[0];
76553         }
76554
76555         return graph.replace(osmRelation({
76556             id: restrictionId,
76557             tags: {
76558                 type: 'restriction',
76559                 restriction: turn.restriction ||
76560                     osmInferRestriction(
76561                         graph,
76562                         turn.from,
76563                         turn.via,
76564                         turn.to,
76565                         projection)
76566             },
76567             members: [
76568                 {id: from.id, type: 'way',  role: 'from'},
76569                 {id: via.id,  type: 'node', role: 'via'},
76570                 {id: to.id,   type: 'way',  role: 'to'}
76571             ]
76572         }));
76573     };
76574 }
76575
76576 function actionRevert(id) {
76577     var action = function(graph) {
76578         var entity = graph.hasEntity(id),
76579             base = graph.base().entities[id];
76580
76581         if (entity && !base) {    // entity will be removed..
76582             if (entity.type === 'node') {
76583                 graph.parentWays(entity)
76584                     .forEach(function(parent) {
76585                         parent = parent.removeNode(id);
76586                         graph = graph.replace(parent);
76587
76588                         if (parent.isDegenerate()) {
76589                             graph = actionDeleteWay(parent.id)(graph);
76590                         }
76591                     });
76592             }
76593
76594             graph.parentRelations(entity)
76595                 .forEach(function(parent) {
76596                     parent = parent.removeMembersWithID(id);
76597                     graph = graph.replace(parent);
76598
76599                     if (parent.isDegenerate()) {
76600                         graph = actionDeleteRelation(parent.id)(graph);
76601                     }
76602                 });
76603         }
76604
76605         return graph.revert(id);
76606     };
76607
76608     return action;
76609 }
76610
76611 function actionRotate(rotateIds, pivot, angle, projection) {
76612
76613     var action = function(graph) {
76614         return graph.update(function(graph) {
76615             utilGetAllNodes(rotateIds, graph).forEach(function(node) {
76616                 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
76617                 graph = graph.replace(node.move(projection.invert(point)));
76618             });
76619         });
76620     };
76621
76622     return action;
76623 }
76624
76625 /*
76626  * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
76627  */
76628 function actionStraighten(wayId, projection) {
76629
76630     function positionAlongWay(n, s, e) {
76631         return ((n[0] - s[0]) * (e[0] - s[0]) + (n[1] - s[1]) * (e[1] - s[1])) /
76632                 (Math.pow(e[0] - s[0], 2) + Math.pow(e[1] - s[1], 2));
76633     }
76634
76635
76636     var action = function(graph, t) {
76637         if (t === null || !isFinite(t)) t = 1;
76638         t = Math.min(Math.max(+t, 0), 1);
76639
76640         var way = graph.entity(wayId),
76641             nodes = graph.childNodes(way),
76642             points = nodes.map(function(n) { return projection(n.loc); }),
76643             startPoint = points[0],
76644             endPoint = points[points.length-1],
76645             toDelete = [],
76646             i;
76647
76648         for (i = 1; i < points.length-1; i++) {
76649             var node = nodes[i],
76650                 point = points[i];
76651
76652             if (t < 1 || graph.parentWays(node).length > 1 ||
76653                 graph.parentRelations(node).length ||
76654                 node.hasInterestingTags()) {
76655
76656                 var u = positionAlongWay(point, startPoint, endPoint),
76657                     p = [
76658                         startPoint[0] + u * (endPoint[0] - startPoint[0]),
76659                         startPoint[1] + u * (endPoint[1] - startPoint[1])
76660                     ],
76661                     loc2 = projection.invert(p);
76662
76663                 graph = graph.replace(node.move(geoInterp(node.loc, loc2, t)));
76664
76665             } else {
76666                 // safe to delete
76667                 if (toDelete.indexOf(node) === -1) {
76668                     toDelete.push(node);
76669                 }
76670             }
76671         }
76672
76673         for (i = 0; i < toDelete.length; i++) {
76674             graph = actionDeleteNode(toDelete[i].id)(graph);
76675         }
76676
76677         return graph;
76678     };
76679
76680
76681     action.disabled = function(graph) {
76682         // check way isn't too bendy
76683         var way = graph.entity(wayId),
76684             nodes = graph.childNodes(way),
76685             points = nodes.map(function(n) { return projection(n.loc); }),
76686             startPoint = points[0],
76687             endPoint = points[points.length-1],
76688             threshold = 0.2 * geoEuclideanDistance(startPoint, endPoint),
76689             i;
76690
76691         if (threshold === 0) {
76692             return 'too_bendy';
76693         }
76694
76695         for (i = 1; i < points.length-1; i++) {
76696             var point = points[i],
76697                 u = positionAlongWay(point, startPoint, endPoint),
76698                 p0 = startPoint[0] + u * (endPoint[0] - startPoint[0]),
76699                 p1 = startPoint[1] + u * (endPoint[1] - startPoint[1]),
76700                 dist = Math.sqrt(Math.pow(p0 - point[0], 2) + Math.pow(p1 - point[1], 2));
76701
76702             // to bendy if point is off by 20% of total start/end distance in projected space
76703             if (isNaN(dist) || dist > threshold) {
76704                 return 'too_bendy';
76705             }
76706         }
76707     };
76708
76709
76710     action.transitionable = true;
76711
76712
76713     return action;
76714 }
76715
76716 // Remove the effects of `turn.restriction` on `turn`, which must have the
76717 // following structure:
76718 //
76719 //     {
76720 //         from: { node: <node ID>, way: <way ID> },
76721 //         via:  { node: <node ID> },
76722 //         to:   { node: <node ID>, way: <way ID> },
76723 //         restriction: <relation ID>
76724 //     }
76725 //
76726 // In the simple case, `restriction` is a reference to a `no_*` restriction
76727 // on the turn itself. In this case, it is simply deleted.
76728 //
76729 // The more complex case is where `restriction` references an `only_*`
76730 // restriction on a different turn in the same intersection. In that case,
76731 // that restriction is also deleted, but at the same time restrictions on
76732 // the turns other than the first two are created.
76733 //
76734 function actionUnrestrictTurn(turn) {
76735     return function(graph) {
76736         return actionDeleteRelation(turn.restriction)(graph);
76737     };
76738 }
76739
76740 /* Reflect the given area around its axis of symmetry */
76741 function actionReflect(reflectIds, projection$$1) {
76742     var useLongAxis = true;
76743
76744
76745     // http://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points
76746     // http://gis.stackexchange.com/questions/3739/generalisation-strategies-for-building-outlines/3756#3756
76747     function getSmallestSurroundingRectangle(graph, nodes) {
76748         var points = nodes.map(function(n) { return projection$$1(n.loc); }),
76749             hull = d3polygonHull(points),
76750             centroid = d3polygonCentroid(hull),
76751             minArea = Infinity,
76752             ssrExtent = [],
76753             ssrAngle = 0,
76754             c1 = hull[0];
76755
76756         for (var i = 0; i < hull.length - 1; i++) {
76757             var c2 = hull[i + 1],
76758                 angle = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]),
76759                 poly = geoRotate(hull, -angle, centroid),
76760                 extent$$1 = poly.reduce(function(extent$$1, point) {
76761                         return extent$$1.extend(geoExtent$$1(point));
76762                     }, geoExtent$$1()),
76763                 area$$1 = extent$$1.area();
76764
76765             if (area$$1 < minArea) {
76766                 minArea = area$$1;
76767                 ssrExtent = extent$$1;
76768                 ssrAngle = angle;
76769             }
76770             c1 = c2;
76771         }
76772
76773         return {
76774             poly: geoRotate(ssrExtent.polygon(), ssrAngle, centroid),
76775             angle: ssrAngle
76776         };
76777     }
76778
76779
76780     var action = function(graph, t) {
76781         if (t === null || !isFinite(t)) t = 1;
76782         t = Math.min(Math.max(+t, 0), 1);
76783
76784         var nodes = utilGetAllNodes(reflectIds, graph),
76785             ssr = getSmallestSurroundingRectangle(graph, nodes);
76786
76787         // Choose line pq = axis of symmetry.
76788         // The shape's surrounding rectangle has 2 axes of symmetry.
76789         // Reflect across the longer axis by default.
76790         var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2 ],
76791             q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2 ],
76792             p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2 ],
76793             q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2 ],
76794             p, q;
76795
76796         var isLong = (geoEuclideanDistance(p1, q1) > geoEuclideanDistance(p2, q2));
76797         if ((useLongAxis && isLong) || (!useLongAxis && !isLong)) {
76798             p = p1;
76799             q = q1;
76800         } else {
76801             p = p2;
76802             q = q2;
76803         }
76804
76805         // reflect c across pq
76806         // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
76807         var dx = q[0] - p[0];
76808         var dy = q[1] - p[1];
76809         var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
76810         var b = 2 * dx * dy / (dx * dx + dy * dy);
76811         for (var i = 0; i < nodes.length; i++) {
76812             var node = nodes[i];
76813             var c = projection$$1(node.loc);
76814             var c2 = [
76815                 a * (c[0] - p[0]) + b * (c[1] - p[1]) + p[0],
76816                 b * (c[0] - p[0]) - a * (c[1] - p[1]) + p[1]
76817             ];
76818             var loc2 = projection$$1.invert(c2);
76819             node = node.move(geoInterp(node.loc, loc2, t));
76820             graph = graph.replace(node);
76821         }
76822
76823         return graph;
76824     };
76825
76826
76827     action.useLongAxis = function(_) {
76828         if (!arguments.length) return useLongAxis;
76829         useLongAxis = _;
76830         return action;
76831     };
76832
76833
76834     action.transitionable = true;
76835
76836
76837     return action;
76838 }
76839
76840
76841
76842 var index$17 = Object.freeze({
76843         d3combobox: d3combobox,
76844         d3geoTile: d3geoTile,
76845         d3keybinding: d3keybinding
76846 });
76847
76848 /* export some legacy symbols: */
76849 var Connection = services.osm;
76850 var debug = false;
76851
76852
76853
76854
76855 var iD = Object.freeze({
76856         Connection: Connection,
76857         debug: debug,
76858         d3: index$2,
76859         _: lodash$1,
76860         lib: index$17,
76861         Context: coreContext,
76862         setAreaKeys: setAreaKeys,
76863         Difference: coreDifference,
76864         Graph: coreGraph$$1,
76865         History: coreHistory,
76866         Tree: coreTree,
76867         Entity: osmEntity$$1,
76868         Node: osmNode,
76869         Relation: osmRelation,
76870         Way: osmWay,
76871         BackgroundSource: rendererBackgroundSource,
76872         Background: rendererBackground,
76873         Features: rendererFeatures,
76874         Map: rendererMap,
76875         TileLayer: rendererTileLayer,
76876         Detect: utilDetect,
76877         actionAddEntity: actionAddEntity,
76878         actionAddMember: actionAddMember,
76879         actionAddMidpoint: actionAddMidpoint,
76880         actionAddVertex: actionAddVertex,
76881         actionChangeMember: actionChangeMember,
76882         actionChangePreset: actionChangePreset,
76883         actionChangeTags: actionChangeTags,
76884         actionCircularize: actionCircularize,
76885         actionConnect: actionConnect,
76886         actionCopyEntities: actionCopyEntities,
76887         actionDeleteMember: actionDeleteMember,
76888         actionDeleteMultiple: actionDeleteMultiple,
76889         actionDeleteNode: actionDeleteNode,
76890         actionDeleteRelation: actionDeleteRelation,
76891         actionDeleteWay: actionDeleteWay,
76892         actionDeprecateTags: actionDeprecateTags,
76893         actionDiscardTags: actionDiscardTags,
76894         actionDisconnect: actionDisconnect,
76895         actionJoin: actionJoin,
76896         actionMerge: actionMerge,
76897         actionMergePolygon: actionMergePolygon,
76898         actionMergeRemoteChanges: actionMergeRemoteChanges,
76899         actionMove: actionMove,
76900         actionMoveNode: actionMoveNode,
76901         actionNoop: actionNoop,
76902         actionOrthogonalize: actionOrthogonalize,
76903         actionRestrictTurn: actionRestrictTurn,
76904         actionReverse: actionReverse,
76905         actionRevert: actionRevert,
76906         actionRotate: actionRotate,
76907         actionSplit: actionSplit,
76908         actionStraighten: actionStraighten,
76909         actionUnrestrictTurn: actionUnrestrictTurn,
76910         actionReflect: actionReflect,
76911         behaviorAddWay: behaviorAddWay,
76912         behaviorBreathe: behaviorBreathe,
76913         behaviorCopy: behaviorCopy,
76914         behaviorDrag: behaviorDrag,
76915         behaviorDrawWay: behaviorDrawWay,
76916         behaviorDraw: behaviorDraw,
76917         behaviorEdit: behaviorEdit,
76918         behaviorHash: behaviorHash,
76919         behaviorHover: behaviorHover,
76920         behaviorLasso: behaviorLasso,
76921         behaviorOperation: behaviorOperation,
76922         behaviorPaste: behaviorPaste,
76923         behaviorSelect: behaviorSelect,
76924         behaviorTail: behaviorTail,
76925         coreContext: coreContext,
76926         coreDifference: coreDifference,
76927         coreGraph: coreGraph$$1,
76928         coreHistory: coreHistory,
76929         coreTree: coreTree,
76930         dataFeatureIcons: dataFeatureIcons,
76931         data: data,
76932         dataWikipedia: dataWikipedia,
76933         dataSuggestions: dataSuggestions,
76934         dataAddressFormats: dataAddressFormats,
76935         dataDeprecated: dataDeprecated,
76936         dataDiscarded: dataDiscarded,
76937         dataLocales: dataLocales,
76938         dataPhoneFormats: dataPhoneFormats,
76939         dataShortcuts: dataShortcuts,
76940         dataImperial: dataImperial,
76941         dataDriveLeft: dataDriveLeft,
76942         dataEn: en,
76943         geoAngle: geoAngle,
76944         geoChooseEdge: geoChooseEdge,
76945         geoCross: geoCross,
76946         geoEdgeEqual: geoEdgeEqual,
76947         geoEuclideanDistance: geoEuclideanDistance,
76948         geoExtent: geoExtent$$1,
76949         geoInterp: geoInterp,
76950         geoRawMercator: geoRawMercator,
76951         geoRoundCoords: geoRoundCoords,
76952         geoRotate: geoRotate,
76953         geoLatToMeters: geoLatToMeters,
76954         geoLineIntersection: geoLineIntersection,
76955         geoLonToMeters: geoLonToMeters,
76956         geoMetersToLat: geoMetersToLat,
76957         geoMetersToLon: geoMetersToLon,
76958         geoMetersToOffset: geoMetersToOffset,
76959         geoOffsetToMeters: geoOffsetToMeters,
76960         geoPathIntersections: geoPathIntersections,
76961         geoPathLength: geoPathLength,
76962         geoPointInPolygon: geoPointInPolygon,
76963         geoPolygonContainsPolygon: geoPolygonContainsPolygon,
76964         geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
76965         geoSphericalDistance: geoSphericalDistance,
76966         modeAddArea: modeAddArea$$1,
76967         modeAddLine: modeAddLine$$1,
76968         modeAddPoint: modeAddPoint$$1,
76969         modeBrowse: modeBrowse,
76970         modeDragNode: modeDragNode$$1,
76971         modeDrawArea: modeDrawArea,
76972         modeDrawLine: modeDrawLine,
76973         modeMove: modeMove$$1,
76974         modeRotate: modeRotate$$1,
76975         modeSave: modeSave$$1,
76976         modeSelect: modeSelect,
76977         operationCircularize: operationCircularize,
76978         operationContinue: operationContinue,
76979         operationDelete: operationDelete,
76980         operationDisconnect: operationDisconnect,
76981         operationMerge: operationMerge,
76982         operationMove: operationMove,
76983         operationOrthogonalize: operationOrthogonalize,
76984         operationReflectShort: operationReflectShort,
76985         operationReflectLong: operationReflectLong,
76986         operationReverse: operationReverse,
76987         operationRotate: operationRotate,
76988         operationSplit: operationSplit,
76989         operationStraighten: operationStraighten,
76990         osmChangeset: osmChangeset,
76991         osmEntity: osmEntity$$1,
76992         osmNode: osmNode,
76993         osmRelation: osmRelation,
76994         osmWay: osmWay,
76995         osmIntersection: osmIntersection,
76996         osmTurn: osmTurn,
76997         osmInferRestriction: osmInferRestriction,
76998         osmLanes: osmLanes,
76999         osmIsSimpleMultipolygonOuterMember: osmIsSimpleMultipolygonOuterMember,
77000         osmSimpleMultipolygonOuterMember: osmSimpleMultipolygonOuterMember,
77001         osmJoinWays: osmJoinWays,
77002         osmOneWayTags: osmOneWayTags,
77003         osmPavedTags: osmPavedTags,
77004         osmIsInterestingTag: osmIsInterestingTag,
77005         presetCategory: presetCategory,
77006         presetCollection: presetCollection,
77007         presetField: presetField,
77008         presetPreset: presetPreset,
77009         presetIndex: presetIndex,
77010         rendererBackgroundSource: rendererBackgroundSource,
77011         rendererBackground: rendererBackground,
77012         rendererFeatures: rendererFeatures,
77013         rendererMap: rendererMap,
77014         rendererTileLayer: rendererTileLayer,
77015         services: services,
77016         svgAreas: svgAreas$$1,
77017         svgDebug: svgDebug,
77018         svgDefs: svgDefs,
77019         svgGpx: svgGpx,
77020         svgIcon: svgIcon,
77021         svgLabels: svgLabels,
77022         svgLayers: svgLayers,
77023         svgLines: svgLines$$1,
77024         svgMapillaryImages: svgMapillaryImages,
77025         svgMapillarySigns: svgMapillarySigns,
77026         svgMidpoints: svgMidpoints$$1,
77027         svgOneWaySegments: svgOneWaySegments,
77028         svgOsm: svgOsm,
77029         svgPath: svgPath,
77030         svgPointTransform: svgPointTransform,
77031         svgPoints: svgPoints$$1,
77032         svgRelationMemberTags: svgRelationMemberTags,
77033         svgTagClasses: svgTagClasses,
77034         svgTurns: svgTurns,
77035         svgVertices: svgVertices$$1,
77036         uiFields: uiFields,
77037         uiFieldDefaultCheck: uiFieldCheck,
77038         uiFieldOnewayCheck: uiFieldCheck,
77039         uiFieldCheck: uiFieldCheck,
77040         uiFieldMultiCombo: uiFieldCombo,
77041         uiFieldNetworkCombo: uiFieldCombo,
77042         uiFieldSemiCombo: uiFieldCombo,
77043         uiFieldTypeCombo: uiFieldCombo,
77044         uiFieldCombo: uiFieldCombo,
77045         uiFieldUrl: uiFieldText,
77046         uiFieldNumber: uiFieldText,
77047         uiFieldTel: uiFieldText,
77048         uiFieldEmail: uiFieldText,
77049         uiFieldText: uiFieldText,
77050         uiFieldAccess: uiFieldAccess,
77051         uiFieldAddress: uiFieldAddress,
77052         uiFieldCycleway: uiFieldCycleway,
77053         uiFieldLanes: uiFieldLanes,
77054         uiFieldLocalized: uiFieldLocalized,
77055         uiFieldMaxspeed: uiFieldMaxspeed,
77056         uiFieldStructureRadio: uiFieldRadio,
77057         uiFieldRadio: uiFieldRadio,
77058         uiFieldRestrictions: uiFieldRestrictions,
77059         uiFieldTextarea: uiFieldTextarea,
77060         uiFieldWikipedia: uiFieldWikipedia,
77061         uiIntro: uiIntro,
77062         uiInit: uiInit,
77063         uiAccount: uiAccount,
77064         uiAttribution: uiAttribution,
77065         uiBackground: uiBackground,
77066         uiCmd: uiCmd,
77067         uiCommit: uiCommit,
77068         uiConfirm: uiConfirm,
77069         uiConflicts: uiConflicts,
77070         uiContributors: uiContributors,
77071         uiCurtain: uiCurtain,
77072         uiDisclosure: uiDisclosure,
77073         uiEditMenu: uiEditMenu,
77074         uiEntityEditor: uiEntityEditor,
77075         uiFeatureInfo: uiFeatureInfo,
77076         uiFeatureList: uiFeatureList,
77077         uiFlash: uiFlash,
77078         uiFullScreen: uiFullScreen,
77079         uiGeolocate: uiGeolocate,
77080         uiHelp: uiHelp,
77081         uiInfo: uiInfo,
77082         uiInspector: uiInspector,
77083         uiLasso: uiLasso,
77084         uiLoading: uiLoading,
77085         uiMapData: uiMapData,
77086         uiMapInMap: uiMapInMap,
77087         uiModal: uiModal,
77088         uiModes: uiModes,
77089         uiNotice: uiNotice,
77090         uiPreset: uiPreset,
77091         uiPresetIcon: uiPresetIcon,
77092         uiPresetList: uiPresetList,
77093         uiRadialMenu: uiRadialMenu,
77094         uiRawMemberEditor: uiRawMemberEditor,
77095         uiRawMembershipEditor: uiRawMembershipEditor,
77096         uiRawTagEditor: uiRawTagEditor,
77097         uiRestore: uiRestore,
77098         uiSave: uiSave,
77099         uiScale: uiScale,
77100         uiSelectionList: uiSelectionList,
77101         uiSidebar: uiSidebar,
77102         uiSourceSwitch: uiSourceSwitch,
77103         uiSpinner: uiSpinner,
77104         uiSplash: uiSplash,
77105         uiStatus: uiStatus,
77106         uiSuccess: uiSuccess,
77107         uiTagReference: uiTagReference,
77108         uiToggle: uiToggle,
77109         uiTooltipHtml: uiTooltipHtml,
77110         uiUndoRedo: uiUndoRedo,
77111         uiVersion: uiVersion,
77112         uiViewOnOSM: uiViewOnOSM,
77113         uiZoom: uiZoom,
77114         utilAsyncMap: utilAsyncMap,
77115         utilDisplayName: utilDisplayName,
77116         utilDisplayNameForPath: utilDisplayNameForPath,
77117         utilDisplayType: utilDisplayType,
77118         utilEditDistance: utilEditDistance,
77119         utilEntitySelector: utilEntitySelector,
77120         utilEntityOrMemberSelector: utilEntityOrMemberSelector,
77121         utilFastMouse: utilFastMouse,
77122         utilFunctor: utilFunctor,
77123         utilGetAllNodes: utilGetAllNodes,
77124         utilGetPrototypeOf: utilGetPrototypeOf,
77125         utilGetSetValue: utilGetSetValue,
77126         utilNoAuto: utilNoAuto,
77127         utilPrefixCSSProperty: utilPrefixCSSProperty,
77128         utilPrefixDOMProperty: utilPrefixDOMProperty,
77129         utilQsString: utilQsString,
77130         utilRebind: utilRebind,
77131         utilSetTransform: utilSetTransform,
77132         utilSessionMutex: utilSessionMutex,
77133         utilStringQs: utilStringQs,
77134         utilSuggestNames: utilSuggestNames,
77135         utilTagText: utilTagText,
77136         utilTriggerEvent: utilTriggerEvent,
77137         utilWrap: utilWrap,
77138         d3combobox: d3combobox,
77139         d3geoTile: d3geoTile,
77140         d3keybinding: d3keybinding,
77141         validationDeprecatedTag: validationDeprecatedTag,
77142         validationDisconnectedHighway: validationDisconnectedHighway,
77143         validationManyDeletions: validationManyDeletions,
77144         validationMissingTag: validationMissingTag,
77145         validationOldMultipolygon: validationOldMultipolygon,
77146         validationTagSuggestsArea: validationTagSuggestsArea
77147 });
77148
77149 window.iD = iD;
77150
77151 }());
77152 //# sourceMappingURL=iD.js.map